users.c

Go to the documentation of this file.
00001 /* Routines to maintain a list of online users.
00002  *
00003  * (C) 2003-2013 Anope Team
00004  * Contact us at team@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church. 
00010  * 
00011  *
00012  */
00013 
00014 #include "services.h"
00015 
00016 #define HASH(nick)      (((nick)[0]&31)<<5 | ((nick)[1]&31))
00017 User *userlist[1024];
00018 
00019 #define HASH2(nick)     (((nick)[0]&31)<<5 | ((nick)[1]&31))
00020 Uid *uidlist[1024];
00021 
00022 int32 usercnt = 0, opcnt = 0;
00023 uint32 maxusercnt = 0;
00024 time_t maxusertime;
00025 
00026 /*************************************************************************/
00027 /*************************************************************************/
00028 
00029 /* Allocate a new User structure, fill in basic values, link it to the
00030  * overall list, and return it.  Always successful.
00031  */
00032 
00033 static User *new_user(const char *nick)
00034 {
00035     User *user, **list;
00036 
00037     user = scalloc(sizeof(User), 1);
00038     if (!nick)
00039         nick = "";
00040     strscpy(user->nick, nick, NICKMAX);
00041     list = &userlist[HASH(user->nick)];
00042     user->next = *list;
00043     if (*list)
00044         (*list)->prev = user;
00045     *list = user;
00046     user->na = findnick(nick);
00047     if (user->na)
00048         user->na->u = user;
00049     usercnt++;
00050     if (usercnt > maxusercnt) {
00051         maxusercnt = usercnt;
00052         maxusertime = time(NULL);
00053         if (LogMaxUsers)
00054             alog("user: New maximum user count: %d", maxusercnt);
00055     }
00056     user->isSuperAdmin = 0;     /* always set SuperAdmin to 0 for new users */
00057     user->nickTrack = NULL;     /* ensure no default tracking nick */
00058     return user;
00059 }
00060 
00061 /*************************************************************************/
00062 
00063 /* Change the nickname of a user, and move pointers as necessary. */
00064 
00065 static void change_user_nick(User * user, const char *nick)
00066 {
00067     User **list;
00068     int is_same;
00069 
00070     /* Sanity check to make sure we don't segfault */
00071     if (!user || !nick || !*nick) {
00072         return;
00073     }
00074 
00075     is_same = (!stricmp(user->nick, nick) ? 1 : 0);
00076 
00077     if (user->prev)
00078         user->prev->next = user->next;
00079     else
00080         userlist[HASH(user->nick)] = user->next;
00081     if (user->next)
00082         user->next->prev = user->prev;
00083     user->nick[1] = 0;          /* paranoia for zero-length nicks */
00084     strscpy(user->nick, nick, NICKMAX);
00085     list = &userlist[HASH(user->nick)];
00086     user->next = *list;
00087     user->prev = NULL;
00088     if (*list)
00089         (*list)->prev = user;
00090     *list = user;
00091 
00092     /* Only if old and new nick aren't the same; no need to waste time */
00093     if (!is_same) {
00094         if (user->na)
00095             user->na->u = NULL;
00096         user->na = findnick(nick);
00097         if (user->na)
00098             user->na->u = user;
00099     }
00100 }
00101 
00102 /*************************************************************************/
00103 
00104 void update_host(User * user)
00105 {
00106     if (user->na && (nick_identified(user)
00107                      || (!(user->na->nc->flags & NI_SECURE)
00108                          && nick_recognized(user)))) {
00109         if (user->na->last_usermask)
00110             free(user->na->last_usermask);
00111 
00112         user->na->last_usermask =
00113             smalloc(strlen(common_get_vident(user)) +
00114                     strlen(common_get_vhost(user)) + 2);
00115         sprintf(user->na->last_usermask, "%s@%s", common_get_vident(user),
00116                 common_get_vhost(user));
00117     }
00118 
00119     if (debug)
00120         alog("debug: %s changes its host to %s", user->nick,
00121              common_get_vhost(user));
00122 }
00123 
00124 
00125 /*************************************************************************/
00126 
00127 /* Change the (virtual) hostname of a user. */
00128 
00129 void change_user_host(User * user, const char *host)
00130 {
00131     if (user->vhost)
00132         free(user->vhost);
00133     user->vhost = sstrdup(host);
00134 
00135     if (debug)
00136         alog("debug: %s changes its vhost to %s", user->nick, host);
00137 
00138 
00139 
00140     update_host(user);
00141 }
00142 
00143 /*************************************************************************/
00144 
00145 /* Change the realname of a user. */
00146 
00147 void change_user_realname(User * user, const char *realname)
00148 {
00149     if (user->realname)
00150         free(user->realname);
00151     user->realname = sstrdup(realname);
00152 
00153     if (user->na && (nick_identified(user)
00154                      || (!(user->na->nc->flags & NI_SECURE)
00155                          && nick_recognized(user)))) {
00156         if (user->na->last_realname)
00157             free(user->na->last_realname);
00158         user->na->last_realname = sstrdup(realname);
00159     }
00160 
00161     if (debug)
00162         alog("debug: %s changes its realname to %s", user->nick, realname);
00163 }
00164 
00165 
00166 /*************************************************************************/
00167 
00168 /* Change the username of a user. */
00169 
00170 void change_user_username(User * user, const char *username)
00171 {
00172     if (user->vident)
00173         free(user->vident);
00174     user->vident = sstrdup(username);
00175     if (user->na && (nick_identified(user)
00176                      || (!(user->na->nc->flags & NI_SECURE)
00177                          && nick_recognized(user)))) {
00178         if (user->na->last_usermask)
00179             free(user->na->last_usermask);
00180 
00181         user->na->last_usermask =
00182             smalloc(strlen(common_get_vident(user)) +
00183                     strlen(common_get_vhost(user)) + 2);
00184         sprintf(user->na->last_usermask, "%s@%s", common_get_vident(user),
00185                 common_get_vhost(user));
00186     }
00187     if (debug)
00188         alog("debug: %s changes its username to %s", user->nick, username);
00189 }
00190 
00191 /*************************************************************************/
00192 
00193 /* Remove and free a User structure. */
00194 
00195 void delete_user(User * user)
00196 {
00197     struct u_chanlist *c, *c2;
00198     struct u_chaninfolist *ci, *ci2;
00199     char *realname;
00200 
00201     if (LogUsers) {
00202         realname = normalizeBuffer(user->realname);
00203         if (ircd->vhost) {
00204             alog("LOGUSERS: %s (%s@%s => %s) (%s) left the network (%s).",
00205                  user->nick, user->username, user->host,
00206                  (user->vhost ? user->vhost : "(none)"),
00207                  realname, user->server->name);
00208         } else {
00209             alog("LOGUSERS: %s (%s@%s) (%s) left the network (%s).",
00210                  user->nick, user->username, user->host,
00211                  realname, user->server->name);
00212         }
00213         free(realname);
00214     }
00215     send_event(EVENT_USER_LOGOFF, 1, user->nick);
00216 
00217     if (debug >= 2)
00218         alog("debug: delete_user() called");
00219     usercnt--;
00220     if (is_oper(user))
00221         opcnt--;
00222     if (debug >= 2)
00223         alog("debug: delete_user(): free user data");
00224     free(user->username);
00225     free(user->host);
00226     if (user->chost)
00227         free(user->chost);
00228     if (user->vhost)
00229         free(user->vhost);
00230     if (user->vident)
00231         free(user->vident);
00232     if (user->uid) {
00233         free(user->uid);
00234     }
00235     Anope_Free(user->realname);
00236     Anope_Free(user->hostip);
00237     if (debug >= 2) {
00238         alog("debug: delete_user(): remove from channels");
00239     }
00240     c = user->chans;
00241     while (c) {
00242         c2 = c->next;
00243         chan_deluser(user, c->chan);
00244         free(c);
00245         c = c2;
00246     }
00247     /* This called only here now */
00248     cancel_user(user);
00249     if (user->na)
00250         user->na->u = NULL;
00251     if (debug >= 2)
00252         alog("debug: delete_user(): free founder data");
00253     ci = user->founder_chans;
00254     while (ci) {
00255         ci2 = ci->next;
00256         free(ci);
00257         ci = ci2;
00258     }
00259 
00260     if (user->nickTrack)
00261         free(user->nickTrack);
00262 
00263     moduleCleanStruct(&user->moduleData);
00264 
00265     if (debug >= 2)
00266         alog("debug: delete_user(): delete from list");
00267     if (user->prev)
00268         user->prev->next = user->next;
00269     else
00270         userlist[HASH(user->nick)] = user->next;
00271     if (user->next)
00272         user->next->prev = user->prev;
00273     if (debug >= 2)
00274         alog("debug: delete_user(): free user structure");
00275     free(user);
00276     if (debug >= 2)
00277         alog("debug: delete_user() done");
00278 }
00279 
00280 /*************************************************************************/
00281 /*************************************************************************/
00282 
00283 /* Return statistics.  Pointers are assumed to be valid. */
00284 
00285 void get_user_stats(long *nusers, long *memuse)
00286 {
00287     long count = 0, mem = 0;
00288     int i;
00289     User *user;
00290     struct u_chanlist *uc;
00291     struct u_chaninfolist *uci;
00292 
00293     for (i = 0; i < 1024; i++) {
00294         for (user = userlist[i]; user; user = user->next) {
00295             count++;
00296             mem += sizeof(*user);
00297             if (user->username)
00298                 mem += strlen(user->username) + 1;
00299             if (user->host)
00300                 mem += strlen(user->host) + 1;
00301             if (ircd->vhost) {
00302                 if (user->vhost)
00303                     mem += strlen(user->vhost) + 1;
00304             }
00305             if (user->realname)
00306                 mem += strlen(user->realname) + 1;
00307             if (user->server->name)
00308                 mem += strlen(user->server->name) + 1;
00309             for (uc = user->chans; uc; uc = uc->next)
00310                 mem += sizeof(*uc);
00311             for (uci = user->founder_chans; uci; uci = uci->next)
00312                 mem += sizeof(*uci);
00313         }
00314     }
00315     *nusers = count;
00316     *memuse = mem;
00317 }
00318 
00319 /*************************************************************************/
00320 
00321 /* Find a user by nick.  Return NULL if user could not be found. */
00322 
00323 User *finduser(const char *nick)
00324 {
00325     User *user;
00326 
00327     if (!nick || !*nick) {
00328         if (debug) {
00329             alog("debug: finduser() called with NULL values");
00330         }
00331         return NULL;
00332     }
00333 
00334     if (debug >= 3)
00335         alog("debug: finduser(%p)", nick);
00336     user = userlist[HASH(nick)];
00337     while (user && stricmp(user->nick, nick) != 0)
00338         user = user->next;
00339     if (debug >= 3)
00340         alog("debug: finduser(%s) -> 0x%p", nick, (void *) user);
00341     return user;
00342 }
00343 
00344 
00345 /*************************************************************************/
00346 
00347 /* Iterate over all users in the user list.  Return NULL at end of list. */
00348 
00349 static User *current;
00350 static int next_index;
00351 
00352 User *firstuser(void)
00353 {
00354     next_index = 0;
00355     current = NULL;
00356     while (next_index < 1024 && current == NULL)
00357         current = userlist[next_index++];
00358     if (debug)
00359         alog("debug: firstuser() returning %s",
00360              current ? current->nick : "NULL (end of list)");
00361     return current;
00362 }
00363 
00364 User *nextuser(void)
00365 {
00366     if (current)
00367         current = current->next;
00368     if (!current && next_index < 1024) {
00369         while (next_index < 1024 && current == NULL)
00370             current = userlist[next_index++];
00371     }
00372     if (debug)
00373         alog("debug: nextuser() returning %s",
00374              current ? current->nick : "NULL (end of list)");
00375     return current;
00376 }
00377 
00378 User *find_byuid(const char *uid)
00379 {
00380     User *u, *next;
00381 
00382     if (!uid) {
00383         if (debug)
00384             alog("debug: find_byuid() called with NULL-value");
00385         return NULL;
00386     }
00387 
00388     u = first_uid();
00389     while (u) {
00390         next = next_uid();
00391         if (u->uid) {
00392             if (!stricmp(uid, u->uid)) {
00393                 return u;
00394             }
00395         }
00396         u = next;
00397     }
00398     return NULL;
00399 }
00400 
00401 static User *current_uid;
00402 static int next_index_uid;
00403 
00404 User *first_uid(void)
00405 {
00406     next_index_uid = 0;
00407     current_uid = NULL;
00408     while (next_index_uid < 1024 && current_uid == NULL) {
00409         current_uid = userlist[next_index_uid++];
00410     }
00411     if (debug >= 2) {
00412         alog("debug: first_uid() returning %s %s",
00413              current_uid ? current_uid->nick : "NULL (end of list)",
00414              current_uid ? current_uid->uid : "");
00415     }
00416     return current_uid;
00417 }
00418 
00419 User *next_uid(void)
00420 {
00421     if (current_uid)
00422         current_uid = current_uid->next;
00423     if (!current_uid && next_index_uid < 1024) {
00424         while (next_index_uid < 1024 && current_uid == NULL)
00425             current_uid = userlist[next_index_uid++];
00426     }
00427     if (debug >= 2) {
00428         alog("debug: next_uid() returning %s %s",
00429              current_uid ? current_uid->nick : "NULL (end of list)",
00430              current_uid ? current_uid->uid : "");
00431     }
00432     return current_uid;
00433 }
00434 
00435 Uid *new_uid(const char *nick, char *uid)
00436 {
00437     Uid *u, **list;
00438 
00439     u = scalloc(sizeof(Uid), 1);
00440     if (!nick || !uid) {
00441         return NULL;
00442     }
00443     strscpy(u->nick, nick, NICKMAX);
00444     list = &uidlist[HASH2(u->nick)];
00445     u->next = *list;
00446     if (*list)
00447         (*list)->prev = u;
00448     *list = u;
00449     u->uid = sstrdup(uid);
00450     return u;
00451 }
00452 
00453 Uid *find_uid(const char *nick)
00454 {
00455     Uid *u;
00456     int i;
00457 
00458     for (i = 0; i < 1024; i++) {
00459         for (u = uidlist[i]; u; u = u->next) {
00460             if (!stricmp(nick, u->nick)) {
00461                 return u;
00462             }
00463         }
00464     }
00465     return NULL;
00466 }
00467 
00468 Uid *find_nickuid(const char *uid)
00469 {
00470     Uid *u;
00471     int i;
00472 
00473     for (i = 0; i < 1024; i++) {
00474         for (u = uidlist[i]; u; u = u->next) {
00475             if (!stricmp(uid, u->uid)) {
00476                 return u;
00477             }
00478         }
00479     }
00480     return NULL;
00481 }
00482 
00483 /*************************************************************************/
00484 /*************************************************************************/
00485 
00486 /* Handle a server NICK command. */
00500 User *do_nick(const char *source, char *nick, char *username, char *host,
00501               char *server, char *realname, time_t ts, uint32 svid,
00502               uint32 ip, char *vhost, char *uid)
00503 {
00504     User *user = NULL;
00505 
00506     char *tmp = NULL;
00507     NickAlias *old_na;          /* Old nick rec */
00508     int nc_changed = 1;         /* Did nick core change? */
00509     int status = 0;             /* Status to apply */
00510     char mask[USERMAX + HOSTMAX + 2];
00511     char *logrealname;
00512     char *oldnick;
00513 
00514     if (!*source) {
00515         char ipbuf[16];
00516         struct in_addr addr;
00517 
00518         if (ircd->nickvhost) {
00519             if (vhost) {
00520                 if (!strcmp(vhost, "*")) {
00521                     vhost = NULL;
00522                     if (debug)
00523                         alog("debug: new user�with no vhost in NICK command: %s", nick);
00524                 }
00525             }
00526         }
00527 
00528         /* This is a new user; create a User structure for it. */
00529         if (debug)
00530             alog("debug: new user: %s", nick);
00531 
00532         if (ircd->nickip) {
00533             addr.s_addr = htonl(ip);
00534             ntoa(addr, ipbuf, sizeof(ipbuf));
00535         }
00536 
00537 
00538         if (LogUsers) {
00542             if (realname) {
00543                 tmp = strchr(realname, '%');
00544                 while (tmp) {
00545                     *tmp = '-';
00546                     tmp = strchr(realname, '%');
00547                 }
00548             }
00549             logrealname = normalizeBuffer(realname);
00550 
00555             if (ircd->nickvhost) {
00556                 if (ircd->nickip) {
00557                     alog("LOGUSERS: %s (%s@%s => %s) (%s) [%s] connected to the network (%s).", nick, username, host, (vhost ? vhost : "none"), logrealname, ipbuf, server);
00558                 } else {
00559                     alog("LOGUSERS: %s (%s@%s => %s) (%s) connected to the network (%s).", nick, username, host, (vhost ? vhost : "none"), logrealname, server);
00560                 }
00561             } else {
00562                 if (ircd->nickip) {
00563                     alog("LOGUSERS: %s (%s@%s) (%s) [%s] connected to the network (%s).", nick, username, host, logrealname, ipbuf, server);
00564                 } else {
00565                     alog("LOGUSERS: %s (%s@%s) (%s) connected to the network (%s).", nick, username, host, logrealname, server);
00566                 }
00567             }
00568             Anope_Free(logrealname);
00569         }
00570 
00571         /* We used to ignore the ~ which a lot of ircd's use to indicate no
00572          * identd response.  That caused channel bans to break, so now we
00573          * just take what the server gives us.  People are still encouraged
00574          * to read the RFCs and stop doing anything to usernames depending
00575          * on the result of an identd lookup.
00576          */
00577 
00578         /* First check for AKILLs. */
00579         /* DONT just return null if its an akill match anymore - yes its more efficent to, however, now that ircd's are
00580          * starting to use things like E/F lines, we cant be 100% sure the client will be removed from the network :/
00581          * as such, create a user_struct, and if the client is removed, we'll delete it again when the QUIT notice
00582          * comes in from the ircd.
00583          **/
00584         if (check_akill(nick, username, host, vhost, ipbuf)) {
00585 /*            return NULL; */
00586         }
00587 
00592         /* don't akill on netmerges -Certus */
00593         /* don't akill clients introduced by ulines. -Viper */
00594         if (is_sync(findserver(servlist, server))
00595             && checkDefCon(DEFCON_AKILL_NEW_CLIENTS) && !is_ulined(server)) {
00596             strncpy(mask, "*@", 3);
00597             strncat(mask, host, HOSTMAX);
00598             alog("DEFCON: adding akill for %s", mask);
00599             add_akill(NULL, mask, s_OperServ,
00600                       time(NULL) + dotime(DefConAKILL),
00601                       DefConAkillReason ? DefConAkillReason :
00602                       "DEFCON AKILL");
00603             if (check_akill(nick, username, host, vhost, ipbuf)) {
00604 /*            return NULL; */
00605             }
00606         }
00607 
00608         /* SGLINE */
00609         if (ircd->sgline) {
00610             if (check_sgline(nick, realname))
00611                 return NULL;
00612         }
00613 
00614         /* SQLINE */
00615         if (ircd->sqline) {
00616             if (check_sqline(nick, 0))
00617                 return NULL;
00618         }
00619 
00620         /* SZLINE */
00621         if (ircd->szline && ircd->nickip) {
00622             if (check_szline(nick, ipbuf))
00623                 return NULL;
00624         }
00625         /* Now check for session limits */
00626         if (LimitSessions && !is_ulined(server)
00627             && !add_session(nick, host, ipbuf))
00628             return NULL;
00629 
00630         /* Allocate User structure and fill it in. */
00631         user = new_user(nick);
00632         user->username = sstrdup(username);
00633         user->host = sstrdup(host);
00634         user->server = findserver(servlist, server);
00635         user->realname = sstrdup(realname);
00636         user->timestamp = ts;
00637         user->my_signon = time(NULL);
00638         user->chost = vhost ? sstrdup(vhost) : sstrdup(host);
00639         user->vhost = vhost ? sstrdup(vhost) : sstrdup(host);
00640         if (uid) {
00641             user->uid = sstrdup(uid);   /* p10/ts6 stuff */
00642         } else {
00643             user->uid = NULL;
00644         }
00645         user->vident = sstrdup(username);
00646         /* We now store the user's ip in the user_ struct,
00647          * because we will use it in serveral places -- DrStein */
00648         if (ircd->nickip) {
00649             user->hostip = sstrdup(ipbuf);
00650         } else {
00651             user->hostip = NULL;
00652         }
00653 
00654         if (svid == 0) {
00655             display_news(user, NEWS_LOGON);
00656             display_news(user, NEWS_RANDOM);
00657         }
00658 
00659         if (svid == 2 && user->na) {
00660             /* We do not yet know if the user should be identified or not.
00661              * mark him as recognized for now. 
00662              * It s up to the protocol module to make sure this either becomes ID'd or
00663              * is invalidated. ~ Viper */
00664             if (debug) 
00665                 alog("debug: Marking %s as recognized..", user->nick);
00666             user->svid = 1;
00667             user->na->status |= NS_RECOGNIZED;
00668             nc_changed = 0;
00669         } else if (svid == ts && user->na) {
00670             /* Timestamp and svid match, and nick is registered; automagically identify the nick */
00671             user->svid = svid;
00672             user->na->status |= NS_IDENTIFIED;
00673             check_memos(user);
00674             nc_changed = 0;
00675 
00676             /* Start nick tracking if available */
00677             if (NSNickTracking)
00678                 nsStartNickTracking(user);
00679 
00680         } else if (svid != 1) {
00681             /* Resets the svid because it doesn't match */
00682             user->svid = 1;
00683 
00684             anope_cmd_svid_umode(user->nick, user->timestamp);
00685 
00686         } else {
00687             user->svid = 1;
00688         }
00689         send_event(EVENT_NEWNICK, 1, nick);
00690 
00691     } else {
00692         /* An old user changing nicks. */
00693         if (UseTS6 && ircd->ts6)
00694             user = find_byuid(source);
00695 
00696         if (!user)
00697             user = finduser(source);
00698 
00699         if (!user) {
00700             alog("user: NICK from nonexistent nick %s", source);
00701             return NULL;
00702         }
00703         user->isSuperAdmin = 0; /* Dont let people nick change and stay SuperAdmins */
00704         if (debug)
00705             alog("debug: %s changes nick to %s", source, nick);
00706 
00707         if (LogUsers) {
00708             logrealname = normalizeBuffer(user->realname);
00709             if (ircd->vhost) {
00710                 alog("LOGUSERS: %s (%s@%s => %s) (%s) changed nick to %s (%s).", user->nick, user->username, user->host, (user->vhost ? user->vhost : "(none)"), logrealname, nick, user->server->name);
00711             } else {
00712                 alog("LOGUSERS: %s (%s@%s) (%s) changed nick to %s (%s).",
00713                      user->nick, user->username, user->host, logrealname,
00714                      nick, user->server->name);
00715             }
00716             if (logrealname) {
00717                 free(logrealname);
00718             }
00719         }
00720 
00721         user->timestamp = ts;
00722 
00723         if (stricmp(nick, user->nick) == 0) {
00724             /* No need to redo things */
00725             change_user_nick(user, nick);
00726             nc_changed = 0;
00727         } else {
00728             /* Update this only if nicks aren't the same */
00729             user->my_signon = time(NULL);
00730 
00731             old_na = user->na;
00732             if (old_na) {
00733                 if (nick_recognized(user))
00734                     user->na->last_seen = time(NULL);
00735                 status = old_na->status & NS_TRANSGROUP;
00736                 cancel_user(user);
00737             }
00738 
00739             oldnick = sstrdup(user->nick);
00740             change_user_nick(user, nick);
00741 
00742             if ((old_na ? old_na->nc : NULL) ==
00743                 (user->na ? user->na->nc : NULL))
00744                 nc_changed = 0;
00745 
00746             if (!nc_changed && (user->na))
00747                 user->na->status |= status;
00748             else {
00749                 anope_cmd_nc_change(user);
00750             }
00751 
00752             send_event(EVENT_CHANGE_NICK, 2, nick, oldnick);
00753             free(oldnick);
00754         }
00755 
00756         if (ircd->sqline) {
00757             if (!is_oper(user) && check_sqline(user->nick, 1))
00758                 return NULL;
00759         }
00760 
00761     }                           /* if (!*source) */
00762 
00763     /* Check for nick tracking to bypass identification */
00764     if (NSNickTracking && nsCheckNickTracking(user)) {
00765         user->na->status |= NS_IDENTIFIED;
00766         nc_changed = 0;
00767     }
00768 
00769     if (nc_changed || !nick_recognized(user)) {
00770         if (validate_user(user))
00771             check_memos(user);
00772 
00773     } else {
00774         if (nick_identified(user)) {
00775             char tsbuf[16];
00776             user->na->last_seen = time(NULL);
00777 
00778             if (user->na->last_usermask)
00779                 free(user->na->last_usermask);
00780             user->na->last_usermask =
00781                 smalloc(strlen(common_get_vident(user)) +
00782                         strlen(common_get_vhost(user)) + 2);
00783             sprintf(user->na->last_usermask, "%s@%s",
00784                     common_get_vident(user), common_get_vhost(user));
00785 
00786             snprintf(tsbuf, sizeof(tsbuf), "%lu",
00787                      (unsigned long int) user->timestamp);
00788             anope_cmd_svid_umode2(user, tsbuf);
00789 
00790             alog("%s: %s!%s@%s automatically identified for nick %s",
00791                  s_NickServ, user->nick, user->username,
00792                  user->host, user->nick);
00793         }
00794     }
00795 
00796     /* Bahamut sets -r on every nick changes, so we must test it even if nc_changed == 0 */
00797     if (ircd->check_nick_id) {
00798         if (nick_identified(user)) {
00799             char tsbuf[16];
00800             snprintf(tsbuf, sizeof(tsbuf), "%lu",
00801                      (unsigned long int) user->timestamp);
00802             anope_cmd_svid_umode3(user, tsbuf);
00803         }
00804     }
00805 
00806     return user;
00807 }
00808 
00809 /*************************************************************************/
00810 
00811 /* Handle a MODE command for a user.
00812  *      av[0] = nick to change mode for
00813  *      av[1] = modes
00814  */
00815 
00816 void do_umode(const char *source, int ac, char **av)
00817 {
00818     User *user;
00819 
00820     user = finduser(av[0]);
00821     if (!user) {
00822         alog("user: MODE %s for nonexistent nick %s: %s", av[1], av[0],
00823              merge_args(ac, av));
00824         return;
00825     }
00826 
00827     anope_set_umode(user, ac - 1, &av[1]);
00828 }
00829 
00830 /* Handle a UMODE2 command for a user.
00831  *      av[0] = modes
00832  */
00833 
00834 void do_umode2(const char *source, int ac, char **av)
00835 {
00836     User *user;
00837 
00838     user = finduser(source);
00839     if (!user) {
00840         alog("user: MODE %s for nonexistent nick %s: %s", av[0], source,
00841              merge_args(ac, av));
00842         return;
00843     }
00844 
00845     anope_set_umode(user, ac, &av[0]);
00846 }
00847 
00848 /*************************************************************************/
00849 
00850 /* Handle a QUIT command.
00851  *      av[0] = reason
00852  */
00853 
00854 void do_quit(const char *source, int ac, char **av)
00855 {
00856     User *user;
00857     NickAlias *na;
00858 
00859     user = finduser(source);
00860     if (!user) {
00861         alog("user: QUIT from nonexistent user %s: %s", source,
00862              merge_args(ac, av));
00863         return;
00864     }
00865     if (debug) {
00866         alog("debug: %s quits", source);
00867     }
00868     if ((na = user->na) && (!(na->status & NS_VERBOTEN))
00869         && (!(na->nc->flags & NI_SUSPENDED))
00870         && (na->status & (NS_IDENTIFIED | NS_RECOGNIZED))) {
00871         na->last_seen = time(NULL);
00872         if (na->last_quit)
00873             free(na->last_quit);
00874         na->last_quit = *av[0] ? sstrdup(av[0]) : NULL;
00875     }
00876     if (LimitSessions && !is_ulined(user->server->name)) {
00877         del_session(user->host);
00878     }
00879     delete_user(user);
00880 }
00881 
00882 /*************************************************************************/
00883 
00884 /* Handle a KILL command.
00885  *      av[0] = nick being killed
00886  *      av[1] = reason
00887  */
00888 
00889 void do_kill(char *nick, char *msg)
00890 {
00891     User *user;
00892     NickAlias *na;
00893 
00894     user = finduser(nick);
00895     if (!user) {
00896         if (debug) {
00897             alog("debug: KILL of nonexistent nick: %s", nick);
00898         }
00899         return;
00900     }
00901     if (debug) {
00902         alog("debug: %s killed", nick);
00903     }
00904     if ((na = user->na) && (!(na->status & NS_VERBOTEN))
00905         && (!(na->nc->flags & NI_SUSPENDED))
00906         && (na->status & (NS_IDENTIFIED | NS_RECOGNIZED))) {
00907         na->last_seen = time(NULL);
00908         if (na->last_quit)
00909             free(na->last_quit);
00910         na->last_quit = *msg ? sstrdup(msg) : NULL;
00911 
00912     }
00913     if (LimitSessions && !is_ulined(user->server->name)) {
00914         del_session(user->host);
00915     }
00916     delete_user(user);
00917 }
00918 
00919 /*************************************************************************/
00920 /*************************************************************************/
00921 
00922 /* Is the given user protected from kicks and negative mode changes? */
00923 
00924 int is_protected(User * user)
00925 {
00926     if (ircd->protectedumode) {
00927         return (user->mode & ircd->protectedumode);
00928     } else {
00929         return 0;
00930     }
00931 }
00932 
00933 /*************************************************************************/
00934 
00935 /* Is the given nick an oper? */
00936 
00937 int is_oper(User * user)
00938 {
00939     if (user) {
00940         return (user->mode & anope_get_oper_mode());
00941     } else {
00942         return 0;
00943     }
00944 }
00945 
00946 /*************************************************************************/
00947 /*************************************************************************/
00948 
00949 /* Is the given user ban-excepted? */
00950 int is_excepted(ChannelInfo * ci, User * user)
00951 {
00952     if (!ci->c || !ircd->except)
00953         return 0;
00954 
00955     if (elist_match_user(ci->c->excepts, user))
00956         return 1;
00957 
00958     return 0;
00959 }
00960 
00961 /*************************************************************************/
00962 
00963 /* Is the given MASK ban-excepted? */
00964 int is_excepted_mask(ChannelInfo * ci, char *mask)
00965 {
00966     if (!ci->c || !ircd->except)
00967         return 0;
00968 
00969     if (elist_match_mask(ci->c->excepts, mask, 0))
00970         return 1;
00971 
00972     return 0;
00973 }
00974 
00975 
00976 /*************************************************************************/
00977 
00978 /* Does the user's usermask match the given mask (either nick!user@host or
00979  * just user@host)?
00980  */
00981 
00982 static int _match_usermask(const char *mask, User * user, boolean full)
00983 {
00984     char *mask2;
00985     char *nick, *username, *host;
00986     int result;
00987 
00988     if (!mask || !*mask) {
00989         return 0;
00990     }
00991 
00992     mask2 = sstrdup(mask);
00993 
00994     if (strchr(mask2, '!')) {
00995         nick = strtok(mask2, "!");
00996         username = strtok(NULL, "@");
00997     } else {
00998         nick = NULL;
00999         username = strtok(mask2, "@");
01000     }
01001     host = strtok(NULL, "");
01002     if (!username || !host) {
01003         free(mask2);
01004         return 0;
01005     }
01006 
01007     if (nick) {
01008         result = match_wild_nocase(nick, user->nick)
01009             && match_wild_nocase(username, user->username)
01010             && ((full && match_wild_nocase(host, user->host))
01011                 || match_wild_nocase(host, user->vhost)
01012                 || match_wild_nocase(host, user->chost));
01013     } else {
01014         result = match_wild_nocase(username, user->username)
01015             && ((full && match_wild_nocase(host, user->host))
01016                 || match_wild_nocase(host, user->vhost)
01017                 || match_wild_nocase(host, user->chost));
01018     }
01019 
01020     free(mask2);
01021     return result;
01022 }
01023 
01024 int match_usermask(const char *mask, User *user)
01025 {
01026         return _match_usermask(mask, user, false);
01027 }
01028 
01029 int match_usermask_full(const char *mask, User *user, boolean full)
01030 {
01031         return _match_usermask(mask, user, full);
01032 }
01033 
01034 /*************************************************************************/
01035 
01036 /* simlar to match_usermask, except here we pass the host as the IP */
01037 
01038 int match_userip(const char *mask, User * user, char *iphost)
01039 {
01040     char *mask2;
01041     char *nick, *username, *host;
01042     int result;
01043 
01044     if (!mask || !*mask) {
01045         return 0;
01046     }
01047 
01048     mask2 = sstrdup(mask);
01049 
01050     if (strchr(mask2, '!')) {
01051         nick = strtok(mask2, "!");
01052         username = strtok(NULL, "@");
01053     } else {
01054         nick = NULL;
01055         username = strtok(mask2, "@");
01056     }
01057     host = strtok(NULL, "");
01058     if (!username || !host) {
01059         free(mask2);
01060         return 0;
01061     }
01062 
01063     if (nick) {
01064         result = match_wild_nocase(nick, user->nick)
01065             && match_wild_nocase(username, user->username)
01066             && (match_wild_nocase(host, iphost)
01067                 || match_wild_nocase(host, user->vhost));
01068     } else {
01069         result = match_wild_nocase(username, user->username)
01070             && (match_wild_nocase(host, iphost)
01071                 || match_wild_nocase(host, user->vhost));
01072     }
01073 
01074     free(mask2);
01075     return result;
01076 }
01077 
01078 /*************************************************************************/
01079 
01080 /* Split a usermask up into its constitutent parts.  Returned strings are
01081  * malloc()'d, and should be free()'d when done with.  Returns "*" for
01082  * missing parts.
01083  */
01084 
01085 void split_usermask(const char *mask, char **nick, char **user,
01086                     char **host)
01087 {
01088     char *mask2 = sstrdup(mask);
01089 
01090     *nick = strtok(mask2, "!");
01091     *user = strtok(NULL, "@");
01092     *host = strtok(NULL, "");
01093     /* Handle special case: mask == user@host */
01094     if (*nick && !*user && strchr(*nick, '@')) {
01095         *nick = NULL;
01096         *user = strtok(mask2, "@");
01097         *host = strtok(NULL, "");
01098     }
01099     if (!*nick)
01100         *nick = "*";
01101     if (!*user)
01102         *user = "*";
01103     if (!*host)
01104         *host = "*";
01105     *nick = sstrdup(*nick);
01106     *user = sstrdup(*user);
01107     *host = sstrdup(*host);
01108     free(mask2);
01109 }
01110 
01111 /*************************************************************************/
01112 
01113 /* Given a user, return a mask that will most likely match any address the
01114  * user will have from that location.  For IP addresses, wildcards the
01115  * appropriate subnet mask (e.g. 35.1.1.1 -> 35.*; 128.2.1.1 -> 128.2.*);
01116  * for named addresses, wildcards the leftmost part of the name unless the
01117  * name only contains two parts.  If the username begins with a ~, delete
01118  * it.  The returned character string is malloc'd and should be free'd
01119  * when done with.
01120  */
01121 
01122 char *create_mask(User * u)
01123 {
01124     char *mask, *s, *end;
01125     int ulen = strlen(common_get_vident(u));
01126 
01127     /* Get us a buffer the size of the username plus hostname.  The result
01128      * will never be longer than this (and will often be shorter), thus we
01129      * can use strcpy() and sprintf() safely.
01130      */
01131     end = mask = smalloc(ulen + strlen(common_get_vhost(u)) + 3);
01132     end += sprintf(end, "%s%s@",
01133                    (ulen <
01134                     (*(common_get_vident(u)) ==
01135                      '~' ? USERMAX + 1 : USERMAX) ? "*" : ""),
01136                    (*(common_get_vident(u)) ==
01137                     '~' ? common_get_vident(u) +
01138                     1 : common_get_vident(u)));
01139 
01140     if (strspn(common_get_vhost(u), "0123456789.") ==
01141         strlen(common_get_vhost(u))
01142         && (s = strchr(common_get_vhost(u), '.'))
01143         && (s = strchr(s + 1, '.'))
01144         && (s = strchr(s + 1, '.'))
01145         && (!strchr(s + 1, '.'))) {     /* IP addr */
01146         s = sstrdup(common_get_vhost(u));
01147         *strrchr(s, '.') = 0;
01148 
01149         sprintf(end, "%s.*", s);
01150         free(s);
01151     } else {
01152         if ((s = strchr(common_get_vhost(u), '.')) && strchr(s + 1, '.')) {
01153             s = sstrdup(strchr(common_get_vhost(u), '.') - 1);
01154             *s = '*';
01155             strcpy(end, s);
01156             free(s);
01157         } else {
01158             strcpy(end, common_get_vhost(u));
01159         }
01160     }
01161     return mask;
01162 }
01163 
01164 /*************************************************************************/