/** * account.C: Account management * Rights to this code are documented in doc/LICENSE. * * Copyright © 2005-2007 Atheme Project (http://www.atheme.org) */ static char const rcsid[] = "$Id"; #include "atheme.h" #include #include #include #include #include "uplink.h" /* XXX, for sendq_flush(curr_uplink->conn); */ #include "datastream.h" #include "privs.h" #if 0 static BlockHeap *myuser_heap; /* HEAP_USER */ static BlockHeap *mynick_heap; /* HEAP_USER */ static BlockHeap *mychan_heap; /* HEAP_CHANNEL */ static BlockHeap *chanacs_heap; /* HEAP_CHANACS */ static BlockHeap *metadata_heap; /* HEAP_CHANUSER */ #endif /* * init_accounts() * * Initializes the accounts DTree. * * Inputs: * - none * * Outputs: * - none * * Side Effects: * - if the DTree initialization fails, services will abort. */ void init_accounts (void) { #if 0 myuser_heap = BlockHeapCreate (sizeof (myuser_t), HEAP_USER); mynick_heap = BlockHeapCreate (sizeof (myuser_t), HEAP_USER); mychan_heap = BlockHeapCreate (sizeof (mychan_t), HEAP_CHANNEL); chanacs_heap = BlockHeapCreate (sizeof (chanacs_t), HEAP_CHANUSER); metadata_heap = BlockHeapCreate (sizeof (metadata_t), HEAP_CHANUSER); if (myuser_heap == NULL || mynick_heap == NULL || mychan_heap == NULL || chanacs_heap == NULL || metadata_heap == NULL) { slog (LG_ERROR, "init_accounts(): block allocator failure."); exit (EXIT_FAILURE); } #endif mulist = dictionary_create ("myuser", HASH_USER, irccasecmp); nicklist = dictionary_create ("mynick", HASH_USER, irccasecmp); mclist = dictionary_create ("mychan", HASH_CHANNEL, irccasecmp); } static int expire_myuser_cb (dictionary_elem_t *delem, void *unused) { myuser_t *mu = static_cast (delem->node.data); /* If they're logged in, update lastlogin time. * To decrease db traffic, may want to only do * this if the account would otherwise be * deleted. -- jilles */ if (!mu->logins.empty ()) { mu->lastlogin = NOW; return 0; } if (MU_HOLD & mu->flags) return 0; if (((NOW - mu->lastlogin) >= nicksvs.expiry) || ((mu->flags & MU_WAITAUTH) && (NOW - mu->registered >= 86400))) { /* Don't expire accounts with privs on them in atheme.conf, * otherwise someone can reregister * them and take the privs -- jilles */ if (is_conf_soper (mu)) return 0; snoop (_("EXPIRE: \2%s\2 from \2%s\2 "), mu->name, mu->email); slog (LG_REGISTER, "expire_check(): expiring account %s (unused %ds, email %s, nicks %d, chanacs %d)", mu->name, (int) (NOW - mu->lastlogin), mu->email, LIST_LENGTH (&mu->nicks), LIST_LENGTH (&mu->chanacs)); mu->refcnt_dec (); } return 0; } void expire_check (void *arg) { mynick_t *mn; mychan_t *mc; user_t *u; dictionary_iteration_state_t state; /* Let them know about this and the likely subsequent db_save() * right away -- jilles */ sendq_flush (curr_uplink->conn); if (nicksvs.expiry != 0) { dictionary_foreach (mulist, expire_myuser_cb, NULL); DICTIONARY_FOREACH (mn, mynick_t, &state, nicklist) { if ((NOW - mn->lastseen) >= nicksvs.expiry) { if (MU_HOLD & mn->owner->flags) continue; /* do not drop main nick like this */ if (!irccasecmp (mn->nick, mn->owner->name)) continue; u = user_find_named (mn->nick); if (u != NULL && u->myuser == mn->owner) { /* still logged in, bleh */ mn->lastseen = NOW; mn->owner->lastlogin = NOW; continue; } snoop (_("EXPIRE: \2%s\2 from \2%s\2"), mn->nick, mn->owner->name); slog (LG_REGISTER, "expire_check(): expiring nick %s (unused %ds, account %s)", mn->nick, NOW - mn->lastseen, mn->owner->name); object_unref (mn); } } } if (chansvs.expiry != 0) { DICTIONARY_FOREACH (mc, mychan_t, &state, mclist) { if ((NOW - mc->used) >= 86400 - 3660) { /* keep last used time accurate to * within a day, making sure an active * channel will never get "Last used" * in /cs info -- jilles */ if (mychan_isused (mc)) { mc->used = NOW; slog (LG_DEBUG, "expire_check(): updating last used time on %s because it appears to be still in use", mc->name); continue; } } if ((NOW - mc->used) >= chansvs.expiry) { if (MU_HOLD & mc->founder->flags) continue; if (MC_HOLD & mc->flags) continue; snoop (_("EXPIRE: \2%s\2 from \2%s\2"), mc->name, mc->founder->name); slog (LG_REGISTER, "expire_check(): expiring channel %s (unused %ds, founder %s, chanacs %d)", mc->name, NOW - mc->used, mc->founder->name, LIST_LENGTH (&mc->chanacs)); hook_call_event ("channel_drop", mc); if ((config_options.chan && irccasecmp (mc->name, config_options.chan)) || !config_options.chan) part (mc->name, chansvs.nick); mc->refcnt_dec (); } } } } static int check_myuser_cb (dictionary_elem_t *delem, void *unused) { myuser_t *mu = static_cast (delem->node.data); mynick_t *mn; if (MU_OLD_ALIAS & mu->flags) { slog (LG_REGISTER, "db_check(): converting previously linked nick %s to a standalone nick", mu->name); mu->flags &= ~MU_OLD_ALIAS; mu->del_metadata ("private:alias:parent"); } if (!nicksvs.no_nick_ownership) { mn = mynick_find (mu->name); if (mn == NULL) { slog (LG_REGISTER, "db_check(): adding missing nick %s", mu->name); mn = mynick_add (mu, mu->name); mn->registered = mu->registered; mn->lastseen = mu->lastlogin; } else if (mn->owner != mu) { slog (LG_REGISTER, "db_check(): replacing nick %s owned by %s with %s", mn->nick, mn->owner->name, mu->name); object_unref (mn); mn = mynick_add (mu, mu->name); mn->registered = mu->registered; mn->lastseen = mu->lastlogin; } } return 0; } void db_check () { mychan_t *mc; dictionary_iteration_state_t state; dictionary_foreach (mulist, check_myuser_cb, NULL); DICTIONARY_FOREACH (mc, mychan_t, &state, mclist) { if (!chanacs_find (mc, mc->founder, CA_FLAGS)) { slog (LG_REGISTER, "db_check(): adding access for founder on channel %s", mc->name); chanacs_change_simple (mc, mc->founder, NULL, CA_FOUNDER_0, 0); } } }