source: db/threaded.cc @ 7f6e52f

Revision 7f6e52f, 8.5 KB checked in by Antti-Juhani Kaijanaho <antti-juhani@…>, 5 years ago (diff)

[SECURITY] [db::threaded] Fix handling of sibling_iterator

This caused a DoS vulnerability that was remote exploitable by at least
mirroring the https facet.

Signed-off-by: Antti-Juhani Kaijanaho <antti-juhani@…>

  • Property mode set to 100644
Line 
1/*  This file is part of Alue, the multiprotocol Internet discussion daemon
2
3    Copyright © 2009 Antti-Juhani Kaijanaho
4
5    Alue is free software: you can redistribute it and/or modify it
6    under the terms of the GNU General Public License as published by
7    the Free Software Foundation, either version 3 of the License, or
8    (at your option) any later version.
9
10    Alue is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with Alue.  If not, see <http://www.gnu.org/licenses/>.
17
18 */
19
20#include "threaded.hh"
21
22#include "../msg/lexutils.hh"
23#include "../msg/msg.hh"
24#include "../html/util.hh"
25#include "../tlate/sequential_value.hh"
26#include "../tlate/lazy_structured_value.hh"
27#include "../uri.hh"
28
29#include "../assert.hh"
30
31namespace db
32{
33        thread_node::ptr thread_node::previous() const
34        {
35                if (!parent) return ptr();
36                if (sibling_iterator == parent->children.begin())
37                        return parent;
38                std::list<ptr>::iterator it = sibling_iterator;
39                assert(msgid == (*it)->msgid);
40                it--;
41                return *it;
42        }
43
44        thread_node::ptr thread_node::next() const
45        {
46                if (!children.empty()) return *children.begin();
47                const_ptr tn = shared_from_this();
48                while (true)
49                {
50                        if (!tn->parent) return ptr();
51                        std::list<ptr>::iterator it = tn->sibling_iterator;
52                        assert(it != tn->parent->children.end());
53                        it++;
54                        if (it == tn->parent->children.end())
55                        {
56                                tn = tn->parent;
57                                continue;
58                        }
59                        return *it;
60                }
61        }
62
63        void thread_node::disown_children()
64        {
65                for (std::list<ptr>::iterator it = children.begin();
66                     it != children.end(); it++)
67                {
68                        (*it)->parent.reset();
69                }
70                children.clear();
71        }
72
73        void thread_node::set_parent(ptr p)
74        {
75                if (parent)
76                        parent->children.erase(sibling_iterator);
77                parent = p;
78                if (!parent) return;
79                p->children.push_back(shared_from_this());
80                sibling_iterator = p->children.end();
81                assert(sibling_iterator != p->children.begin());
82                sibling_iterator--;
83        }
84
85        thread_node::ptr
86        thread_node::get_principal()
87        {
88                if (art) return ptr();
89                if (children.empty()) return ptr();
90                std::list<ptr>::iterator it = children.begin();
91                it++;
92                if (it != children.end()) return ptr();
93                return *it;
94        }
95
96        size_t thread_node::cardinality() const
97        {
98                size_t rv = art ? 1 : 0;
99                for (std::list<ptr>::const_iterator it = children.begin();
100                     it != children.end(); it++)
101                {
102                        rv += (*it)->cardinality();
103                }
104                return rv;
105        }
106
107        bool thread_node::has_descendant(ptr tn)
108        {
109                for (std::list<ptr>::const_iterator it = children.begin();
110                     it != children.end(); it++)
111                {
112                        if (*it == tn) return true;
113                        if ((*it)->has_descendant(tn)) return true;
114                }
115                return false;
116        }
117
118        void thread_node::prune()
119        {
120                for (std::list<ptr>::iterator it = children.begin();
121                     it != children.end(); /**/)
122                {
123                        (*it)->prune();
124                        if ((*it)->art)
125                        {
126                                it++;
127                        }
128                        else
129                        {
130                                for (std::list<ptr>::iterator jt =
131                                             (*it)->children.begin();
132                                     jt != (*it)->children.end();
133                                     jt++)
134                                {
135                                        (*jt)->sibling_iterator =
136                                                children.insert(it, *jt);
137                                        (*jt)->parent = shared_from_this();
138                                }
139
140                                std::list<ptr>::iterator next = it;
141                                next++;
142                                children.erase(it);
143                                (*it)->parent.reset();
144                                it = next;
145                        }
146                }
147        }
148       
149        void thread_node::add_msg(db::group::number grinx_, 
150                                  boost::shared_ptr<msg::msg> art_)
151        {
152                if (art) return;
153                grinx = grinx_;
154                art = art_;
155                std::string refss = art->get_field("references", false);
156                ptr prev;
157                while (!refss.empty())
158                {
159                        std::string ref = msg::get_msgid(refss);
160                        if (ref.empty()) continue;
161                        ptr &tn = msgids[ref];
162                        if (!tn) tn.reset(new thread_node(msgids,ref));
163                        if (prev && !tn->parent && !tn->has_descendant(prev))
164                                tn->set_parent(prev);
165                        prev = tn;
166                }
167                if (prev)
168                {
169                        set_parent(prev);
170                }
171        }
172
173        void threaded::add_msg(db::group::number grinx,
174                               boost::shared_ptr<msg::msg> art)
175        {
176                thread_node::ptr &tn = msgids[art->msgid()];
177                if (!tn) tn.reset(new thread_node(msgids, art->msgid()));
178                tn->add_msg(grinx, art);
179        }
180
181        void threaded::recalc_roots()
182        {
183                root->disown_children();
184                for (std::map<std::string, thread_node::ptr>::const_iterator it
185                             = msgids.begin();
186                     it != msgids.end(); it++)
187                {
188                        thread_node::ptr tn = it->second;
189                        if (tn->parent) continue;
190
191                        thread_node::ptr princ = tn->get_principal();
192                        if (princ)
193                                tn = princ;
194
195                        if (!tn->is_empty())
196                                tn->set_parent(root);
197                }
198                root->prune();
199        }
200        void threaded::sort()
201        {
202                root->sort_children_recursive(thread_node::cmp_grinx);
203        }
204
205        thread_node::ptr
206        thread_node::restrict_to_group(boost::shared_ptr<group> gr,
207                                       ptr parent) const
208        {
209                ptr rv(new thread_node(msgids, msgid));
210                rv->grinx = grinx;
211                rv->art = art;
212                rv->set_parent(parent);
213
214                for (std::list<ptr>::const_iterator it = children.begin();
215                     it != children.end(); it++)
216                {
217                        (*it)->restrict_to_group(gr, rv);
218                }
219                if (rv->children.empty() && !art) return ptr();
220                if (art)
221                {
222                        std::map<boost::shared_ptr<db::group>,db::group::number>
223                                ::const_iterator git = art->get_xref().find(gr);
224                        if (git == art->get_xref().end()) 
225                        {
226                                rv->set_parent(ptr());
227                                return ptr();
228                        }
229                }
230                return rv;
231        }
232
233        const std::list<thread_node::ptr> threaded::empty_list;
234
235        const std::list<thread_node::ptr> &threaded::get_threads
236        (boost::shared_ptr<group> gr) const 
237        {
238                thread_node::ptr tn = root->restrict_to_group
239                        (gr, thread_node::ptr());
240                if (!tn) return empty_list;
241                return tn->get_children();
242        }
243
244}
245
Note: See TracBrowser for help on using the repository browser.