ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/account/myuser.C
Revision: 1.10
Committed: Sat Sep 22 14:27:30 2007 UTC (18 years, 11 months ago) by pippijn
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.9: +2 -1 lines
Log Message:
split up ermyth into ermyth-modules, libermyth (currently just ermyth-util) and ermyth-core

File Contents

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