ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/account/myuser.C
Revision: 1.1
Committed: Thu Jul 19 08:24:59 2007 UTC (19 years, 2 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Log Message:
initial import. the most important changes since Atheme are:
- fixed many memory leaks
- fixed many bugs
- converted to C++ and use more STL containers
- added a (not very enhanced yet) perl module
- greatly improved XML-RPC speed
- added a JSON-RPC module with code from json-cpp
- added a valgrind memcheck module to operserv
- added a more object oriented base64 implementation
- added a specialised unit test framework
- improved stability
- use gettimeofday() if available
- reworked adding/removing commands
- MemoServ IGNORE DEL can now remove indices

File Contents

# User Rev Content
1 pippijn 1.1 #include "atheme.h"
2     #include <account/myuser.h>
3     #include <account/mynick.h>
4     #include <account/chanacs.h>
5     #include <account/mychan.h>
6     #include <account/mymemo.h>
7     #include "authcookie.h"
8    
9     dictionary_tree_t *mulist;
10    
11     /*
12     * myuser_add(char *name, char *pass, char *email, unsigned int flags)
13     *
14     * Creates an account and adds it to the accounts DTree.
15     *
16     * Inputs:
17     * - an account name
18     * - an account password
19     * - an email to associate with the account or NONE
20     * - flags for the account
21     *
22     * Outputs:
23     * - on success, a new myuser_t object (account)
24     * - on failure, NULL.
25     *
26     * Side Effects:
27     * - the created account is added to the accounts DTree,
28     * this may be undesirable for a factory.
29     *
30     * Caveats:
31     * - if nicksvs.no_nick_ownership is not enabled, the caller is
32     * responsible for adding a nick with the same name
33     */
34     myuser_t *
35     myuser_add (char *name, char *pass, char *email, unsigned int flags)
36     {
37     myuser_t *mu;
38     soper_t *soper;
39    
40     return_val_if_fail ((mu = myuser_find (name)) == NULL, mu);
41    
42     if (!(runflags & RF_STARTING))
43     slog (LG_DEBUG, "myuser_add(): %s -> %s", name, email);
44    
45     mu = new myuser_t;
46    
47     strlcpy (mu->name, name, NICKLEN);
48     strlcpy (mu->email, email, EMAILLEN);
49    
50     mu->registered = NOW;
51     mu->flags = flags;
52    
53     /* If it's already crypted, don't touch the password. Otherwise,
54     * use set_password() to initialize it. Why? Because set_password
55     * will move the user to encrypted passwords if possible. That way,
56     * new registers are immediately protected and the database is
57     * immediately converted the first time we start up with crypto.
58     */
59     if (flags & MU_CRYPTPASS)
60     strlcpy (mu->pass, pass, NICKLEN);
61     else
62     set_password (mu, pass);
63    
64     dictionary_add (mulist, mu->name, mu);
65    
66     if ((soper = soper_find_named (mu->name)) != NULL)
67     {
68     slog (LG_DEBUG, "myuser_add(): user `%s' has been declared as soper, activating privileges.", mu->name);
69     soper->myuser = mu;
70     mu->soper = soper;
71     }
72    
73     cnt.myuser++;
74    
75     return mu;
76     }
77    
78     /*
79     * myuser_delete(myuser_t *mu)
80     *
81     * Destroys and removes an account from the accounts DTree.
82     *
83     * Inputs:
84     * - account to destroy
85     *
86     * Outputs:
87     * - nothing
88     *
89     * Side Effects:
90     * - an account is destroyed and removed from the accounts DTree.
91     */
92     void
93     myuser_delete (myuser_t *mu)
94     {
95     myuser_t *successor;
96     mychan_t *mc;
97     user_t *u;
98     node_t *n, *tn;
99     mymemo_t *memo;
100     chanacs_t *ca;
101    
102     return_if_fail (mu != NULL);
103    
104     if (!(runflags & RF_STARTING))
105     slog (LG_DEBUG, "myuser_delete(): %s", mu->name);
106    
107     /* log them out */
108     while (!mu->logins.empty ())
109     {
110     u = mu->logins.back ();
111     if (!authservice_loaded || !ircd_on_logout (u->nick, mu->name, NULL))
112     {
113     u->myuser = NULL;
114     mu->logins.erase (u);
115     }
116     }
117    
118     /* kill all their channels and chanacs */
119     LIST_FOREACH_SAFE (n, tn, mu->chanacs.head)
120     {
121     ca = static_cast<chanacs_t *> (n->data);
122     mc = ca->mychan;
123    
124     /* attempt succession */
125     if (mc->founder == mu && (successor = mychan_pick_successor (mc)) != NULL)
126     {
127     snoop (_("SUCCESSION: \2%s\2 -> \2%s\2 from \2%s\2"), successor->name, mc->name, mc->founder->name);
128     slog (LG_REGISTER, "myuser_delete(): giving channel %s to %s (unused %ds, founder %s, chanacs %d)", mc->name, successor->name, NOW - mc->used, mc->founder->name, LIST_LENGTH (&mc->chanacs));
129     if (chansvs.me != NULL)
130     verbose (mc, "Foundership changed to \2%s\2 because \2%s\2 was dropped.", successor->name, mc->founder->name);
131    
132     chanacs_change_simple (mc, successor, NULL, CA_FOUNDER_0, 0);
133     mc->founder = successor;
134    
135     if (chansvs.me != NULL)
136     myuser_notice (chansvs.nick, mc->founder, "You are now founder on \2%s\2 (as \2%s\2).", mc->name, mc->founder->name);
137     }
138    
139     /* no successor found */
140     if (mc->founder == mu)
141     {
142     snoop (_("DELETE: \2%s\2 from \2%s\2"), mc->name, mu->name);
143     slog (LG_REGISTER, "myuser_delete(): deleting channel %s (unused %ds, founder %s, chanacs %d)", mc->name, NOW - mc->used, mc->founder->name, LIST_LENGTH (&mc->chanacs));
144    
145     hook_call_event ("channel_drop", mc);
146     if ((config_options.chan && irccasecmp (mc->name, config_options.chan)) || !config_options.chan)
147     part (mc->name, chansvs.nick);
148     object_unref (mc);
149     }
150     else /* successor found, or not founder in the first place */
151     object_unref (ca);
152     }
153    
154     /* remove them from the soper list */
155     if (soper_find (mu))
156     soper_delete (mu->soper);
157    
158     /* delete the metadata */
159     mu->clear_metadata ();
160    
161     /* kill any authcookies */
162     authcookie_destroy_all (mu);
163    
164     /* delete memos */
165     LIST_FOREACH_SAFE (n, tn, mu->memos.head)
166     {
167     memo = (mymemo_t *) n->data;
168    
169     node_del (n, &mu->memos);
170     node_free (n);
171     free (memo);
172     }
173    
174     /* delete access entries */
175     LIST_FOREACH_SAFE (n, tn, mu->access_list.head) myuser_access_delete (mu, (char *) n->data);
176    
177     /* delete their nicks */
178     LIST_FOREACH_SAFE (n, tn, mu->nicks.head)
179     {
180     object_unref (n->data);
181     }
182    
183     /* mu->name is the index for this dtree */
184     dictionary_delete (mulist, mu->name);
185    
186     delete mu;
187    
188     cnt.myuser--;
189     }
190    
191     /*
192     * myuser_find(const char *name)
193     *
194     * Retrieves an account from the accounts DTree.
195     *
196     * Inputs:
197     * - account name to retrieve
198     *
199     * Outputs:
200     * - account wanted or NULL if it's not in the DTree.
201     *
202     * Side Effects:
203     * - none
204     */
205     myuser_t *
206     myuser_find (const char *name)
207     {
208     return static_cast<myuser_t *> (dictionary_retrieve (mulist, name));
209     }
210    
211     /*
212     * myuser_find_ext(const char *name)
213     *
214     * Same as myuser_find() but with nick group support and undernet-style
215     * `=nick' expansion.
216     *
217     * Inputs:
218     * - account name/nick to retrieve or =nick notation for wanted account.
219     *
220     * Outputs:
221     * - account wanted or NULL if it's not in the DTree.
222     *
223     * Side Effects:
224     * - none
225     */
226     myuser_t *
227     myuser_find_ext (const char *name)
228     {
229     user_t *u;
230     mynick_t *mn;
231    
232     if (name == NULL)
233     return NULL;
234    
235     if (*name == '=')
236     {
237     u = user_find_named (name + 1);
238     return u != NULL ? u->myuser : NULL;
239     }
240     else if (nicksvs.no_nick_ownership)
241     return myuser_find (name);
242     else
243     {
244     mn = mynick_find (name);
245     return mn != NULL ? mn->owner : NULL;
246     }
247     }
248    
249     /*
250     * myuser_notice(char *from, myuser_t *target, char *fmt, ...)
251     *
252     * Sends a notice to all users logged into an account.
253     *
254     * Inputs:
255     * - source of message
256     * - target account
257     * - format of message
258     * - zero+ arguments for the formatter
259     *
260     * Outputs:
261     * - nothing
262     *
263     * Side Effects:
264     * - a notice is sent to all users logged into the account.
265     */
266     void
267     myuser_notice (char *from, myuser_t *target, char *fmt, ...)
268     {
269     va_list ap;
270     char buf[BUFSIZE];
271     myuser_t::login_vector::iterator it, it_end;
272    
273     if (target == NULL)
274     return;
275    
276     /* have to reformat it here, can't give a va_list to notice() :(
277     * -- jilles
278     */
279     va_start (ap, fmt);
280     vsnprintf (buf, BUFSIZE, fmt, ap);
281     va_end (ap);
282    
283     for (it = target->logins.begin (), it_end = target->logins.end (); it != it_end; ++it)
284     notice (from, (*it)->nick, "%s", buf);
285     }
286    
287     /*
288     * myuser_access_verify()
289     *
290     * Inputs:
291     * - user to verify, account to verify against
292     *
293     * Outputs:
294     * - true if user matches an accesslist entry
295     * - false otherwise
296     *
297     * Side Effects:
298     * - last login time updated if user matches
299     */
300     bool
301     myuser_access_verify (user_t *u, myuser_t *mu)
302     {
303     node_t *n;
304     char buf[USERLEN + HOSTLEN];
305     char buf2[USERLEN + HOSTLEN];
306     char buf3[USERLEN + HOSTLEN];
307    
308     if (u == NULL || mu == NULL)
309     {
310     slog (LG_DEBUG, "myuser_access_verify(): invalid parameters: u = %p, mu = %p", u, mu);
311     return false;
312     }
313    
314     if (!use_myuser_access)
315     return false;
316    
317     snprintf (buf, sizeof buf, "%s@%s", u->user, u->vhost);
318     snprintf (buf2, sizeof buf2, "%s@%s", u->user, u->host);
319     snprintf (buf3, sizeof buf3, "%s@%s", u->user, u->ip);
320    
321     LIST_FOREACH (n, mu->access_list.head)
322     {
323     char *entry = (char *) n->data;
324    
325     if (!match (entry, buf) || !match (entry, buf2) || !match (entry, buf3) || !match_cidr (entry, buf3))
326     {
327     mu->lastlogin = NOW;
328     return true;
329     }
330     }
331    
332     return false;
333     }
334    
335     /*
336     * myuser_access_add()
337     *
338     * Inputs:
339     * - account to attach access mask to, access mask itself
340     *
341     * Outputs:
342     * - false: me.mdlimit is reached (too many access entries)
343     * - true : success
344     *
345     * Side Effects:
346     * - an access mask is added to an account.
347     */
348     bool
349     myuser_access_add (myuser_t *mu, char *mask)
350     {
351     node_t *n;
352     char *msk;
353    
354     if (mu == NULL || mask == NULL)
355     {
356     slog (LG_DEBUG, "myuser_access_add(): invalid parameters: mu = %p, mask = %p", mu, mask);
357     return false;
358     }
359    
360     if (LIST_LENGTH (&mu->access_list) > me.mdlimit)
361     {
362     slog (LG_DEBUG, "myuser_access_add(): access entry limit reached for %s", mu->name);
363     return false;
364     }
365    
366     msk = sstrdup (mask);
367     n = node_create ();
368     node_add (msk, n, &mu->access_list);
369    
370     cnt.myuser_access++;
371    
372     return true;
373     }
374    
375     /*
376     * myuser_access_find()
377     *
378     * Inputs:
379     * - account to find access mask in, access mask
380     *
381     * Outputs:
382     * - pointer to found access mask or NULL if not found
383     *
384     * Side Effects:
385     * - none
386     */
387     char *
388     myuser_access_find (myuser_t *mu, char *mask)
389     {
390     node_t *n;
391    
392     if (mu == NULL || mask == NULL)
393     {
394     slog (LG_DEBUG, "myuser_access_find(): invalid parameters: mu = %p, mask = %p", mu, mask);
395     return NULL;
396     }
397    
398     LIST_FOREACH (n, mu->access_list.head)
399     {
400     char *entry = (char *) n->data;
401    
402     if (!strcasecmp (entry, mask))
403     return entry;
404     }
405     return NULL;
406     }
407    
408     /*
409     * myuser_access_delete()
410     *
411     * Inputs:
412     * - account to delete access mask from, access mask itself
413     *
414     * Outputs:
415     * - none
416     *
417     * Side Effects:
418     * - an access mask is added to an account.
419     */
420     void
421     myuser_access_delete (myuser_t *mu, char *mask)
422     {
423     node_t *n, *tn;
424    
425     if (mu == NULL || mask == NULL)
426     {
427     slog (LG_DEBUG, "myuser_access_delete(): invalid parameters: mu = %p, mask = %p", mu, mask);
428     return;
429     }
430    
431     LIST_FOREACH_SAFE (n, tn, mu->access_list.head)
432     {
433     char *entry = (char *) n->data;
434    
435     if (!strcasecmp (entry, mask))
436     {
437     node_del (n, &mu->access_list);
438     node_free (n);
439     free (entry);
440    
441     cnt.myuser_access--;
442    
443     return;
444     }
445     }
446     }