Main Page | Modules | Namespace List | Class Hierarchy | Class List | File List | Class Members | File Members | Related Pages

nickserv.c

Go to the documentation of this file.
00001 
00015 /*
00016  * Copyright (c) 1996-1997 Chip Norkus,
00017  * Copyright (c) 1997 Max Byrd
00018  * Copyright (c) 1997 Greg Poma,
00019  * Copyright (c) 2000-2001 James Hess
00020  * All rights reserved.
00021  *
00022  * Redistribution and use in source and binary forms, with or without
00023  * modification, are permitted provided that the following conditions
00024  * are met:
00025  * 1. Redistributions of source code must retain the above copyright
00026  *    notice, this list of conditions and the following disclaimer.
00027  * 2. Redistributions in binary form must reproduce the above copyright
00028  *    notice, this list of conditions and the following disclaimer in the
00029  *    documentation and/or other materials provided with the distribution.
00030  * 3. Neither the name of the authors nor the names of its contributors
00031  *    may be used to endorse or promote products derived from this software
00032  *    without specific prior written permission.
00033  *
00034  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
00035  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00036  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00037  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS
00038  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00039  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00040  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
00041  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00042  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
00043  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
00044  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00045  */
00046 
00047 #include "services.h"
00048 #include "memoserv.h"
00049 #include "queue.h"
00050 #include "macro.h"
00051 #include "nickserv.h"
00052 #include "chanserv.h"
00053 #include "infoserv.h"
00054 #include "email.h"
00055 #include "hash.h"
00056 #include "clone.h"
00057 #include "mass.h"
00058 #include "db.h"
00059 #include "log.h"
00060 #include "hash/md5pw.h"
00061 #define REALLEN 50
00062 
00063 struct akill;
00064 
00066 typedef struct ghost_struct GhostList;
00067 
00068 GhostList *getGhost(char *);
00069 char *urlEncode(const char *);
00070 const char *GetAuthChKey(const char*, const char*pass, time_t,
00071                          u_int32_t code_arg);
00072 const char *PrintPass(u_char pI[], char enc);
00073 struct akill* getAkill(char *nick, char *user, char *host);
00074 char* applyAkill(char* nick, char* user, char* host, struct akill* ak);
00075 char* getAkReason(struct akill *ak);
00076 struct akill* getAhurt(char *nick, char *user, char *host);
00077 long getAkillId(struct akill* ak);
00078 void enforce_nickname (char* nick);
00079 int isPasswordAcceptable(const char* password, char* reason);
00080 
00081 // *INDENT-OFF*
00082 
00084 OperList *firstOper;
00085 
00087 static unsigned long top_cnick = 0;
00088 
00090 static RegId    top_user_idnum(0, 1);
00091 
00094 RegId   top_regnick_idnum(0, 1001);
00095 
00096 
00098 struct ghost_struct {
00100     char ghost[NICKLEN];
00101 
00103     struct ghost_struct *next;
00104 
00106     struct ghost_struct *previous;
00107 };
00108 
00110 int totalghosts = 0;
00111 
00112 
00114 struct opflag_table { 
00116     char symbol;
00117 
00119     flag_t flag;
00120 
00122     char *name;
00123 };
00124 
00126 #define OPFLAG(x, y, z) { x,    y,  z }
00127 
00129 struct opflag_table opflags[] = 
00130 {
00131   /* ROOT/RR intentionally shouldn't be in this list. */
00132     OPFLAG('A', OADMIN,     "ADMIN"),
00133     OPFLAG('O', OSERVOP,    "SERVOP"),
00134     OPFLAG('o', OOPER,      "o"),
00135     OPFLAG('k', ORAKILL,    "AKILL"),
00136     OPFLAG('K', OAKILL,     "XAKILL"),
00137     OPFLAG('p', OINFOPOST,  "INFO-POST"),
00138     OPFLAG('s', OSETOP,     "SETOP"),
00139     OPFLAG('S', OSETFLAG,   "SETFLAG"),
00140     OPFLAG('N', ONBANDEL,   "NBANDEL"),
00141     OPFLAG('C', OCBANDEL,   "CBANDEL"),
00142     OPFLAG('I', OIGNORE,    "IGNORE"),
00143     OPFLAG('G', OGRP,       "GRp"),
00144     OPFLAG('r', ORAW,       "RAW"),
00145     OPFLAG('j', OJUPE,      "JUPE"),
00146     OPFLAG('L', OLIST,      "LIST"),
00147     OPFLAG('!', OPROT,      "FLAG-LOCK"),
00148     OPFLAG('c', OCLONE,     "CLONE"),
00149     OPFLAG('a', OACC,       "OVERRIDE"),
00150     OPFLAG('h', OHELPOP,    "HELPOP"),
00151     OPFLAG('H', OAHURT,     "AHURT"),
00152     OPFLAG('D', ODMOD,      "DIRECTMOD"),
00153     OPFLAG('*', OPFLAG_ADMIN | OPFLAG_DEFAULT | OPFLAG_ROOTSET, "*"),
00154     { (char)0, (int)0,  (char *)0 }
00155 };
00156 
00157 #undef OPFLAG
00158 
00160 enum ns_set_en { 
00161     NSS_FLAG,       
00162     NSS_PROC        
00163 };
00164 
00165 struct nss_tab {
00166     const char *keyword;        
00167     const char *description;    
00168     enum ns_set_en set_type;    
00169     flag_t flag;                
00170     flag_t opFlagsRequired;     
00171 
00173     cmd_return (*proc)(nss_tab *, UserList *nick, char *a[], int);
00174 };
00175 
00176 
00178 char *cnick_prefixes[] = 
00179 {
00180     "Visitor-",
00181     "Nobody-",
00182     "Unnamed-",
00183     "Nickless-",
00184     "Nonick-",
00185     "Untitled-"
00186 };
00187 
00189 #define NUM_CNICKS (sizeof(cnick_prefixes)/sizeof(char *))
00190 
00191 GhostList *firstGhost = NULL;   
00192 GhostList *lastGhost = NULL;    
00193 
00195 interp::service_cmd_t nickserv_commands[] = 
00196 {
00197   /* string             function         Flags      L */
00198   { "help",             ns_help,         0,     LOG_NO, CMD_AHURT },
00199   { "identify",         ns_identify,     0,     LOG_NO, CMD_AHURT },
00200   { "identify-plain",   ns_identify,     0,     LOG_NO, CMD_AHURT },
00201   { "id-md5",           ns_cidentify,    0,     LOG_NO, CMD_AHURT },
00202   { "id",               ns_identify,     0,     LOG_NO, CMD_AHURT },
00203   { "sidentify",        ns_identify,     0,     LOG_NO, CMD_AHURT },
00204   { "identify-*",       ns_cidentify,    0,     LOG_NO, CMD_AHURT | CMD_MATCH },
00205   { "register",         ns_register,     0,     LOG_NO, 0 },
00206   { "info",             ns_info,         0,     LOG_NO, 0 },
00207   { "ghost",            ns_ghost,        0,     LOG_NO, 0 },
00208   { "recover",          ns_recover,      0,     LOG_NO, 0 },
00209   { "release",          ns_release,      0,     LOG_NO, 0 },
00210   { "set",              ns_set,          0,     LOG_NO, CMD_REG },
00211   { "vacation",         ns_vacation,     0,     LOG_NO, 0 /*MD_REG*/ },
00212   { "drop",             ns_drop,         0,     LOG_NO, CMD_REG },
00213   { "addmask",          ns_addmask,      0,     LOG_NO, CMD_REG },
00214   { "access",           ns_access,       0,     LOG_NO, 0 },
00215   { "acc",              ns_acc,          0,     LOG_NO, 0 },
00216   { "logoff",           ns_logoff,       0,     LOG_NO, 0 },
00217   { "logout",           ns_logoff,       0,     LOG_NO, 0 },
00218   { "setflag",          ns_setflags,     OOPER, LOG_NO, 0 },
00219   { "setop",            ns_setopflags,   OOPER, LOG_NO, 0 },
00220   { "mark",             ns_mark,         OOPER, LOG_NO, 0 },
00221   { "siteok",           ns_bypass,       OOPER, LOG_NO, CMD_REG },
00222   { "bypass",           ns_bypass,       OOPER, LOG_NO, CMD_REG },
00223   { "banish",           ns_banish,       OOPER, LOG_NO, CMD_REG },
00224   { "getpass",          ns_getpass,      0, LOG_NO, CMD_REG },
00225   { "sendpass",         ns_getpass,      0, LOG_NO, CMD_REG },
00226   { "setpass",          ns_setpass,      0,     LOG_DB, 0 },
00227   { "setemail",         ns_setemail,         0, LOG_NO, CMD_REG },
00228   { "realgetpass",      ns_getrealpass,  OOPER, LOG_NO, CMD_REG },
00229   { "delete",           ns_delete,       OOPER, LOG_DB, CMD_REG },
00230   { "list",             ns_list,         OOPER, LOG_NO, CMD_REG },
00231   { "save",             ns_save,         OOPER, LOG_NO, CMD_REG },
00232   { "savememo",         ms_save,         OOPER, LOG_NO, CMD_REG },
00233   { NULL }
00234 };
00235 
00236 // *INDENT-ON*
00237 
00238 /**************************************************************************/
00239 
00252 void nDesynch(char *nick, char *type)
00253 {
00254     dlogEntry("Desynced user: \"%s\" (%p) removed", nick, nick);
00255 
00256     if (nick) {
00257         /*sSend(":%s PRIVMSG " DEBUGCHAN
00258               " :User %s DESYNCHED during command [%s]", NickServ, nick,
00259               type);*/
00260         sSend(":%s GLOBOPS "
00261               " :User %s DESYNCHED during command [%s]", NickServ, nick,
00262               type);
00263         if (!getNickData(nick))
00264             sSend(":%s KILL %s :%s (Desynch, type: [%s])", myname, nick,
00265                   myname, type);
00266     }
00267     return;
00268 }
00269 
00270 
00271 /*
00272  * ===DOC===
00273  * getNickData will find a nick and retreieve data for it
00274  * init*Data cleans up a user/nick ent
00275  * killide, uhm, killides someone, :)
00276  */
00277 void annoyNickThief(UserList *);
00278 void complainAboutEmail(UserList *);
00279 void killide(char *);
00280 void removeEnforcer(char *);    
00281 
00283 static void freeUserListRec(UserList *zap)
00284 {
00285     SetDynBuffer(&zap->host, NULL);
00286 #ifdef TRACK_GECOS
00287     SetDynBuffer(&zap->gecos, NULL);
00288 #endif
00289     FREE(zap);
00290 }
00291 
00293 static void freeRegNickListRec(RegNickList *zap)
00294 {
00295     if (zap->url != NULL)
00296         FREE(zap->url);
00297     SetDynBuffer(&zap->host, NULL);
00298 #ifdef TRACK_GECOS
00299     SetDynBuffer(&zap->gecos, NULL);
00300 #endif
00301 
00302     SetDynBuffer(&zap->markby, NULL);
00303     FREE(zap);
00304 }
00305 
00329 void NickSeeUser(UserList *newnick, RegNickList *reg, int caccess,
00330                  int verbose) 
00331 {
00332 
00333     /* strncpyzt(reg->nick, newnick->nick, NICKLEN); */
00334     /* The heck was that?  -Mysid */
00335 
00336     strncpyzt(reg->user, newnick->user, USERLEN);
00337     SetDynBuffer(&reg->host, newnick->host);
00338 
00339 #ifdef TRACK_GECOS
00340     SetDynBuffer(&reg->gecos, newnick->gecos);
00341 #endif
00342 
00343     reg->timestamp = CTime;
00344     reg->flags &= ~NVACATION;
00345 
00346     if (verbose)
00347     {
00348         checkMemos(newnick);
00349         complainAboutEmail(newnick);
00350         newsNag(newnick);
00351     }
00352 }
00353 
00375 static void SetUserNickHostReal(UserList *newnick, char *nick, char *user,
00376                          char *host, char *gecos)
00377 {
00378     char HostTmp[HOSTLEN+1];
00379 #ifdef TRACK_GECOS
00380     char RealTmp[REALLEN+1];
00381 #endif
00382 
00383     strncpyzt(newnick->nick, nick, NICKLEN);
00384     strncpyzt(newnick->user, user, USERLEN);
00385 
00386     strncpyzt(HostTmp, host, HOSTLEN);
00387     SetDynBuffer(&newnick->host, HostTmp);
00388 #ifdef TRACK_GECOS
00389     strncpyzt(RealTmp, gecos, sizeof(RealTmp));
00390     SetDynBuffer(&newnick->gecos, RealTmp);
00391 #endif
00392 
00393 }
00394 
00400 char NickGetEnc(RegNickList *rnl)
00401 {
00402     if (rnl)
00403         return ((rnl->flags & NENCRYPT) ? '$' : '@');
00404     return '@';
00405 }
00406 
00417 void addNewUser(char **args, int numargs)
00418 {
00419     UserList *newnick = NULL;
00420     struct akill* ak;
00421     char *reason = NULL;
00422     char realtmp[REALLEN+1];
00423     struct akill* ahitem;
00424 
00425     if (numargs < 7) {
00426         sSend
00427             (":%s GLOBOP :Error adding nick from uplink server!  (args == %d)",
00428              OperServ, numargs);
00429         return;
00430     }
00431 
00432     if (getNickData(args[1])) {
00433         sSend
00434             (":%s GLOBOPS :Desync in adding new user \"%s\" (%p) (%s@%s) -- user exists??",
00435              NickServ, args[1], newnick, args[4], args[5]);
00436         logDump(corelog,
00437                 "Desync in adding new user \"%s\" (%p) (%s@%s) -- user exists??",
00438                 args[1], newnick, args[4], args[5]);
00439     }
00440 
00441        /* Try to prevent race */
00442        if (args[1] && isGhost(args[1])) {
00443          sSend(":%s KILL %s :%s!%s (Nickname currently blocked for NickServ enforcer).", services[1].name, args[1], services[1].host, services[1].name);
00444          /* delGhost(args[1]); */
00445          addGhost(args[1]);
00446          return;
00447        }
00448 
00449     newnick = (UserList *) oalloc(sizeof(UserList));
00450     dlogEntry("Adding new user: \"%s\" (%p) (%s@%s)", args[1], newnick,
00451               args[4], args[5]);
00452     if (args[4][0] == '~')
00453         args[4]++;
00454     args[7]++;
00455 
00456     parse_str(args, numargs, 7, realtmp, sizeof(realtmp));
00457     SetUserNickHostReal(newnick, args[1], args[4], args[5], realtmp);
00458 
00459     newnick->reg = getRegNickData(args[1]);
00460     newnick->timestamp = (time_t) atol(args[3]);
00461     if ((ak = getAkill(newnick->nick, newnick->user, newnick->host)) &&
00462             (reason = getAkReason(ak))) {
00463 
00464         sSend(":%s KILL %s :%s!%s (AKilled: %s)", services[1].name,
00465               newnick->nick, services[1].host, services[1].name, reason);
00466         applyAkill(newnick->nick, newnick->user, newnick->host, ak);
00467         freeUserListRec(newnick);
00468         /* remUser(args[1]); */
00469         addGhost(args[1]);
00470         timer(30, delTimedGhost, strdup(args[1]));
00471         return;
00472     }
00473 
00474     newnick->idnum.SetNext(top_user_idnum);
00475 
00476     if (((CTime - 240) <= (newnick->timestamp)) && (ahitem = getAhurt(newnick->nick, newnick->user, newnick->host))) {
00477 #ifdef IRCD_HURTSET
00478         sSend(":%s HURTSET %s 2 :[#%.6x] Subject to a selective user ban.",
00479               OperServ, newnick->nick, getAkillId(ahitem));
00480 #endif
00481         newnick->oflags |= NISAHURT;
00482     }
00483     if (newnick->reg) {
00484         newnick->reg->flags &= ~(NDOEDIT);
00485 
00486         if (newnick->reg->flags & NBANISH) {
00487             sSend(":%s KILL %s :%s!%s (Banished nickname)",
00488                   services[1].name, newnick->nick, services[1].host,
00489                   services[1].name);
00490             freeUserListRec(newnick);
00491             /* remUser(args[1]); */
00492             addGhost(args[1]);
00493             timer(15, delTimedGhost, strdup(args[1]));
00494             return;
00495         }
00496 
00497         /*if (newnick->reg && !newnick->auth_cookie) {
00498          * sSend(":%s NOTICE %s :200 MD5 PLAIN", NickServ, newnick->nick, newnick->auth_cookie, newnick->idnum);
00499          * } */
00500         if ((newnick->reg->flags & NDBISMASK)) {
00501             newnick->oflags |= NOISMASK;
00502             sSend(":%s MODE %s :+m", NickServ, newnick->nick);
00503         }
00504 
00505         if (!checkAccess(newnick->user, newnick->host, newnick->reg)) {
00506             newnick->caccess = 1;
00507             annoyNickThief(newnick);
00508         } else {
00509             newnick->caccess = 2;
00510             newnick->reg->timestamp = (time_t) atol(args[3]);
00511 
00512             NickSeeUser(newnick, newnick->reg, 2, 1);
00513         }
00514     } else {
00515         /* Make default +m */
00516         do {
00517             newnick->oflags |= NOISMASK;
00518             sSend(":%s MODE %s :+m", NickServ, newnick->nick);
00519         } while (0);
00520 
00521 #ifdef WELCOME_NOTE
00522         PutReply(InfoServ, newnick, RPL_IS_GREET_1ARG, WELCOME_NOTE, 0, 0);
00523 #endif
00524 #ifdef DISCLAIMER
00525         PutReply(InfoServ, newnick, RPL_IS_GREET_1ARG, DISCLAIMER, 0, 0);
00526 #endif
00527 #ifdef COPYRIGHT
00528         PutReply(InfoServ, newnick, RPL_IS_COPYRIGHT_1ARG, VERSION_NUM, 0, 0);
00529 #endif
00530     }
00531 
00532     if (addClone(newnick->nick, newnick->user, newnick->host))
00533         freeUserListRec(newnick);
00534     else {
00535         addNick(newnick);
00536     }
00537 
00538     if (mostusers < totalusers)
00539         mostusers = totalusers;
00540 }
00541 
00562 void changeNick(char *from, char *to, char *ts)
00563 {
00564     UserList *changeme, *tmp;
00565     char tmp1[NICKLEN + 2];
00566 
00567     changeme = getNickData(from);
00568     if (changeme == NULL) {
00569         nDesynch(from, "NICK");
00570         return;
00571     }
00572 
00573     if (changeme->oflags & NCNICK) {
00574         addGhost(changeme->nick);
00575         timer(120, delTimedGhost, strdup(changeme->nick));
00576         changeme->oflags &= ~(NCNICK);
00577     }
00578 
00579     /* ALOT of changing around goes on here....it rather sucks...ohwell */
00580     tmp = (UserList *) oalloc(sizeof(UserList));
00581     tmp->idnum.SetNext(top_user_idnum);
00582     dlogEntry("Changing nick -> \"%s\" (%p) to \"%s\" (%p)", from, from,
00583               to, tmp);
00584     strcpy(tmp->nick, to);
00585 #ifdef TRACK_GECOS
00586     SetUserNickHostReal(tmp, to, changeme->user, changeme->host, changeme->gecos);
00587 #else
00588     SetUserNickHostReal(tmp, to, changeme->user, changeme->host, NULL);
00589 #endif
00590 
00591     tmp->oflags = changeme->oflags;
00592     tmp->floodlevel = changeme->floodlevel;
00593 
00594     changeNickOnAllChans(changeme, tmp);
00595     if (ts && *ts) {
00596         if (*ts == ':')
00597             ts++;
00598         tmp->timestamp = (time_t) atol(ts);
00599     } else
00600         tmp->timestamp = CTime;
00601 
00602     if (changeme->id.nick) {
00603         RegNickList *tmptarget = getRegNickData(changeme->id.nick);
00604         tmp->id.nick = changeme->id.nick;
00605         tmp->id.idnum = changeme->id.idnum;
00606         /* Update timestamp unless the nick has a new owner */
00607         if (tmptarget && (tmptarget->timereg < changeme->id.timestamp))
00608             tmp->id.timestamp = tmp->timestamp;
00609         else
00610             clearIdentify(tmp);
00611         changeme->id.nick = NULL;
00612     }
00613 
00614     // Update the "Last Seen" time  
00615     if (changeme->reg && isIdentified(changeme, changeme->reg))
00616         changeme->reg->timestamp = CTime;
00617 
00618     addNick(tmp);
00619     delNick(changeme);
00620     if (isAKilled(tmp->nick, tmp->user, tmp->host)) {
00621         sSend(":%s KILL %s :%s!%s (AKilled user)", services[1].name,
00622               tmp->nick, services[1].host, services[1].name);
00623         remUser(to, 1);
00624         addGhost(to);
00625         return;
00626     }
00627 
00628         /* Try to prevent race */
00629     if (isGhost(tmp->nick)) {
00630         sSend(":%s KILL %s :%s!%s (Nickname currently blocked for NickServ enforcer).", services[1].name, tmp->nick, services[1].host, services[1].name);
00631         /* delGhost(tmp->nick); */
00632         addGhost(tmp->nick);
00633         remUser(to, 1);
00634         return;
00635     }
00636 
00637     tmp->reg = getRegNickData(to);
00638 
00639     if (tmp->reg != NULL) {
00640         if (tmp->reg->flags & NBANISH) {
00641             sSend
00642                 (":%s 433 %s :Banished nickname - You have 10 seconds to change your nick.",
00643                  myname, tmp->nick);
00644             sprintf(tmp1, "%s@@%i", to, 0);
00645             timer(10, killide, strdup(tmp1));
00646         }
00647 
00648         if (tmp->id.timestamp && tmp->id.nick
00649             && tmp->id.timestamp > tmp->reg->timereg
00650             && tmp->id.idnum == tmp->reg->regnum
00651             && !strcasecmp(tmp->id.nick, tmp->nick)) {
00652             sSend(":%s NOTICE %s :You have already identified for access.",
00653                   NickServ, tmp->nick);
00654             clearIdentify(tmp);
00655             tmp->caccess = 3;
00656             NickSeeUser(tmp, tmp->reg, 3, 1);
00657 
00658             if (ts[0] == ':')
00659                 ts++;
00660             tmp->reg->timestamp = (time_t) atol(ts);
00661             return;
00662         }
00663         /* Users may case change their nicks without nagging [Echo] */
00664         else if (!strcasecmp(tmp->nick, changeme->nick))
00665             tmp->caccess = changeme->caccess;
00666         else if (!checkAccess(tmp->user, tmp->host, tmp->reg)) {
00667             tmp->caccess = 0;
00668             annoyNickThief(tmp);
00669         } else {
00670             tmp->caccess = 2;
00671 
00672             NickSeeUser(tmp, tmp->reg, 2, 1);
00673             if (ts[0] == ':')
00674                 ts++;
00675             tmp->reg->timestamp = (time_t) atol(ts);
00676         }
00677     }
00678 }
00679 
00695 void setMode(char *nick, char *mode)
00696 {
00697     UserList *changeme;
00698     RegNickList *regn;
00699     int i, c = 0;
00700 
00701     changeme = getNickData(nick);
00702 
00703     dlogEntry("Changing umodes for \"%s\" (%p) to \"%s\" (%p)", changeme,
00704               changeme, mode, mode);
00705 
00706     if (changeme == NULL) {
00707         nDesynch(nick, "UMODE");
00708         return;
00709     }
00710 
00711     mode++;                     /* We don't need to bother with the : */
00712 
00713     for (i = 0; mode[i] != 0; i++) {
00714         switch (tolower(mode[i])) {
00715         case '-':
00716             c = 0;
00717             break;
00718         case '+':
00719             c = 1;
00720             break;
00721         case 'h':
00722             if (c == 1)
00723                 changeme->oflags |= NISHELPOP;
00724             else
00725                 changeme->oflags &= ~NISHELPOP;
00726             break;
00727         case 'm':
00728             if (c == 1) {
00729                 changeme->oflags |= NOISMASK;
00730                 if ((regn = getRegNickData(changeme->nick))
00731                     && isRecognized(changeme, regn))
00732                     regn->flags |= NDBISMASK;
00733             } else {
00734                 changeme->oflags &= ~NOISMASK;
00735                 if ((regn = getRegNickData(changeme->nick))
00736                     && isIdentified(changeme, regn))
00737                     regn->flags &= ~NDBISMASK;
00738             }
00739             break;
00740         case 'o':
00741             if (c == 1) {
00742                 changeme->oflags |= NISOPER;
00743                 changeme->oflags &= ~NISAHURT;
00744             } else
00745                 changeme->oflags &= ~NISOPER;
00746             break;
00747         }
00748     }
00749 
00750     mode--;
00751     return;
00752 }
00753 
00754 
00770 void setFlags(char *nick, int flag, char change)
00771 {
00772     UserList *bah;
00773     bah = getNickData(nick);
00774     if (bah == NULL) {
00775         nDesynch(nick, "SETFLAG(internal source)");
00776         return;
00777     }
00778 
00779     dlogEntry("Setting flags for \"%s\" (%p) - %i", nick, bah, flag);
00780 
00781     if (change == '+')
00782         bah->oflags |= flag;
00783     else
00784         bah->oflags &= ~flag;
00785 
00786 }
00787 
00798 void setIdentify(UserList * user, RegNickList * nick)
00799 {
00800     if (!user || !nick || !nick->nick)
00801         return;
00802     if (user->id.nick)
00803         FREE(user->id.nick);
00804     user->id.nick = (char *)oalloc(strlen(nick->nick) + 2);
00805     strcpy(user->id.nick, nick->nick);
00806 
00807     user->id.timestamp = MAX(user->timestamp, CTime);
00808     user->id.idnum = nick->regnum;
00809     return;
00810 }
00811 
00818 void clearIdentify(UserList * user)
00819 {
00820     if (!user)
00821         return;
00822     if (user->id.nick)
00823         FREE(user->id.nick);
00824     user->id.nick = NULL;
00825     user->id.timestamp = 0;
00826     user->id.idnum = RegId(0,0);
00827     return;
00828 }
00829 
00841 int isIdentified(UserList * user, RegNickList * nick)
00842 {
00843     if (!(user && nick) || (nick->flags & NVACATION)
00844         || (nick->flags & NFORCEXFER))
00845         return 0;
00846     if (user->reg != nick && user->id.nick && user->id.timestamp) {
00847         if (user->timestamp <= user->id.timestamp &&
00848             nick->timereg < user->id.timestamp &&
00849             nick->regnum == user->id.idnum &&
00850             !strcmp(user->id.nick, nick->nick)) return 1;
00851         return 0;
00852     }
00853     return (user->reg == nick && user->reg && (user->caccess > 2));
00854 }
00855 
00856 
00869 int isRecognized(UserList * user, RegNickList * nick)
00870 {
00871     if (!(user && nick) || (nick->flags & NVACATION))
00872         return 0;
00873     if (checkAccess(user->user, user->host, nick))
00874         return 1;
00875     if (!(user && nick) || user->reg != nick)
00876         return isIdentified(user, nick);
00877     return (user->reg && user->reg == nick && (user->caccess > 1));
00878 }
00879 
00886 int isOper(UserList * nick)
00887 {
00888     if (nick == NULL)
00889         return 0;
00890     else {
00891         if (nick->oflags & NISOPER)
00892             return 1;
00893         else
00894             return 0;
00895     }
00896 }
00897 
00911 int opFlagged(UserList * nick, flag_t flag)
00912 {
00913     int need_oper = (flag & OOPER);
00914     int need_user_override = (flag & OACC);
00915     extern int userOverriding(UserList *);
00916 
00917     if (nick == NULL)
00918         return 0;
00919     flag &= ~(OOPER);
00920     if (need_user_override && !userOverriding(nick))
00921         return FALSE;
00922     if (nick->reg == NULL || (flag && !isIdentified(nick, nick->reg)))
00923         return 0;
00924     if ((nick->reg->opflags & OROOT))
00925         if (!flag || ((flag & OPFLAG_ROOT) == flag))
00926             return (!need_oper || isOper(nick));
00927     if (!flag || ((nick->reg->opflags & flag) == flag))
00928         return (!need_oper || isOper(nick));
00929     return 0;
00930 }
00931 
00945 flag_t getOpFlags(UserList * nick)
00946 {
00947     flag_t flags = 0;
00948     extern int userOverriding(UserList *);
00949 
00950     if (nick == NULL)
00951         return 0;
00952     if (isOper(nick))
00953         flags |= OOPER;
00954     if (nick->reg == NULL || (!isIdentified(nick, nick->reg)))
00955         return flags;
00956     if (userOverriding(nick))
00957         flags |= OACC;
00958     if ((nick->reg->opflags & OROOT))
00959         return (flags | (OPFLAG_PLUS));
00960     return (flags | nick->reg->opflags);
00961 }
00962 
00963 
00965 int issRoot(UserList* nick) {
00966     int ofl;
00967 
00968     if (!nick || !isRoot(nick)) {
00969         return 0;
00970     }
00971 
00972     ofl = getOpFlags(nick);
00973     return ((ofl & 0x2)) ? 1 : 0;
00974 }
00975 
00982 int isRoot(UserList * nick)
00983 {
00984     if (nick == NULL)
00985         return 0;
00986     if (nick->reg == NULL)
00987         return 0;
00988 
00989     if (nick->reg->opflags & OROOT && isIdentified(nick, nick->reg))
00990         return isOper(nick);
00991     else
00992         return 0;
00993 }
00994 
01002 int isServop(UserList * nick)
01003 {
01004     if (nick == NULL)
01005         return 0;
01006     if (nick->reg == NULL)
01007         return 0;
01008 
01009     if ((nick->reg->opflags & OSERVOP || nick->reg->opflags & OROOT)
01010         && isIdentified(nick, nick->reg))
01011         return isOper(nick);
01012     else
01013         return 0;
01014 }
01015 
01016 #ifdef ENABLE_GRPOPS
01017 
01024 int isGRPop(UserList * nick)
01025 {
01026     if (nick == NULL)
01027         return 0;
01028     if (nick->reg == NULL)
01029         return 0;
01030 
01031     if ((nick->reg->opflags & OGRP) && isIdentified(nick, nick->reg))
01032         return isOper(nick);
01033     else
01034         return 0;
01035 }
01036 #endif
01037 
01046 int isHelpop(UserList * nick)
01047 {
01048     if (nick == NULL)
01049         return 0;
01050     if (nick->reg == NULL)
01051         return 0;
01052 
01053     if ((nick->oflags & NISHELPOP) && isIdentified(nick, nick->reg))
01054         return 1;
01055     else
01056         return 0;
01057 }
01058 
01066 int canAkill(UserList * nick)
01067 {
01068     if (nick == NULL)
01069         return 0;
01070     if (nick->reg == NULL)
01071         return 0;
01072 
01073     if (nick->reg->opflags & OAKILL && isIdentified(nick, nick->reg))
01074         return isOper(nick);
01075     else
01076         return 0;
01077 }
01078 
01079 
01094 void remUser(char *nick, int ignoreDesync)
01095 {
01096     UserList *killme;
01097 
01098     killme = getNickData(nick);
01099 
01100     if (killme == NULL) {
01101         if (!ignoreDesync)
01102             nDesynch(nick, "QUIT");
01103         return;
01104     }
01105 
01106     dlogEntry("Removing user \"%s\" (%p)", nick, killme);
01107     remFromAllChans(killme);
01108     delClone(killme->user, killme->host);
01109 
01110     if (killme->reg && isIdentified(killme, killme->reg)) {
01111         cleanMemos(killme);
01112         killme->reg->timestamp = CTime;
01113     }
01114 
01115     delNick(killme);
01116 }
01117 
01118 
01128 void addNick(UserList * newnick)
01129 {
01130     HashKeyVal hashEnt;
01131 
01132     dlogEntry("Adding nick \"%s\" (%p)", newnick->nick, newnick);
01133 
01134     hashEnt = getHashKey(newnick->nick) % NICKHASHSIZE;
01135     dlogEntry("Added nick \"%s\" with hash entry %i",
01136               newnick->nick, hashEnt);
01137     LIST_ENTRY_INIT(newnick, ul_lst);
01138     LIST_INSERT_HEAD(&UserHash[hashEnt], newnick, ul_lst);
01139     totalusers++;
01140 }
01141 
01153 void addRegNick(RegNickList * newnick)
01154 {
01155     RegNickList *tmp;
01156     RegNickIdMap *mapPtr, *mapPtrIter, *mapPtrIterNext;
01157     HashKeyVal hashEnt;
01158 
01159     /*
01160      * If this nick is already registered, don't do a thing.
01161      */
01162     if ((tmp = getRegNickData(newnick->nick))) {
01163         logDump(corelog, "addRegNick(%p) : %s already exists",
01164                 newnick, newnick->nick);
01165         assert(tmp == NULL);
01166 
01167         abort();
01168         freeRegNickListRec(newnick);
01169         return;
01170     }
01171 
01172     /*
01173      * hash the nick, and insert it into the correct linked list.
01174      */
01175     hashEnt = getHashKey(newnick->nick) % NICKHASHSIZE;
01176     LIST_ENTRY_INIT(newnick, rn_lst);
01177     LIST_INSERT_HEAD(&RegNickHash[hashEnt], newnick, rn_lst);
01178 
01179 
01180     mapPtr = (RegNickIdMap *)oalloc(sizeof(RegNickIdMap));
01181     mapPtr->nick = newnick;
01182     mapPtr->id   = newnick->regnum;
01183 
01184     hashEnt = newnick->regnum.getHashKey() % IDHASHSIZE;
01185     LIST_ENTRY_INIT(mapPtr, id_lst);
01186     if (!LIST_FIRST(&RegNickIdHash[hashEnt]))
01187         LIST_INSERT_HEAD(&RegNickIdHash[hashEnt], mapPtr, id_lst);
01188     else {
01189         for(mapPtrIter = LIST_FIRST(&RegNickIdHash[hashEnt]);
01190             mapPtrIter;
01191             mapPtrIter = mapPtrIterNext)
01192         {
01193             mapPtrIterNext = LIST_NEXT(mapPtrIter, id_lst);
01194 
01195             if ((mapPtr->id) > (mapPtrIter->id)) {
01196                 if (mapPtrIterNext)
01197                     continue;
01198                 LIST_INSERT_AFTER(mapPtrIter, mapPtr, id_lst);
01199                 break;
01200             }
01201             else {
01202                 LIST_INSERT_BEFORE(mapPtrIter, mapPtr, id_lst);
01203                 break;
01204             }
01205         }
01206 
01207     }
01208 }
01209 
01210 
01221 void delNick(UserList * killme)
01222 {
01223     LIST_REMOVE(killme, ul_lst);
01224     clearIdentify(killme);
01225 
01226     freeUserListRec(killme);
01227     flush_ad(killme);
01228     totalusers--;
01229 }
01230 
01242 void delRegNick(RegNickList * killme)
01243 {
01244     MemoList *memos;
01245     MemoList *memos_next;
01246     RegNickList *to;
01247     RegNickIdMap *mapPtr;
01248 
01249     LIST_REMOVE(killme, rn_lst);
01250 
01251     mapPtr = killme->regnum.getIdMap();
01252     if (mapPtr)
01253     {
01254         LIST_REMOVE(mapPtr, id_lst);
01255 
01256         FREE(mapPtr);
01257     }
01258 
01259     delOpData(killme);
01260     if (killme->memos)
01261     {
01262         memos = LIST_FIRST(&killme->memos->mb_sent);
01263         while (memos != NULL) {
01264             memos_next = LIST_NEXT(memos, ml_sent);
01265             to = memos->realto;
01266             if (to == NULL)
01267                 return;
01268             LIST_REMOVE(memos, ml_sent);
01269             delMemo(to->memos, memos);
01270             memos = memos_next;
01271         }
01272     }
01273     freeRegNickListRec(killme);
01274 }
01275 
01287 UserList *getNickData(char *nick)
01288 {
01289     HashKeyVal hashEnt;
01290     UserList *tmpnick;
01291 
01292     hashEnt = getHashKey(nick) % NICKHASHSIZE;
01293     for (tmpnick = LIST_FIRST(&UserHash[hashEnt]); tmpnick != NULL;
01294          tmpnick = LIST_NEXT(tmpnick, ul_lst)) {
01295         if (!strcasecmp(tmpnick->nick, nick))
01296             return tmpnick;
01297     }
01298 
01299     return NULL;
01300 }
01301 
01311 RegNickList *getRegNickData(const char *nick)
01312 {
01313     HashKeyVal hashEnt;
01314     RegNickList *tmpnick;
01315     int l;
01316 
01317     if (nick == NULL || (l = strlen(nick)) > NICKLEN || l == 0)
01318         return NULL;
01319 
01320     hashEnt = getHashKey(nick) % NICKHASHSIZE;
01321     for (tmpnick = LIST_FIRST(&RegNickHash[hashEnt]); tmpnick != NULL;
01322          tmpnick = LIST_NEXT(tmpnick, rn_lst))
01323         if (strcasecmp(tmpnick->nick, nick) == 0)
01324             return tmpnick;
01325 
01326     return NULL;
01327 }
01328 
01342 int checkAccess(char *user, char *host, RegNickList * nick)
01343 {
01344     nAccessList *tmp;
01345     char theirmask[HOSTLEN + USERLEN + 3];
01346 
01347     if (nick == NULL || user == NULL || host == NULL)
01348         return 0;
01349 
01350     sprintf(theirmask, "%.*s@%.*s", USERLEN, user, HOSTLEN, host);
01351 
01352     /* otherwise, check their access masks */
01353     for (tmp = LIST_FIRST(&nick->acl); tmp; tmp = LIST_NEXT(tmp, al_lst))
01354         if (!match(tmp->mask, theirmask))
01355             return 1;           /* match */
01356     return 0;                   /* NoMatch */
01357 }
01358 
01375 void sendToNickServ(UserList * tmp, char **args, int numargs)
01376 {
01377     char *from = tmp->nick;
01378     interp::parser * cmd;
01379 
01380     tmp = getNickData(from);
01381     if (tmp == NULL) {
01382         nDesynch(from, "PRIVMSG");
01383         return;
01384     }
01385 
01386     cmd = new interp::parser(NickServ, getOpFlags(tmp),
01387                              nickserv_commands, args[0]);
01388     if (!cmd)
01389         return;
01390 
01391     switch (cmd->run(tmp, args, numargs)) {
01392     default:
01393         break;
01394     case RET_FAIL:
01395         sSend(":%s NOTICE %s :Unknown command %s.\r\n"
01396               ":%s NOTICE %s :Please try /msg %s HELP",
01397               NickServ, from, args[0], NickServ, from, NickServ);
01398         break;
01399     case RET_OK_DB:
01400         sSend(":%s NOTICE %s :Next database synch(save) in %ld minutes.",
01401               NickServ, tmp->nick, ((nextNsync - CTime) / 60));
01402         break;
01403     }
01404 
01405     delete cmd;
01406 }
01407 
01408 /* && 
01409             !Valid_md5key(args[2], nick->auth, tmp->passwd,
01410             NickGetEnc(tmp))) {*/
01411 
01412 
01421 char *regnick_ugethost(UserList * user, RegNickList * target, int sM)
01422 {
01423     UserList *online;
01424     static char rep[NICKLEN + USERLEN + HOSTLEN + 275];
01425 
01426     if (!user || !target || (strlen(target->host) > (sizeof(rep) - 200)))
01427         return "<ERROR>";
01428 
01429     if ((online = getNickData(target->nick))) {
01430         if (isRecognized(online, target)) {
01431             if (!(online->oflags & NOISMASK))
01432                 return strcpy(rep, target->host);
01433             else if (!(user->oflags & NISOPER)) {
01434                 strncpyzt(rep, genHostMask(target->host), sizeof(rep));
01435                 return rep;
01436             } else if ((user->oflags & NISOPER)) {
01437                 strncpyzt(rep, target->host, sizeof(rep) - 11);
01438                 if (sM)
01439                     sprintf(rep + strlen(rep), " (\2masked\2)");
01440                 return rep;
01441             }
01442         }
01443     }
01444 
01445     if (!(target->flags & NDBISMASK))
01446         return strcpy(rep, target->host);
01447     if (!(user->oflags & NISOPER)) {
01448         strncpyzt(rep, genHostMask(target->host), sizeof(rep));
01449         return rep;
01450     } else {
01451         strcpy(rep, target->host);
01452         if (sM)
01453             sprintf(rep + strlen(rep), " (\2masked\2)");
01454         return rep;
01455     }
01456     return ("<ERROR>@<ERROR>");
01457 }
01458 
01471 void addAccessMask(char *mask, UserList * nick)
01472 {
01473     if (!isIdentified(nick, nick->reg)) {
01474         sSend(":%s NOTICE %s :You must identify to use ACCESS ADD",
01475               NickServ, nick->nick);
01476         return;
01477     }
01478 
01479     if (USERLEN + HOSTLEN + 3 < strlen(mask)) {
01480         sSend(":%s GLOBOPS :%s tried to add a HUGE access mask", NickServ,
01481               nick->nick);
01482         sSend(":%s NOTICE %s :That access mask is WAY too long", NickServ,
01483               nick->nick);
01484         return;
01485     }
01486 
01487     if (nick->reg->amasks >= AccessLimit) {
01488         sSend
01489             (":%s NOTICE %s :You have reached the limit of access masks, you cannot add any more",
01490              NickServ, nick->nick);
01491         sSend(":%s GLOBOPS :%s attempts to add too many access items.",
01492              NickServ, nick->nick);
01493         return;
01494     }
01495 
01496     if (addAccItem(nick->reg, mask) == 0)
01497         sSend
01498             (":%s NOTICE %s :%s was \002not\002 added to your access list, it is an improper mask or already present.",
01499              NickServ, nick->nick, mask);
01500     else {
01501         sSend(":%s NOTICE %s :%s is added to your access list",
01502               NickServ, nick->nick, mask);
01503     }
01504 }
01505 
01518 void delAccessMask(char *mask, UserList * nick)
01519 {
01520     nAccessList *acl;
01521     char deleted[71];
01522 
01523     if (!isIdentified(nick, nick->reg)) {
01524         sSend(":%s NOTICE %s :You must identify to use ACCESS DEL",
01525               NickServ, nick->nick);
01526         return;
01527     }
01528 
01529     if (LIST_FIRST(&nick->reg->acl) == NULL)
01530         return;
01531 
01532     if (*mask == '-') {
01533         for (acl = LIST_FIRST(&nick->reg->acl); acl != NULL;
01534              acl = LIST_NEXT(acl, al_lst))
01535             delAccItem(nick->reg, acl->mask, deleted);
01536 
01537         sSend(":%s NOTICE %s :Your access list has been cleared",
01538               NickServ, nick->nick);
01539         nick->reg->amasks = 0;
01540 
01541         return;
01542     }
01543 
01544     if (delAccItem(nick->reg, mask, deleted)) {
01545         sSend(":%s NOTICE %s :The mask %s has been deleted"
01546               " from your access list", NickServ, nick->nick, deleted);
01547         nick->reg->amasks--;
01548     } else if (strchr(mask, '@') == NULL)
01549         sSend(":%s NOTICE %s :Access list entry #%s was not found",
01550               NickServ, nick->nick, mask);
01551     else
01552         sSend(":%s NOTICE %s :%s was not in your access list",
01553               NickServ, nick->nick, mask);
01554 }
01555 
01563 void complainAboutEmail(UserList * nick)
01564 {
01565     if (!nick->reg || (nick->reg->email[0] &&
01566                        (strncasecmp(nick->reg->email, "(none)", 6))
01567                        || index(nick->reg->email, ' ')))
01568         return;
01569 
01570     sSend(":%s NOTICE %s :***** NOTICE *****", NickServ, nick->nick);
01571     sSend(":%s NOTICE %s :You have not specified an e-mail address.",
01572           NickServ, nick->nick);
01573     sSend
01574         (":%s NOTICE %s :Should you forget or lose your NickServ password, the operators will most likely be unable to assist you,",
01575          NickServ, nick->nick);
01576     sSend(":%s NOTICE %s :unless you specify one.", NickServ, nick->nick);
01577     sSend
01578         (":%s NOTICE %s :To set an e-mail address and eliminate this message:",
01579          NickServ, nick->nick);
01580     sSend
01581         (":%s NOTICE %s :      type \2/msg nickserv set address YOUREMAIL\2 ",
01582          NickServ, nick->nick);
01583     sSend
01584         (":%s NOTICE %s :Once set, NickServ will NOT divulge your address to other users unless you explicitly tell it to.",
01585          NickServ, nick->nick);
01586     sSend(":%s NOTICE %s :", NickServ, nick->nick);
01587     sSend
01588         (":%s NOTICE %s :To keep no e-mail address but eliminate this message:",
01589          NickServ, nick->nick);
01590     sSend(":%s NOTICE %s :      type \2/msg nickserv set address NONE",
01591           NickServ, nick->nick);
01592     sSend(":%s NOTICE %s :", NickServ, nick->nick);
01593     sSend
01594         (":%s NOTICE %s :Type \2/join #help\2 if you have any questions regarding this.",
01595          NickServ, nick->nick);
01596     sSend(":%s NOTICE %s :***** NOTICE *****", NickServ, nick->nick);
01597     sSend
01598         (":%s PRIVMSG %s :You have not yet set an e-mail address or indicated your desire to send none: please see the notice from services (it may be in a status window).",
01599          NickServ, nick->nick);
01600 }
01601 
01612 void annoyNickThief(UserList * nick)
01613 {
01614     char buffer[NICKLEN+HOSTLEN+41];
01615 
01616     if (nick->reg->flags & NKILL) {
01617         sSend(":%s NOTICE %s :This nick belongs to another user."
01618               "  Please change nicks or it will be forcefully changed"
01619               " in %i seconds.", NickServ, nick->nick, nick->reg->idtime);
01620         sSend(":%s NOTICE %s :If this is your nick please try:"
01621               " /msg %s ID password", NickServ, nick->nick, NickServ);
01622 
01623         /* Start a timer to killide the nick using their ID time */
01624         if (nick->reg->idtime > NICKWARNINT) {
01625             if ((nick->reg->idtime - NICKWARNINT) < NICKWARNINT)
01626                 sSend(":%s 433 %s %s :Belongs to another user",
01627                       myname, nick->nick, nick->nick);
01628             sprintf(buffer, "%s@%s@%i", nick->nick, nick->host,
01629                     nick->reg->idtime);
01630             timer(NICKWARNINT, killide, strdup(buffer));
01631         } else {
01632             sSend(":%s 433 %s %s :Belongs to another user",
01633                   myname, nick->nick, nick->nick);
01634             sprintf(buffer, "%s@%s@%i", nick->nick, nick->host, 0);
01635             timer(nick->reg->idtime, killide, strdup(buffer));
01636         }
01637         return;
01638     }
01639 
01640     sSend(":%s NOTICE %s :This nick belongs to another user."
01641           "  Please change nicks", NickServ, nick->nick);
01642     sSend(":%s NOTICE %s :If this is your nick please try:"
01643           " /msg %s ID password", NickServ, nick->nick, NickServ);
01644     return;
01645 }
01646 
01647 
01648 void guest_cnick(UserList* ul)
01649 {
01650 #ifndef CNICK_UNSUPPORTED
01651     unsigned int j = 0;
01652     extern int dice(int, int);
01653     char forcenick[NICKLEN];
01654     const char* nick;
01655 
01657 #   define CNICK_FMT ":%s CNICK %s %s %ld"
01658         
01659     if (!ul)
01660         return;
01661     nick = ul->nick;
01662 
01663     do {
01664         snprintf(forcenick, NICKLEN, "%s%lX%X",
01665              cnick_prefixes[(top_cnick + j) % NUM_CNICKS],
01666              (++top_cnick) / NUM_CNICKS, dice(3, 200) + 1);
01667     } while ((j++ < NUM_CNICKS && getNickData(forcenick))
01668                      || (getNickData(forcenick) && ++top_cnick));   
01669 
01670     sSend(":%s NOTICE %s :Your nickname is now being "
01671           "changed to \2%s\2.", NickServ, nick, forcenick);
01672     sSend(CNICK_FMT, myname, nick, forcenick, CTime);
01673     if (ul)
01674         ul->oflags |= NCNICK;
01675 #endif               
01676 }
01677 
01678 void enforce_nickname (char* nick)
01679 {
01680     UserList* ul = nick ? getNickData(nick) : 0;
01681 
01682     if (ul == 0) {
01683         return;
01684     }
01685 
01686 #ifndef CNICK_UNSUPPORTED
01687     guest_cnick(ul);
01688 #else
01689     sSend(":%s KILL %s :%s!%s (Nick protection enforced)",
01690           NickServ, nick, services[1].host, services[1].name);
01691     remUser(nick, 1);
01692     addGhost(nick);
01693     timer(120, delTimedGhost, strdup(nick));
01694 #endif
01695 }
01696 
01717 void killide(char *info)
01718 {
01719     char tmp[NICKLEN + HOSTLEN + 10];
01720     UserList *check;
01721     RegNickList *regnick;
01722     char *nick;
01723     char *host;
01724     char *time;
01725 
01726     nick = strtok(info, "@");
01727     host = strtok(NULL, "@");
01728     time = strtok(NULL, "\0");
01729 
01730     unsigned int left = 0;      /* Amount of time remaining (in seconds) */
01731 
01732     if (nick == NULL) {
01733         return;
01734     }
01735 
01736     /*
01737      * If they don't exist, or they have access to the nick, just clean
01738      * up and return.
01739      */
01740     check = getNickData(nick);
01741     regnick = getRegNickData(nick);
01742 
01743     if (check == NULL) {
01744         FREE(info);
01745         return;
01746     } else if (isIdentified(check, regnick)) {
01747         FREE(info);
01748         return;
01749     } else if (host != NULL) {
01750         if (strcmp(check->host, host)) {
01751             FREE(info);
01752             return;
01753         }
01754     } else if (time == NULL) {
01755         FREE(info);
01756         return;
01757     }
01758 
01759     left = atoi(time);
01760 
01761     if (left == 0) {            /* All warnings have expired.  Change nick now. */
01762         if (getNickData(nick)) {
01763             enforce_nickname( nick );
01764         }       
01765     } else {                    /* There are warning(s) left, Warn the user and reset timer */
01766         if (getNickData(nick)) {
01767             if (left >= NICKWARNINT) {
01768                 left -= NICKWARNINT;
01769             } else {
01770                 /* If the code fails, reset the time left to a
01771                  * sane value and log. */
01772                 left = NICKWARNINT;
01773                 logDump(corelog, "Time left sanity check failed in "
01774                           "killide().  Resetting to %i.", NICKWARNINT);
01775             }
01776 
01777             if (left >= NICKWARNINT) {
01778                 sSend(":%s NOTICE %s :You have %i seconds to "
01779                       "change your nick, or %s will be forced "
01780                       "to change it for you.", NickServ, nick,
01781                       left, NickServ);
01782                 if ((left - NICKWARNINT) < NICKWARNINT)
01783                     sSend(":%s 433 %s %s :Belongs to "
01784                           "another user", myname, nick, nick);
01785                 sprintf(tmp, "%s@%s@%i", nick, host, left);
01786                 timer(NICKWARNINT, killide, strdup(tmp));
01787             } else {
01788                 sprintf(tmp, "%s@%s@%i", nick, host, 0);
01789                 timer(left, killide, strdup(tmp));
01790             }
01791         }
01792         FREE(info);
01793     }
01794 }
01795 
01810 void addGhost(char *ghost)
01811 {
01812     GhostList *newghost = (GhostList *)0; 
01813     char host[HOSTLEN];
01814     
01815 
01816     if (ghost) {
01817         for(newghost = firstGhost; newghost; newghost = newghost->next)
01818         {
01819             if (!strcasecmp(ghost, newghost->ghost)) {
01820                 break;
01821             }
01822         }
01823     }
01824 
01825     if (!newghost) {
01826         newghost = (GhostList *) oalloc(sizeof(GhostList));
01827 
01828         strncpyzt(newghost->ghost, ghost, NICKLEN);
01829 
01830         if (firstGhost == NULL) {
01831             firstGhost = newghost;
01832             newghost->previous = NULL;
01833         } else {
01834             lastGhost->next = newghost;
01835             newghost->previous = lastGhost;
01836         }
01837 
01838         lastGhost = newghost;
01839         newghost->next = NULL;
01840 
01841         totalusers++;
01842         totalghosts++;
01843     }
01844 
01845     snprintf(host, sizeof(host), "nicks.%s", NETWORK);
01846     addUser(ghost, "owned", host, "Nick Enforcement", "i");
01847 }
01848 
01858 void delGhost(char *ghost)
01859 {
01860     GhostList *killme;
01861 
01862 
01863     sSend(":%s QUIT :Ahhh, they finally let me off work!", ghost);
01864 
01865     killme = getGhost(ghost);
01866 
01867     if (killme == NULL)
01868         return;
01869 
01870     if (killme->previous)
01871         killme->previous->next = killme->next;
01872     else
01873         firstGhost = killme->next;
01874     if (killme->next)
01875         killme->next->previous = killme->previous;
01876     else
01877         lastGhost = killme->previous;
01878 
01879     FREE(killme);
01880     totalghosts--;
01881     totalusers--;
01882 
01883     return;
01884 }
01885 
01896 void delTimedGhost(char *ghost)
01897 {
01898     delGhost(ghost);
01899     FREE(ghost);
01900 }
01901 
01906 GhostList *getGhost(char *ghost)
01907 {
01908     GhostList *tmp;
01909 
01910     for (tmp = firstGhost; tmp; tmp = tmp->next) {
01911         if (strcasecmp(tmp->ghost, ghost) == 0)
01912             return tmp;
01913     }
01914     return NULL;
01915 }
01916 
01924 int isGhost(char *ghost)
01925 {
01926     if (getGhost(ghost))
01927         return 1;
01928     else
01929         return 0;
01930 }
01931 
01932 // Services Flood Protection ////////////////////////////////////////////
01933 
01934 RateInfo::RateInfo() :
01935   lastEventTime(0),  rateFloodValue(0),  numOfEvents(0),
01936   warningsSent(0)
01937 {
01938 
01939 }
01940 
01941 void RateInfo::Event(int weightOfEvent, time_t tNow)
01942 {
01943     // If the last message was [ period1 length ] or more seconds ago, then
01944     // cut in half
01945     if ((tNow - lastEventTime) >= FLOOD_DET_HALF_PERIOD)
01946         rateFloodValue >>= 1;
01947 
01948     // If more than [ period2 length ] seconds ago, then flood level
01949         // restarts, else: the flood weight is added
01950 
01951     if ((tNow - lastEventTime) <= FLOOD_DET_Z_PERIOD)
01952         rateFloodValue += weightOfEvent;
01953     else
01954         rateFloodValue = weightOfEvent;
01955 
01956     lastEventTime = tNow;
01957     if (numOfEvents < INT_MAX)
01958         numOfEvents++;
01959 }
01960 
01961 void RateInfo::Warn() {
01962     if (warningsSent < UCHAR_MAX)
01963         warningsSent++;
01964 }
01965 
01966 int RateInfo::Warned() {
01967     return (int) warningsSent;
01968 }
01969 
01970 int RateInfo::GetLev() {
01971     return rateFloodValue;
01972 }
01973 
01975 int BadPwNick(UserList *sender, RegNickList *target)
01976 {
01977     if (sender == NULL || target == NULL)
01978         return 0;
01979 
01980     if (sender->badpws < UCHAR_MAX)
01981         sender->badpws++;
01982 
01983     if (target->badpws < UCHAR_MAX)
01984         target->badpws++;
01985 
01986     if ((sender->badpws > NPW_TH_SENDER_1 && target->badpws > NPW_TH_TARGET_1) ||
01987             (sender->badpws > NPW_TH_SENDER_2 && target->badpws > NPW_TH_TARGET_2) ||
01988             (sender->badpws > NPW_TH_SENDER_3 && target->badpws > NPW_TH_TARGET_3)) 
01989         {
01990         sSend(":%s GLOBOPS :Possible password guess attempt %s!%s@%s (%u) -> %s (%u)",
01991             NickServ, sender->nick, sender->user, sender->host, (u_int)sender->badpws,
01992             target->nick, (u_int)target->badpws
01993         );
01994 
01995         if (addFlood(sender, FLOODVAL_BADPW))
01996             return 1;
01997     }
01998 
01999     return 0;
02000 }
02001 
02003 int GoodPwNick(UserList *sender, RegNickList *target)
02004 {
02005     char timeJunk[80];
02006 
02007     if (sender == NULL || target == NULL)
02008         return 0;
02009 
02010     if (target->badpws > 0)
02011     {
02012         sSend(":%s NOTICE %s :%d failed password attempt(s) for %s since last access",
02013              NickServ, sender->nick, target->badpws, target->nick);
02014         if (strftime(timeJunk, 80, "%a %Y-%b-%d %T %Z", localtime(&target->timestamp)) > 0) {
02015             sSend(":%s NOTICE %s :%s seen %s from %s@%s.",
02016                  NickServ, sender->nick, target->nick, timeJunk, target->user, regnick_ugethost(sender, target));
02017         }
02018 
02019         target->badpws = 0;
02020     }
02021 
02022     return 0;
02023 }
02024 
02051 int addFlood(UserList * tmp, int addtoflood)
02052 {
02053     int fIsIgnored = 0;
02054     long timenow = time(NULL);
02055 
02056     if (tmp == NULL)
02057         return 0;
02058 
02059     if (isRoot(tmp) == 1) {
02060         return 0;
02061     }
02062 
02063     if (tmp->nick && tmp->user && tmp->host)
02064         fIsIgnored = isIgnored(tmp->nick, tmp->user, tmp->host);
02065 
02066     tmp->floodlevel.Event(addtoflood, timenow);
02067 
02068     if (tmp->floodlevel.Warned() && tmp->floodlevel.GetLev() >= MAXFLOODLEVEL) {
02069         char user[USERLEN], host[HOSTLEN],
02070              theirmask[USERLEN + HOSTLEN + 3];
02071         char tmpstr[NICKLEN + USERLEN + HOSTLEN + 4];
02072         sSend
02073             (":%s KILL %s :%s!%s (Flooding services is not permitted [You are now on services ignore])",
02074              OperServ, tmp->nick, services[0].host, OperServ);
02075         if (!fIsIgnored)
02076             sSend
02077                 (":%s GLOBOPS :\002Severe Flooding\002: %s!%s@%s  [User killed] (Flood: %i/%i)",
02078                  myname, tmp->nick, tmp->user, tmp->host, tmp->floodlevel.GetLev(),
02079                  MAXFLOODLEVEL);
02080 
02081         strncpyzt(user, tmp->user, USERLEN);
02082         strncpyzt(host, tmp->host, HOSTLEN);
02083 
02084         mask(user, host, 0, theirmask);
02085         sprintf(tmpstr, "*!%.*s", USERLEN + HOSTLEN + 4, theirmask);
02086         if (!isIgnored(tmp->nick, tmp->user, tmp->host))
02087             addakill((10 * 3600), tmpstr, OperServ, A_IGNORE,
02088                      "Flooding Services");
02089         remUser(tmp->nick, 1);
02090 
02091         return 1;
02092     }
02093 
02094     else if (tmp->floodlevel.GetLev() >= (.75 * MAXFLOODLEVEL) && !fIsIgnored) 
02095     {
02096         sSend(":%s GLOBOPS :\002Flooding\002: %s!%s@%s (Flood: %i/%i)",
02097               myname, tmp->nick, tmp->user, tmp->host, tmp->floodlevel.GetLev(),
02098               MAXFLOODLEVEL);
02099         sSend(":%s NOTICE %s :Flooding is not good for your health or mine, "
02100               "stop now before you are removed from the network and placed "
02101               "on services ignore (Floodlevel %i/%i)", NickServ, tmp->nick,
02102               tmp->floodlevel.GetLev(), MAXFLOODLEVEL);
02103         tmp->floodlevel.Warn();
02104 
02105         return 1;
02106     }
02107     return 0;
02108 }
02109 
02119 /* ARGSUSED0 */
02120 void expireNicks(char *dummy)
02121 {
02122     time_t timestart, timeend;
02123     RegNickList *tmp;
02124     RegNickList *next;
02125     char backup[30];
02126     char cmd[500];         
02127     int i = 0, bucket = 0;
02128 
02129     mostnicks = 0;
02130     timestart = time(NULL);
02131 
02132     /*
02133      * back up the nickserv database
02134      */
02135     strftime(backup, 30, "nickserv.db%d%m%Y", localtime(&timestart));
02136     sprintf(cmd, "cp nickserv/nickserv.db nickserv/backups/%s", backup);
02137     system(cmd);
02138 
02139     /*
02140      * back up memoserv database as well, as memos are tied to nicks
02141      */
02142     strftime(backup, 30, "memoserv.db%d%m%Y", localtime(&timestart));
02143     sprintf(cmd, "cp memoserv/memoserv.db memoserv/backups/%s", backup);
02144     system(cmd);
02145 
02146 
02147     /*
02148      * Run through all hash buckets, checking nick status and if
02149      * appropriate, last used times
02150      */
02151     for (bucket = 0; bucket < NICKHASHSIZE; bucket++) {
02152         tmp = LIST_FIRST(&RegNickHash[bucket]);
02153 
02154         while (tmp != NULL) {
02155             next = LIST_NEXT(tmp, rn_lst);
02156 
02157             if (getNickData(tmp->nick) != NULL)
02158                 tmp->timestamp = CTime;
02159 
02160             if (!isIdentified(getNickData(tmp->nick), tmp)) {
02161 
02162                 if ((tmp->flags & (NHOLD | NBANISH)) != 0) {
02163                     ;
02164                 } else if (tmp->flags & NVACATION) {
02165                     if ((timestart - tmp->timestamp)
02166                         >= (3 * NICKDROPTIME)) {
02167                         nicklog->log(NULL, NSE_EXPIRE, tmp->nick, 0,
02168                                      "%ld %ld %ld vacation", timestart,
02169                                      tmp->timestamp,
02170                                      timestart - tmp->timestamp);
02171                         delRegNick(tmp);
02172                         i++;
02173                     }
02174                 } else if ((timestart - tmp->timestamp) >= NICKDROPTIME) {
02175                     nicklog->log(NULL, NSE_EXPIRE, tmp->nick, 0,
02176                                  "%ld %ld %ld", timestart, tmp->timestamp,
02177                                  timestart - tmp->timestamp);
02178                     delRegNick(tmp);
02179                     i++;
02180                 }
02181             }
02182 
02183             tmp = next;
02184             mostnicks++;
02185         }
02186     }
02187 
02188     timeend = time(NULL);
02189     sSend(":%s GLOBOPS :NickServ EXPIRE(%i/%lu) %lu seconds",
02190           NickServ, i, mostnicks, (timeend - timestart));
02191 
02192     timer(2 * 3600, (void (*)(char *))expireNicks, NULL);
02193 }
02194 
02205 int addAccItem(RegNickList * nick, char *mask)
02206 {
02207     nAccessList *acl;
02208 
02209     if (!nick)
02210         return 0;
02211 
02212     if (!strcmp(mask, "*@*") || !strcmp(mask, "*@*.*") ||
02213         !match(mask, "..@...com") ||
02214         !match(mask, "..@...edu") ||
02215         !match(mask, "..@...org") ||
02216         !match(mask, "..@...net") ||
02217         !match(mask, "..@...info") ||
02218         !match(mask, "..@...co.uk") ||
02219         !match(mask, "..@...br") ||
02220         index(mask, '!') || !index(mask, '@'))
02221         return 0;
02222 
02223     for (acl = LIST_FIRST(&nick->acl); acl != NULL;
02224          acl = LIST_NEXT(acl, al_lst)) if (!strcasecmp(mask, acl->mask))
02225             return 0;
02226 
02227     acl = (nAccessList *) oalloc(sizeof(nAccessList));
02228     strncpyzt(acl->mask, mask, 70);
02229 
02230     LIST_INSERT_HEAD(&(nick->acl), acl, al_lst);
02231 
02232     nick->amasks++;
02233 
02234     return 1;
02235 }
02236 
02253 int delAccItem(RegNickList * nick, char *mask, char *deletedmask)
02254 {
02255     nAccessList *acl;
02256     int found = 0;
02257     int x = 0;
02258     int idx;
02259 
02260     if (nick == NULL)
02261         return 0;
02262 
02263     x = atoi(mask);
02264     idx = 1;
02265 
02266     for (acl = LIST_FIRST(&nick->acl); acl != NULL;
02267          acl = LIST_NEXT(acl, al_lst)) {
02268         if (!strcasecmp(mask, acl->mask) || (idx++ == x)) {
02269             found = 1;
02270             break;
02271         }
02272     }
02273 
02274     if (found == 0)
02275         return 0;
02276 
02277     strncpyzt(deletedmask, acl->mask, 70);
02278 
02279     LIST_REMOVE(acl, al_lst);
02280 
02281     FREE(acl);
02282 
02283     return 1;
02284 }
02285 
02290 void syncNickData(time_t next)
02291 {
02292     nextNsync = next;
02293     saveNickData();
02294 }
02295 
02300 void syncMemoData(time_t next)
02301 {
02302     nextMsync = next;
02303     saveMemoData();
02304 }
02305 
02306 /* ARGSUSED1 */
02310 NCMD(ms_save)
02311 {
02312     char *from = nick->nick;
02313 
02314     if (isRoot(nick) == 0) {
02315         PutReply(MemoServ, nick, ERR_NOACCESS, 0, 0, 0);
02316         return RET_FAIL;
02317     }
02318 
02319 #ifdef GLOBOP_ON_SAVE
02320     sSend(":%s GLOBOPS :Saving database. (%s)", MemoServ, from);
02321 #else
02322     sSend(":%s PRIVMSG " LOGCHAN " :Saving database. (%s)", MemoServ,
02323           from);
02324 #endif
02325     saveMemoData();
02326     return RET_OK_DB;
02327 }
02328 
02333 void addOpData(RegNickList * nick)
02334 {
02335     OperList *oper;
02336 
02337     if (!nick || !nick->opflags)
02338         return;
02339     for (oper = firstOper; oper; oper = oper->next)
02340         if (oper->who == nick)
02341             return;
02342 
02343     if (!firstOper || (nick->opflags & OROOT)) {
02344         oper = (OperList *) oalloc(sizeof(OperList));
02345         oper->next = firstOper;
02346         firstOper = oper;
02347         oper->who = nick;
02348     } else {
02349         for (oper = firstOper; oper->next; oper = oper->next);
02350         oper->next = (OperList *) oalloc(sizeof(OperList));
02351         oper->next->who = nick;
02352         oper->next->next = NULL;
02353     }
02354 }
02355 
02360 void delOpData(RegNickList * nick)
02361 {
02362     OperList *oper, *nextoper, *tmp;
02363 
02364     for (oper = firstOper, tmp = NULL; oper; oper = nextoper) {
02365         nextoper = oper->next;
02366         if (oper->who == nick) {
02367             if (tmp)
02368                 tmp->next = nextoper;
02369             else
02370                 firstOper = nextoper;
02371             FREE(oper);
02372             continue;
02373         } else
02374             tmp = oper;
02375     }
02376 }
02377 
02378 /**************************************************************************/
02379 
02384 NCMD(ns_help)
02385 {
02386     help(nick->nick, NickServ, args, numargs);
02387     return RET_OK;
02388 }
02389 
02396 NCMD(ns_vacation)
02397 {
02398     char *from = nick->nick;
02399     time_t timestart;
02400 
02401     timestart = time(NULL);
02402 
02403     if (!nick->reg) {
02404         PutError(NickServ, nick, ERR_NEEDREGNICK_1ARG, nick->nick, 0, 0);
02405         return RET_FAIL;
02406     }
02407 
02408     if ((timestart - nick->reg->timereg) < NICKDROPTIME) {
02409         sSend
02410             (":%s NOTICE %s :Your nick has not been registered long enough to set vacation mode.  The current requirement is %u days",
02411              NickServ, from, (NICKDROPTIME / 3600 / 24));
02412         return RET_FAIL;
02413     }
02414 
02415     if (!isIdentified(nick, nick->reg)) {
02416         sSend
02417             (":%s NOTICE %s :You must be identifed with NickServ to use VACATION",
02418              NickServ, from);
02419         return RET_FAIL;
02420     }
02421     nick->reg->flags |= NVACATION;
02422 
02423     sSend(":%s NOTICE %s :Your nick is now marked as on vacation.",
02424           NickServ, from);
02425     sSend
02426         (":%s NOTICE %s :Please be aware that this will be automatically removed next time you return to IRC.",
02427          NickServ, from);
02428     sSend
02429         (":%s NOTICE %s :Your nick will automatically expire in %u days if you do not return.",
02430          NickServ, from, (NICKDROPTIME / 3600 / 24 * 2));
02431     return RET_OK_DB;
02432 }
02433 
02439 NCMD(ns_identify)
02440 {
02441     RegNickList *tonick = nick->reg;
02442     char *s_nick = NULL, *passwd;
02443     char *from = nick->nick;
02444 
02445     if (addFlood(nick, 5))
02446         return RET_KILLED;
02447 
02448     if (numargs < 2) {
02449         sSend(":%s NOTICE %s :The IDENTIFY command requires a password",
02450               NickServ, from);
02451         return RET_SYNTAX;
02452     }
02453 
02454     if (numargs < 3)
02455         passwd = args[1];
02456     else {
02457         s_nick = args[1];
02458         passwd = args[2];
02459         tonick = getRegNickData(s_nick);
02460     }
02461 
02462     if (!tonick) {
02463         PutError(NickServ, nick, ERR_NICKNOTREG_1ARG,
02464                  s_nick ? s_nick : nick->nick, 0, 0);
02465         PutHelpInfo(NickServ, nick, "HELP");
02466 
02467         return RET_NOTARGET;
02468     }
02469 
02470     if ((tonick->flags & NBANISH)) {
02471         PutError(NickServ, nick, ERR_NICKBANISHED_1ARG,
02472                  s_nick ? s_nick : nick->nick, 0, 0);
02473 
02474         return RET_EFAULT;
02475     }
02476 
02477     if (!(tonick->flags & NFORCEXFER) 
02478         && Valid_pw(passwd, tonick->password, NickGetEnc(tonick))) {
02479         if (tonick->chpw_key) {
02480             PutReply(NickServ, nick, RPL_CHKEY_DEAD, 0, 0, 0);
02481             tonick->chpw_key = 0;
02482         }
02483 
02484         if (nick->reg == tonick) 
02485         {
02486             nick->caccess = 3;
02487 
02488             assert(!strcasecmp(nick->reg->nick, nick->nick));
02489             strcpy(nick->reg->nick, nick->nick); /* Case update */
02490 
02491             PutReply(NickServ, nick, RPL_IDENTIFYOK_NOARG, 0, 0, 0);
02492 
02493             if ((tonick && !(tonick->flags & NUSEDPW))) {
02494                 tonick->flags |= NUSEDPW;
02495                 PutReply(NickServ, nick, RPL_MASKHELP, NickServ, NickServ,
02496                          0);
02497             }
02498         } else {
02499             PutReply(NickServ, nick, RPL_IDENTIFYOK_NICKARG, tonick->nick,
02500                      0, 0);
02501             clearIdentify(nick);
02502             setIdentify(nick, tonick);
02503             if ((tonick && !(tonick->flags & NUSEDPW))) {
02504                 tonick->flags |= NUSEDPW;
02505                 PutReply(NickServ, nick, RPL_MASKHELP, NickServ, NickServ,
02506                          0);
02507             }
02508         }
02509 
02510 #ifdef ENABLE_AHURT
02511         /*
02512          * Identify invokes AHURT bypass
02513          */
02514         if ((nick->oflags & NISAHURT)) {
02515             if ((tonick && !(tonick->flags & NBYPASS)))
02516                 PutError(NickServ, nick, ERR_NOAHURTBYPASS, 0, 0, 0);
02517             else {
02518                 PutReply(NickServ, nick, RPL_AHURTBYPASS, 0, 0, 0);
02519                 PutReply(NickServ, nick, RPL_BYPASSISLOGGED, 0, 0, 0);
02520                 sSend(":%s HEAL %s", NickServ, from);
02521                 nick->oflags &= ~(NISAHURT);
02522                 nicklog->log(nick, NS_IDENTIFY, tonick->nick, 0, "AHURT");
02523             }
02524         }
02525 #endif
02526 
02527         /*
02528          * Update last seen host, badpws, and time to reflect the
02529          * use of identify.
02530          */
02531         NickSeeUser(nick, tonick, 3, 0);
02532         GoodPwNick(nick, tonick);
02533         tonick->timestamp = CTime;
02534 
02535         /*
02536          * Local identify, check memos e-mail and news
02537          */
02538         if (nick->reg == tonick) {
02539             checkMemos(nick);
02540             complainAboutEmail(nick);
02541             newsNag(nick);
02542         }
02543         else if ((nick->oflags & NOISMASK) /* Remote id, update masked status */
02544              && !(tonick->flags & NDBISMASK)) tonick->flags |= NDBISMASK;
02545         return RET_OK;
02546     } else { 
02547         /*
02548          * Incorrect Password
02549          */
02550 
02551         /* failed identify takes away even the access list ID */
02552         if (nick->reg == tonick) { /* Local */
02553             nick->caccess = 1;
02554             PutError(NickServ, nick, ERR_BADPW, 0, 0, 0);
02555             if (BadPwNick(nick, nick->reg))
02556                 return RET_KILLED;
02557             nicklog->logw(nick, NS_IDENTIFY, tonick->nick, LOGF_BADPW);
02558         } else {
02559             PutError(NickServ, nick, ERR_BADPW, 0, 0, 0);
02560             nicklog->logw(nick, NS_IDENTIFY, tonick->nick, LOGF_BADPW);
02561 
02562             if (BadPwNick(nick, tonick))
02563                 return RET_KILLED;
02564             return RET_BADPW;
02565         }
02566     }
02567     return RET_OK;
02568 }
02569 
02570 
02571 #ifdef MD5_AUTH
02572 
02588 NCMD(ns_cidentify)
02589 {
02590     RegNickList *tonick = nick->reg;
02591     struct auth_data auth_info[1];
02592     char *s_nick = NULL, *passwd;
02593     int valid = 0;
02594 
02595     if (addFlood(nick, 5))
02596         return RET_KILLED;
02597 
02598     /*
02599      * Send info about the available types
02600      */
02601     if (!strcasecmp(args[0], "identify-types")) {
02602         PutError(NickServ, nick, RPL_AUTH_TYPES, 0, 0, 0);
02603         return RET_OK;
02604     }
02605 
02606     /*
02607      * Check for valid auth type, default is MD5 (for cidentify)
02608      */
02609     if (!strncasecmp(args[0], "identify-", 9)
02610         && strncasecmp((args[0]) + 9, "md5", 3)) {
02611         PutReply(NickServ, nick, ERR_AUTH_NOTYPE, 0, 0, 0);
02612         return RET_OK;
02613     }
02614 
02615     /*
02616      * No cookie, but nick specified? Bad.
02617      */
02618     if (numargs >= 2 && !nick->auth_cookie) {
02619         PutError(NickServ, nick, ERR_AUTH_CHAL, 0, 0, 0);
02620         nick->auth_cookie = 0;
02621         return RET_OK;
02622     }
02623 
02624     /*
02625      * Cookie but no arguments? Cancel previous cookie, issue new one.
02626      */
02627     if (nick->auth_cookie && numargs < 2) {
02628         PutError(NickServ, nick, RPL_AUTH_NORESPONSE, 0, 0, 0);
02629         nick->auth_cookie = 0;
02630     }
02631 
02638     if (numargs < 2) {
02639         /*
02640          * Cookie requested
02641          */
02642         nick->auth_cookie = time(NULL);
02643         if (nick->auth_cookie > 900000000)
02644             nick->auth_cookie -= 900000000;
02645         PutReply(NickServ, nick, RPL_AUTH_SEED,
02646                  (unsigned int)nick->auth_cookie,
02647                  (unsigned int)nick->idnum.getHashKey(), 0);
02648         return RET_OK;
02649     }
02650 
02651     /*
02652      * Identify request and they indeed have a challenge to answer
02653      * this message should be it.
02654      */
02655 
02656     if (numargs < 3)
02657         passwd = args[1];
02658     else {
02659         s_nick = args[1];
02660         passwd = args[2];
02661         tonick = getRegNickData(s_nick);
02662     }
02663 
02664     /*
02665      * Uh-oh not registered
02666      */
02667 
02668     if (!tonick) {
02669         PutError(NickServ, nick, ERR_AUTH_NOTREGISTERED_2ARG, "nickname",
02670                  args[1], 0);
02671         PutHelpInfo(NickServ, nick, "HELP IDENTIFY");
02672         return RET_NOTARGET;
02673     }
02674     
02675     auth_info->auth_cookie = nick->auth_cookie;
02676     auth_info->auth_user = nick->idnum.getHashKey();
02677     auth_info->format = 1;
02678 
02679     valid = Valid_md5key(passwd, auth_info, tonick->nick, tonick->password, NickGetEnc(tonick));
02680 //xValid_md5
02681     nick->auth_cookie = 0;
02682 
02683     /*
02684      * If the key was valid
02685      */
02686 
02687     if ( valid != 0 ) {
02688         if (tonick->chpw_key) {
02689             PutReply(NickServ, nick, RPL_CHKEY_DEAD, 0, 0, 0);
02690             tonick->chpw_key = 0;
02691         }
02692         if ((tonick && !(tonick->flags & NUSEDPW)))
02693             tonick->flags |= NUSEDPW;
02694 
02695         /*
02696          * Local identify
02697          */
02698         if (nick->reg == tonick) {
02699             nick->caccess = 4;
02700 
02701             assert(!strcasecmp(nick->reg->nick, nick->nick));
02702             strcpy(nick->reg->nick, nick->nick);    /* Case update */
02703             PutReply(NickServ, nick, RPL_AUTH_OK_0ARG, 0, 0, 0);
02704             GoodPwNick(nick, tonick);
02705         } else { /* Remote */
02706             PutReply(NickServ, nick, RPL_AUTH_OK_1ARG, tonick->nick, 0, 0);
02707             clearIdentify(nick);
02708             setIdentify(nick, tonick);
02709             GoodPwNick(nick, tonick);
02710         }
02711 
02712 #ifdef ENABLE_AHURT
02713         /*
02714          * Handle the ahurt bypass case
02715          */
02716         if ((nick->oflags & NISAHURT)) {
02717             if ((tonick && !(tonick->flags & NBYPASS)))
02718                 PutError(NickServ, nick, ERR_NOAHURTBYPASS, 0, 0, 0);
02719             else {
02720                 PutReply(NickServ, nick, RPL_AHURTBYPASS, 0, 0, 0);
02721                 PutReply(NickServ, nick, RPL_BYPASSISLOGGED, 0, 0, 0);
02722 
02723                 sSend(":%s HEAL %s", NickServ, nick->nick);
02724                 nick->oflags &= ~(NISAHURT);
02725                 nicklog->log(nick, NS_IDENTIFY, tonick->nick, 0, "AHURT");
02726             }
02727         }
02728 #endif
02729 
02730         /*
02731          * Update user information last seen host and time
02732          */
02733         NickSeeUser(nick, tonick, 3, 0);
02734         tonick->timestamp = CTime;
02735 
02736         /*
02737          * Local nick, check memos and for bad e-mail field
02738          */
02739         if (nick->reg == tonick) {
02740             checkMemos(nick);
02741             complainAboutEmail(nick);
02742         }
02743         return RET_OK;
02744     } else {
02745         /*
02746          * Uh-oh... they didn't answer the challenge correctly.
02747          */
02748         if (nick->reg == tonick) {
02749             PutError(NickServ, nick, ERR_AUTH_BAD_1ARG, tonick->nick, 0,
02750                      0);
02751             nicklog->log(nick, NS_IDENTIFY, tonick->nick, LOGF_BADPW,
02752                          "MD5");
02753             if (BadPwNick(nick, tonick))
02754                 return RET_KILLED;
02755         }
02756         else {
02757             PutError(NickServ, nick, ERR_AUTH_BAD_1ARG, tonick->nick, 0,
02758                      0);
02759             nicklog->log(nick, NS_IDENTIFY, tonick->nick, LOGF_BADPW,
02760                          "MD5");
02761             if (BadPwNick(nick, tonick))
02762                 return RET_KILLED;
02763             return RET_BADPW;
02764         }
02765     }
02766     return RET_OK;
02767 }
02768 #endif
02769 
02773 cmd_return ns_set_passwd(nss_tab *setEnt, UserList *nick,
02774                          char *args[], int numargs)
02775 {
02776     const char *from = nick->nick;
02777     char pw_reason[IRCBUF];
02778 
02779     if (numargs < 2) {
02780         sSend(":%s NOTICE %s :You must specify a parameter", NickServ,
02781               from);
02782         return RET_EFAULT;
02783     }
02784 
02785     if (PASSLEN < strlen(args[1])) {
02786         sSend(":%s NOTICE %s :Please specify a password of %d "
02787               "characters or less.", NickServ, from, PASSLEN);
02788         return RET_EFAULT;
02789     }
02790 
02791     if (isPasswordAcceptable(args[1], pw_reason) == 0) {
02792         sSend(":%s NOTICE %s :Sorry, %s isn't a password that you can use.",
02793             NickServ, from, args[1]);
02794         sSend(":%s NOTICE %s :%s", NickServ, from, pw_reason);
02795         return RET_EFAULT;
02796     }
02797     
02798     pw_enter_password(args[1], nick->reg->password, NickGetEnc(nick->reg));
02799     sSend(":%s NOTICE %s :Your password is now %s, do NOT forget it, we"
02800           " are not responsible for lost passwords", NickServ, from,
02801           args[1]);
02802     return RET_OK_DB;
02803 }
02804 
02805 
02806 
02810 cmd_return ns_set_url(nss_tab *setEnt, UserList *nick,
02811                          char *args[], int numargs)
02812 {
02813     const char *from = nick->nick;
02814     int urllen;
02815 
02816     /*
02817      * Clear the URL field?
02818      */
02819     if (numargs < 2) {
02820         if (nick->reg->url)
02821             FREE(nick->reg->url);
02822         nick->reg->url = NULL;
02823         sSend(":%s NOTICE %s :Your URL has been cleared",
02824               NickServ, from);
02825         return RET_OK_DB;
02826     }
02827 
02828     /*
02829      * Check the length, and report an error if it is too long
02830      */
02831     urllen = strlen(args[1]);
02832     if (urllen > URLLEN - 1) {
02833         sSend(":%s NOTICE %s :URL too long."
02834               "  Max is %d characters.", NickServ, from, URLLEN - 1);
02835         return RET_EFAULT;
02836     }
02837 
02838     /*
02839      * Free the old URL space, and allocate a new chunk.
02840      */
02841     if (nick->reg->url)
02842         FREE(nick->reg->url);
02843     nick->reg->url = strdup(args[1]);
02844     sSend(":%s NOTICE %s :Your URL has been set to: %s",
02845           NickServ, from, nick->reg->url);
02846     return RET_OK_DB;
02847 }
02848 
02849 
02853 cmd_return ns_set_encrypt(nss_tab *setEnt, UserList *nick,
02854                          char *args[], int numargs)
02855 {
02856     const char *from = nick->nick;
02857     int do_enc = 0;
02858 
02859     if (numargs < 2) {
02860         sSend(":%s NOTICE %s :Your password is %scurrently encrypted.",
02861               NickServ, from, (nick->reg->flags & NENCRYPT) ? "" : "\2not\2 ");
02862         return RET_OK_DB;
02863     }
02864 
02865     if (!str_cmp(args[1], "ON") || !str_cmp(args[1], "ENCRYPT") ||
02866         !str_cmp(args[1], "YES"))
02867         do_enc = 1;
02868     else if (!str_cmp(args[1], "OFF") || !str_cmp(args[1], "UNENCRYPT") ||
02869         !str_cmp(args[1], "NO"))
02870         do_enc = 0;
02871     else {
02872         sSend(":%s NOTICE %s :Invalid setting.  Must be ON or OFF.",
02873               NickServ, from);
02874     }
02875 
02876     if (numargs < 3) {
02877         sSend(":%s NOTICE %s :Your password must also be specified to "
02878               "change this setting.", NickServ, from);
02879         return RET_OK_DB;
02880     }
02881 
02882     if (!Valid_pw(args[2], nick->reg->password, NickGetEnc(nick->reg))) {
02883         PutReply(NickServ, nick, ERR_BADPW, 0, 0, 0);
02884         if (BadPwNick(nick, nick->reg))
02885             return RET_KILLED;
02886 
02887         return RET_BADPW;
02888     }
02889     else
02890         GoodPwNick(nick, nick->reg);
02891 
02892 
02893     if (do_enc) {
02894         sSend(":%s NOTICE %s :You password is now encrypted within services.",
02895                NickServ, from);
02896         nick->reg->flags |= NENCRYPT;
02897     }
02898     else {
02899         sSend(":%s NOTICE %s :You password is no longer encrypted within services.",
02900                NickServ, from);
02901         nick->reg->flags &= ~NENCRYPT;
02902     }
02903 
02904     pw_enter_password(args[2], nick->reg->password, NickGetEnc(nick->reg));
02905 
02906     return RET_OK_DB;
02907 }
02908 
02909 
02913 cmd_return ns_set_idtime(nss_tab *setEnt, UserList *nick,
02914                          char *args[], int numargs)
02915 {
02916     const char *from = nick->nick;
02917     int delay;
02918 
02919     if (numargs < 2) {
02920         sSend(":%s NOTICE %s :Your current ID time is: %i "
02921               "seconds", NickServ, from, nick->reg->idtime);
02922         sSend(":%s NOTICE %s :If you wish to set your ID time,"
02923               " you must specify a delay", NickServ, from);
02924         return RET_OK;
02925     }
02926 
02927     if ((delay = atoi(args[1]))) {
02928         if ((delay > ENF_MAXDELAY) || (delay < ENF_MINDELAY)) {
02929             sSend(":%s NOTICE %s :Invalid delay value",
02930                   NickServ, from);
02931             sSend(":%s NOTICE %s :Please enter a value in "
02932                   "the range of: %i - %i seconds",
02933                   NickServ, from, ENF_MINDELAY, ENF_MAXDELAY);
02934             return RET_EFAULT;
02935         }
02936     } else {
02937         sSend(":%s NOTICE %s :Invalid delay value", NickServ, from);
02938         sSend(":%s NOTICE %s :Please enter a value in the "
02939               "range of: %i - %i seconds", NickServ, from,
02940               ENF_MINDELAY, ENF_MAXDELAY);
02941         return RET_EFAULT;
02942     }
02943 
02944     nick->reg->idtime = delay;
02945     sSend(":%s NOTICE %s :Your ID time has been set to: %i seconds",
02946           NickServ, from, nick->reg->idtime);
02947 
02948     return RET_OK_DB;
02949 }
02950 
02951 
02952 #ifdef REQ_EMAIL
02953 /*
02954  * Construct an activation e-mail              -Mysid
02955  */
02956 void ActivateEmail(UserList *nick, char *addy)
02957 {
02958     char buf[IRCBUF * 2];
02959     EmailMessage email;
02960 
02961     email.from = "NickName services <nickserv@"NETWORK">";
02962     email.to = addy;
02963     email.subject = "Nickname verification key";
02964     email.body = "Someone, possibly you has specified the e-mail "
02965                      "contact address of: ";
02966     email.to += addy;
02967     email.to += "\n";
02968     email.to += "If you do not follow the instructions found in this message, \n";
02969     email.to += "then it will be assumed that the e-mail address specified\n";
02970     email.to += " was not correct.\n";
02971     email.to += "\n";
02972     sprintf(buf, "Your nickname activation key is: %lu\n", nick->reg->email_key);
02973     email.to += buf;
02974     sprintf(buf, "To activate your nickname, switch to the nickname %s and\n", nick->reg->nick);
02975     email.to += buf;
02976     sprintf(buf, "/msg %s ACTIVATE %lu\n", nick->reg->email_key);
02977     email.to += buf;
02978     email.to += "\n";
02979     sprintf(buf, "NOTICE: mail sent by %s@%s using the nickname %s\n", nick->user, nick->host, nick->nick);
02980     email.to += buf;
02981     sprintf(buf, "%s\n", ctime(&CTime));
02982     email.to += buf;
02983     email.to += "\n";
02984     email.send();
02985     email.reset();
02986 }
02987 #endif
02988 
02992 cmd_return ns_set_email(nss_tab *setEnt, UserList *nick,
02993                         char *args[], int numargs)
02994 {
02995     const char *from = nick->nick;
02996 
02997     if (numargs < 2) {
02998         sSend(":%s NOTICE %s :You must specify an e-mail address",
02999               NickServ, from);
03000         return RET_EFAULT;
03001     }
03002 
03003     if (!str_cmp(args[1], "on")) {
03004         nick->reg->flags |= NEMAIL;
03005         PutReply(NickServ, nick, RPL_SWITCHNOW_ARG2,
03006             "public e-mail", "ON", 0);
03007         return RET_OK_DB;
03008     } else if (!str_cmp(args[1], "off")) {
03009         nick->reg->flags &= ~(NEMAIL);
03010         PutReply(NickServ, nick, RPL_SWITCHNOW_ARG2,
03011             "public e-mail", "OFF", 0);
03012         return RET_OK_DB;
03013     }
03014 
03015     if ((!strchr(args[1], '@') 
03016 #ifndef REQ_EMAIL
03017        && strcasecmp(args[1], "none")
03018 #endif
03019        ) || *args[1] == '|' || strchr(args[1], '/') || strchr(args[1], '<')
03020          || strchr(args[1], '>') || strchr(args[1], '\"')) {
03021         sSend(":%s NOTICE %s :Please specify a valid e-mail address"
03022               "in the form of user@host", NickServ, from);
03023         return RET_EFAULT;
03024     }
03025 
03026 #ifdef REQ_EMAIL
03027     srandom(time(NULL));
03028 
03029     if (emailAbuseCheck(nick, args[1], 0))
03030         return;
03031 
03032     nick->reg->email_key = random();
03033     nick->reg->flags |= NDEACC;
03034 
03035     sSend(":%s NOTICE %s :Your nick has been temporarily de-activated to verify your new address", NickServ, from);
03036     sSend(":%s NOTICE %s :To re-activate please follow the same procedure as when you registered", NickServ, from);
03037     sSend(":%s NOTICE %s :All your previous data will be saved", NickServ, from);
03038     sSend(":%s NOTICE %s :Registration key sent to %s", NickServ, from, args[1]);
03039 
03040     ActivateEmail(nick, args[1]);
03041 #endif
03042 
03043     strncpyzt(nick->reg->email, args[1], EMAILLEN);
03044 
03045     sSend(":%s NOTICE %s :Your email address has been set to %s",
03046           NickServ, from, args[1]);
03047     if (!strcasecmp(args[1], "none")) {
03048         sSend(":%s NOTICE %s :Please note: should you forget your "
03049               "password and have no e-mail address set, your password "
03050               "cannot be recovered for you.", NickServ, from);
03051         strcpy(nick->reg->email, "(none) ");
03052     }
03053 
03054     return RET_OK_DB;
03055 }
03056 
03057 
03058 
03066 NCMD(ns_set)
03067 {
03068     char *from = nick->nick;
03069     int i;
03070 
03071         // *INDENT-OFF*
03072     nss_tab ns_set_table[] = {
03073         { "enforce",    "nick protection",
03074             NSS_FLAG,   NKILL,      0,      },
03075         { "kill",       "nick protection",
03076             NSS_FLAG,   NKILL,      0,      },
03077         { "ident",      "identification requirement",
03078             NSS_FLAG,   NIDENT,     0,      },
03079         { "noaddop",    "Noaddop option",
03080             NSS_FLAG,   NOADDOP,    0,      },
03081         { "terse",      "Terse option",
03082             NSS_FLAG,   NTERSE,     0,      },
03083         { "maskadd",    "hide mask option",
03084             NSS_FLAG,   NDBISMASK,  0,      },
03085         { "iphide",     "hide mask option",
03086             NSS_FLAG,   NDBISMASK,  0,      },
03087         { "hideip",     "hide mask option",
03088             NSS_FLAG,   NDBISMASK,  0,      },
03089         { "showemail",  "public e-mail",
03090             NSS_FLAG,   NEMAIL,     0,      },
03091         { "passwd",     "password",
03092             NSS_PROC,   0,          0,      ns_set_passwd },
03093         { "password",   "password",
03094             NSS_PROC,   0,          0,      ns_set_passwd },
03095         { "url",        "url",
03096             NSS_PROC,   0,          0,      ns_set_url },
03097         { "idtime",     "identify delay",
03098             NSS_PROC,   0,          0,      ns_set_idtime },
03099         { "email",      "e-mail address",
03100             NSS_PROC,   0,          0,      ns_set_email },
03101         { "address",    "e-mail address",
03102             NSS_PROC,   0,          0,      ns_set_email },
03103         { "encrypt",    "encrypted password",
03104             NSS_PROC,   0,          0,      ns_set_encrypt },
03105         { NULL,     NULL,
03106             (ns_set_en)0,   0,      0,      NULL },
03107     };
03108         // *INDENT-ON*
03109 
03110 
03111     if (addFlood(nick, 2))
03112         return RET_KILLED;
03113 
03114     if (numargs < 2) {
03115         sSend(":%s NOTICE %s :A variable is required with NickServ SET",
03116               NickServ, from);
03117         sSend(":%s NOTICE %s :See /msg %s HELP SET", NickServ, from,
03118               NickServ);
03119 
03120         return RET_SYNTAX;
03121     }
03122 
03123     if (!isIdentified(nick, nick->reg)) {
03124         PutError(NickServ, nick, ERR_NOTIDENTIFIED, 0, 0, 0);
03125         return RET_NOPERM;
03126     }
03127 
03128 
03129     for (i = 0; ns_set_table[i].keyword; i++)
03130         if (!str_cmp(ns_set_table[i].keyword, args[1]) &&
03131             (!ns_set_table[i].opFlagsRequired ||
03132              opFlagged(nick, ns_set_table[i].opFlagsRequired)))
03133             break;
03134 
03135     if (!ns_set_table[i].keyword) {
03136         sSend(":%s NOTICE %s :Unknown set command %s, please "
03137               "try /msg %s HELP SET", NickServ, from, args[1], NickServ);
03138         return RET_SYNTAX;
03139     }
03140 
03141     if (ns_set_table[i].set_type == NSS_FLAG) {
03142         int flag = ns_set_table[i].flag;
03143 
03144         if (numargs < 3) {
03145             PutReply(NickServ, nick, RPL_SWITCHIS_ARG2,
03146                      ns_set_table[i].description,
03147                      !(nick->reg->flags & (flag)) ? "off" : "on", 0);
03148 
03149             return RET_OK;
03150         } else if (!str_cmp(args[2], "on")) {
03151             nick->reg->flags |= flag;
03152             PutReply(NickServ, nick, RPL_SWITCHNOW_ARG2,
03153                      ns_set_table[i].description, "ON", 0);
03154         } else if (!str_cmp(args[2], "off")) {
03155             nick->reg->flags &= ~(flag);
03156             PutReply(NickServ, nick, RPL_SWITCHNOW_ARG2,
03157                      ns_set_table[i].description, "OFF", 0);
03158         } else {
03159             sSend(":%s NOTICE %s :Unknown variable for SET %s",
03160                   NickServ, from, ns_set_table[i].keyword);
03161             sSend(":%s NOTICE %s :Syntax: /msg %s SET %s <on|off>",
03162                   NickServ, from, NickServ, ns_set_table[i].keyword);
03163 
03164             return RET_SYNTAX;
03165         }
03166 
03167         return RET_OK_DB;
03168     }
03169     else if (ns_set_table[i].set_type == NSS_PROC) {
03170         return (* ns_set_table[i].proc)(&ns_set_table[i], nick,
03171                                         args+1, numargs-1);
03172     }
03173 
03174     return RET_OK;
03175 }
03176 
03177 
03188 NCMD(ns_register)
03189 {
03190     char *from;
03191     char user2[USERLEN];
03192     char host2[HOSTLEN];
03193     char pw_reason[IRCBUF];
03194     char mailTemp[EMAILLEN] = "(none)";
03195     char *p;
03196     int wasvalid = 0;
03197     unsigned int i = 0;
03198 #ifdef REQ_EMAIL
03199     time_t doot = time(NULL);
03200 
03201     srandom(time(NULL));
03202 #endif
03203 
03204     from = nick->nick;
03205 
03206     if (addFlood(nick, 20))
03207         return RET_KILLED;
03208 
03209     if (nick->reg != NULL) {
03210         sSend(":%s NOTICE %s :This nickname is already registered.",
03211               NickServ, from);
03212         return RET_EFAULT;
03213     }
03214 
03215     for (i = 0; i < NUM_CNICKS; i++)
03216         if (!strncasecmp
03217             (cnick_prefixes[i], nick->nick, strlen(cnick_prefixes[i]))) {
03218             sSend
03219                 (":%s NOTICE %s :The nick that you are using is a temporary nickname owned by services: it cannot be registered.",
03220                  NickServ, from);
03221             return RET_EFAULT;
03222         }
03223 
03224     if (!strncasecmp("Auth-", nick->nick, strlen("Auth-"))) {
03225         sSend
03226             (":%s NOTICE %s :The nick that you are using is a temporary nickname owned by services: it cannot be registered.",
03227              NickServ, from);
03228         return RET_EFAULT;
03229     }
03230 
03231     if (numargs < 2) {
03232         sSend(":%s NOTICE %s :You must specify a password to register",
03233               NickServ, from);
03234         return RET_SYNTAX;
03235     }
03236 
03237     if (isPasswordAcceptable(args[1], pw_reason) == 0) {
03238         sSend(":%s NOTICE %s :Sorry, %s isn't a password that you can use.",
03239             NickServ, from, args[1]);
03240         sSend(":%s NOTICE %s :%s", NickServ, from, pw_reason);
03241         return RET_EFAULT;
03242     }
03243 
03244     if (strlen(args[1]) > 15) {
03245         sSend(":%s NOTICE %s :Please specify a password of "
03246               "%d characters or less", NickServ, from, PASSLEN);
03247         return RET_EFAULT;
03248     }
03249 
03250     if (strcasecmp(args[1], from) == 0) {
03251         sSend(":%s NOTICE %s :Your password cannot be your nickname.",
03252               NickServ, from);
03253         return RET_EFAULT;
03254     }
03255 
03256     if (strchr(args[1], '@')
03257         || (args[1] == strchr(args[1], '<') && (p = strrchr(args[1], '>'))
03258             && !*(p + 1))) {
03259         if (strchr(args[1], '@'))
03260             sSend
03261                 (":%s NOTICE %s :Your registration password cannot contain the @ symbol.",
03262                  NickServ, from);
03263         if (args[1] == strchr(args[1], '<') && strchr(args[1], '>')) {
03264             sSend
03265                 (":%s NOTICE %s :Your registration password should not be surrounded with <>.",
03266                  NickServ, from);
03267             sSend
03268                 (":%s NOTICE %s :The '<' and '>' symbols surrounding a word in services' helpfiles is an indicator that 'password' is a field that you should specify a value for.",
03269                  NickServ, from);
03270         }
03271         sSend(":%s NOTICE %s :\2/msg %s HELP REGISTER\2 for assistance",
03272               NickServ, from, NickServ);
03273         return RET_EFAULT;
03274     }
03275 
03276         if (strlen(args[1]) < 5)
03277         {
03278                 sSend(":%s NOTICE %s :Your password cannot be %s.  A password should be impossible to guess and must have a length of 5 or more characters (letters, numbers, and symbols).",
03279                       NickServ, from, args[1]);
03280         return RET_EFAULT;
03281         }
03282 
03283     if (strcasecmp(args[1], "password") == 0 || strcasecmp(args[1], "<password>") == 0
03284         || strcasecmp(args[1], "1234") == 0 || strcasecmp(args[1], "fz345") == 0
03285         || strcasecmp(args[1], "word") == 0)
03286     {
03287         sSend(":%s NOTICE %s :Your password cannot be %s.", NickServ, from,
03288               args[1]);
03289         return RET_EFAULT;
03290     }
03291 
03292     if (numargs < 3) {
03293 #ifndef REQ_EMAIL
03294         sSend
03295             (":%s NOTICE %s :To register you must also either specify your e-mail address or NONE.",
03296              NickServ, from);
03297         sSend
03298             (":%s NOTICE %s :E-mail addresses provided are treated as private material and are used ONLY to assist with lost passwords.",
03299              NickServ, from);
03300         sSend
03301             (":%s NOTICE %s :Specifying an e-mail address of NONE indicates that, should you lose your password, operators will be unable to retrieve the password for you.",
03302              NickServ, from);
03303         sSend
03304             (":%s NOTICE %s :examples: /msg nickserv register \2MYSECRETCODE\2 \2me@myemail.com\2",
03305              NickServ, from);
03306         sSend
03307             (":%s NOTICE %s :          /msg nickserv register \2MYSECRETCODE\2 \2NONE\2",
03308              NickServ, from);
03309 #else
03310         sSend(":%s NOTICE %s :You must specify an e-mail address and a "
03311               "password to register.", NickServ, from);
03312 #endif
03313         return RET_SYNTAX;
03314     }
03315 
03316 #ifdef REQ_EMAIL
03317     if (numargs > 2)
03318 #else
03319     if (numargs > 2 && strcasecmp(args[2], "none"))
03320 #endif
03321         if (!strchr(args[2], '@') || !strchr(args[2], '.'))
03322         {
03323             sSend
03324                 (":%s NOTICE %s :specified a e-mail address is invalid. "
03325                  "Must be of the form user@host", NickServ, from);
03326 #ifdef EMAIL_OK_IF_SPECIFIED
03327             return;
03328 #endif
03329         }
03330         else {
03331             wasvalid = 1;
03332             strncpyzt(mailTemp, args[2], EMAILLEN);
03333     } else if (numargs > 2 && !strcasecmp(args[2], "none"))
03334         strcpy(mailTemp, "(none) ");
03335     else
03336         strcpy(mailTemp, "(none)");
03337 
03338     if (wasvalid == 0)
03339         sSend
03340             (":%s NOTICE %s :To enable us to recover your password in the event that it is lost, you must specify your e-mail address by using /msg NickServ set address <email address>",
03341              NickServ, from);
03342 
03343 #ifdef REQ_EMAIL
03344     if (emailAbuseCheck(nick, args[1], 1))
03345         return;
03346 #endif
03347 
03348     strncpyzt(user2, nick->user, USERLEN);
03349     strncpyzt(host2, nick->host, HOSTLEN);
03350 
03351     nick->reg = (RegNickList *) oalloc(sizeof(RegNickList));
03352 
03353     strncpyzt(nick->reg->nick, nick->nick, NICKLEN);
03354     strncpyzt(nick->reg->user, nick->user, USERLEN);
03355     SetDynBuffer(&nick->reg->host, nick->host);
03356     strncpyzt(nick->reg->email, mailTemp, EMAILLEN);
03357 #ifdef TRACK_GECOS
03358     SetDynBuffer(&nick->reg->gecos, nick->gecos);
03359 #endif
03360 
03361     nick->reg->timestamp = CTime;
03362     nick->reg->timereg = CTime;
03363 #ifdef REQ_EMAIL
03364     nick->reg->email_key = random();
03365 #endif
03366     nick->caccess = 3;
03367     nick->reg->flags |= NENCRYPT;
03368     pw_enter_password(args[1], nick->reg->password, NickGetEnc(nick->reg));
03369 
03370     nicklog->log(nick, NS_REGISTER, nick->nick);
03371     ADD_MEMO_BOX(nick->reg);
03372     mostnicks++;
03373 
03374     nick->reg->amasks = 0;
03375     nick->reg->url = NULL;
03376     nick->reg->chans = 0;
03377     nick->reg->idtime = DEF_NDELAY;
03378     nick->reg->regnum.SetNext(top_regnick_idnum);
03379 
03380     addRegNick(nick->reg);
03381 #ifdef REQ_EMAIL
03382     ActivateEmail(nick, args[1]);
03383 #endif
03384 
03385     if (nick->oflags & NOISMASK)
03386         nick->reg->flags |= NDBISMASK;
03387 #if defined(AHURT_BYPASS_BY_DEFAULT)
03388     if (!
03389         (isAHurt(tmp->nick, tmp->user, tmp->host)
03390          || isAKilled(tmp->nick, tmp->user,
03391                       tmp->host))) nick->reg->flags |= NBYPASS;
03392     else {
03393         sSend
03394             (":%s NOTICE %s :Warning: you will not be able to use this registration to bypass select bans without further assistance.",
03395              NickServ, nick->nick);
03396         sSend
03397             (":%s NOTICE %s :This is true for all nicks registered from a domain while selective users from it are being banned for security reasons.",
03398              NickServ, nick->nick);
03399     }
03400 #endif
03401 
03402     sSend
03403         (":%s NOTICE %s :Your nickname has been registered with the password %s",
03404          NickServ, from, args[1]);
03405 
03406     if (nick->oflags & NOISMASK)
03407         nick->reg->flags |= NDBISMASK;
03408     return RET_OK_DB;
03409 }
03410 
03411 
03437 void SendNickInfo(UserList *nick, RegNickList *rnl, int terseOption)
03438 {
03439     char *from = nick->nick;
03440     struct tm *time;
03441     char temp[80];
03442     unsigned int j;
03443     UserList *online = NULL;
03444     struct {
03445         const char *optname;
03446         const char *optline;
03447         flag_t bit;
03448         int verbatim, oper_only;
03449     } regnick_flag_tab[] = {
03450         { "Enforce", "nick protection",                 NKILL, 0 },
03451         { "Held",    "This nickname will not expire.",  NHOLD, 1 },
03452         { "Vacation", "This nickname has vacation set and has an "
03453                       "extended expiration period.", NVACATION, 1 },
03454         { "Nosendpass", NULL, NOSENDPASS, 0, 1}, 
03455         { NULL }
03456     };
03457 
03458     sSend(":%s NOTICE %s :Information for %s:", NickServ, from, rnl->nick);
03459 
03460     if ((online = getNickData(rnl->nick))) {
03461         if (isIdentified(online, rnl)) {
03462                 PutReply(NickServ, nick, RPL_INFONLINE_ID, rnl->nick, online->caccess, 0);
03463         } else if (isRecognized(online, rnl)) {
03464                 PutReply(NickServ, nick, RPL_INFONLINE_NOID, rnl->nick, online->caccess, 0);
03465 
03466                 /* sSend(":%s NOTICE %s :%s is online, but not identified",
03467                       NickServ, from, rnl->nick); */
03468         }
03469     }
03470 
03471     if (rnl->flags & NBANISH) {
03472         PutReply(NickServ, nick, RPL_NS_BANISH, rnl->nick, 0, 0);
03473         PutReply(NickServ, nick, RPL_NS_ENDINFO, rnl->nick, 0, 0);
03474         return;
03475     }
03476 
03477 #ifdef REQ_EMAIL
03478     if (!(rnl->flags & NACTIVE)) {
03479         sSend(":%s NOTICE %s :%s is not activated.",
03480              NickServ, from, rnl->nick);
03481         if (!isOper(nick))
03482             return;
03483     }
03484 #endif
03485 #ifdef TRACK_GECOS
03486     if (rnl->gecos)
03487         sSend(":%s NOTICE %s :%s[%s@%s] (%s)", NickServ, from,
03488               rnl->nick, rnl->user, regnick_ugethost(nick, rnl),
03489               rnl->gecos);
03490     else
03491 #endif
03492         sSend(":%s NOTICE %s :%s[%s@%s]", NickServ, from,
03493               rnl->nick, rnl->user, regnick_ugethost(nick, rnl));
03494 
03495     if (rnl->url)
03496         sSend(":%s NOTICE %s :Url            :  %s", NickServ, from,
03497               rnl->url);
03498 
03499 
03500     if (((rnl->flags & NEMAIL) || isIdentified(nick, rnl))
03501         && rnl->email[0])
03502         sSend(":%s NOTICE %s :Email          :  %s", NickServ, from,
03503               rnl->email);
03504     do
03505     {
03506         char optBuf[IRCBUF];
03507 
03508         time = localtime(&rnl->timestamp);
03509         if ( strftime(temp, 80, "%a %Y-%b-%d %T %Z", time) > 0 )
03510             sSend(":%s NOTICE %s :Last seen time :  %s", NickServ, from, temp);
03511 
03512         time = localtime(&rnl->timereg);
03513 
03514         if ( strftime(temp, 80, "%a %Y-%b-%d %T %Z", time) > 0 )
03515             sSend(":%s NOTICE %s :Registered at  :  %s", NickServ, from, temp);
03516 
03517         time = localtime(&CTime);
03518 
03519         if ( strftime(temp, 80, "%a %Y-%b-%d %T %Z", time) > 0 )
03520             sSend(":%s NOTICE %s :Current time   :  %s", NickServ, from, temp);
03521 
03522         memset(optBuf, 0, sizeof(optBuf));
03523 
03524         for(j = 0; regnick_flag_tab[j].optname; j++)
03525         {
03526             if (regnick_flag_tab[j].oper_only && !isOper(nick))
03527                 continue;
03528 
03529             if (terseOption || !regnick_flag_tab[j].optline) {
03530                 if ((rnl->flags & regnick_flag_tab[j].bit) &&
03531                     (strlen(optBuf) < (IRCBUF - strlen(regnick_flag_tab[j].optname) - 25)))
03532                 {
03533                     if (*optBuf)
03534                         strcat(optBuf, ", ");
03535                     strcat(optBuf, regnick_flag_tab[j].optname);
03536                 }
03537                 continue;
03538             }
03539 
03540             if (rnl->flags & regnick_flag_tab[j].bit)
03541             {
03542                 if (!regnick_flag_tab[j].verbatim)
03543                     sSend(":%s NOTICE %s :This user has enabled \2%s\2.", NickServ,
03544                           from, regnick_flag_tab[j].optline);
03545                 else
03546                     sSend(":%s NOTICE %s :%s", NickServ,
03547                          from, regnick_flag_tab[j].optline);
03548             }
03549         }
03550 
03551         if (terseOption) {
03552             if (rnl->memos) {
03553                 /* Note, 22 characters space is allowed for above, 8 of that
03554                  * is used here.
03555                  */
03556                 if (rnl->memos->flags & MNOMEMO)
03557                     sprintf(optBuf + strlen(optBuf), "%sNoMemo",
03558                             *optBuf ? ", " : "");
03559             }
03560         }   
03561 
03562         if (rnl->memos) {
03563             if (!terseOption && (rnl->memos->flags & MNOMEMO))
03564                 sSend(":%s NOTICE %s :%s has chosen not to receive memos",
03565                       NickServ, from, rnl->nick);
03566             if (rnl->memos->flags & MFORWARDED)
03567                 sSend(":%s NOTICE %s :Memos forwarded to: %s",
03568                      NickServ, from, rnl->memos->forward->nick);
03569         }
03570 
03571         if (*optBuf)
03572             sSend(":%s NOTICE %s :Nick options   :  %s", NickServ, from,
03573                   optBuf);
03574 #ifdef ENABLE_GRPOPS
03575         if (((rnl->opflags & OGRP) && !(rnl->opflags & OROOT)))
03576             sSend(":%s NOTICE %s :User is a GRP-op.",
03577                  NickServ, from);
03578         else if (!isOper(nick) && (rnl->opflags & OROOT))
03579             sSend(":%s NOTICE %s :User is a SRA and GRP-op.",
03580                  NickServ, from);
03581 #else
03582         else if (!isOper(nick) && (rnl->opflags & OROOT))
03583             sSend(":%s NOTICE %s :User is a Services root admin, GRP-op.",
03584                  NickServ, from);
03585 #endif
03586         else
03587         if (online && !isOper(nick) && (isHelpop(online) || isOper(online)))
03588             sSend(":%s NOTICE %s :User can mail lost passwords.", NickServ, from);
03589     } while(0);
03590 
03591     if (isOper(nick) == 1) {
03592         if (!terseOption)
03593         {
03594             sSend(":%s NOTICE %s :+++ IRCop Data +++", NickServ, from);
03595             if (rnl->opflags & OROOT)
03596                 sSend(":%s NOTICE %s :+ This user is a Warlock/Sorceress (Services Root)",
03597                      NickServ, from);
03598             else if (rnl->opflags & OPFLAG_ROOTSET)
03599                 sSend(":%s NOTICE %s :+ This user is a Wizard/Witch (Services Operator)",
03600                      NickServ, from);
03601         }
03602         else
03603         {
03604             if (rnl->opflags & OROOT)
03605                 sSend(":%s NOTICE %s :+ Services root admin.",
03606                      NickServ, from);
03607             else if (rnl->opflags & OPFLAG_ROOTSET)
03608                 sSend(":%s NOTICE %s :+ Services operator.",
03609                      NickServ, from);
03610         }
03611 
03612         {
03613             char buf[EMAILLEN+15];
03614 
03615             *buf = '\0';
03616 
03617             if (((rnl->flags & NEMAIL) == 0) && (rnl->email[0])
03618                         && !isIdentified(nick, rnl))
03619                 snprintf(buf, sizeof(buf), ", Prv Email: %s", rnl->email);
03620             sSend(":%s NOTICE %s :+ Masks: %i, Bypass: %s%s", NickServ, from,
03621                   rnl->amasks, (rnl->flags & NBYPASS) ? "Yes" : "No", buf);
03622         }
03623 
03624 
03625         if (online) {
03626             sSend(":%s NOTICE %s :+ %s flood level: %i/100", NickServ,
03627                   from, rnl->nick, online->floodlevel.GetLev());
03628         }
03629         if ((rnl->flags & NMARK)) {
03630             sSend(":%s NOTICE %s :+ %s MARKED%s%s", NickServ,
03631                   from, rnl->nick, rnl->markby ? " by " : "",
03632                   rnl->markby ? rnl->markby : "");
03633         }
03634     }
03635 
03636     if (isHelpop(nick) == 1 && isOper(nick) == 0) {
03637         if (((rnl->flags & NEMAIL) == 0) && (rnl->email[0]))
03638             sSend(":%s NOTICE %s :+ Email address: Hidden (not displayed)",
03639                   NickServ, from);
03640     }
03641     sSend(":%s NOTICE %s :End of info on %s", NickServ, from,
03642           rnl->nick);
03643 }
03644 
03646 NCMD(ns_info)
03647 {
03648     char *from = nick->nick;
03649     unsigned int i;
03650     int terseOption, k;
03651     RegNickList *regnick;
03652 
03653     if (addFlood(nick, 5))
03654         return RET_KILLED;
03655 
03656     terseOption = (nick->reg && (nick->reg->flags & NTERSE));
03657 
03658     for(k = 1; k < numargs; k++)
03659     {
03660         if (args[k][0] != '-')
03661             break;
03662         if (strcmp(args[k], "-short") == 0 || strcmp(args[k], "-terse") == 0)
03663             terseOption = 1;
03664         else if (strcmp(args[k], "-long") == 0 || strcmp(args[k], "-verbose") == 0)
03665             terseOption = 0;
03666     }
03667 
03668     if (k < numargs)
03669         regnick = getRegNickData(args[k]);
03670     else
03671         regnick = nick->reg;
03672 
03673 #if defined(NICKSERV_INFO_TZ_ARG)
03674     if (regnick && numargs > 2 && args[2])
03675         tzapply(args[2]);
03676 #endif
03677 
03678     if (numargs > 1)
03679         for (i = 0; i < NUM_CNICKS; i++)
03680             if (!strncasecmp
03681                 (cnick_prefixes[i], args[k], strlen(cnick_prefixes[i]))) {
03682                 sSend
03683                     (":%s NOTICE %s :That is a services temporary user nickname.",
03684                      NickServ, from);
03685                 return RET_OK;
03686             }
03687 
03688     if (regnick == NULL) {
03689         sSend(":%s NOTICE %s :%s is not registered", NickServ, from,
03690               numargs > 1 ? args[k] : from);
03691         return RET_FAIL;
03692     }
03693 
03694     SendNickInfo(nick, regnick, terseOption);
03695 
03696 #if defined(NICKSERV_INFO_TZ_ARG)
03697     if (numargs > 2 && args[2])
03698         tzapply(DEF_TIMEZONE);
03699 #endif
03700     return RET_OK;
03701 }
03702 
03706 NCMD(ns_drop)
03707 {
03708     char *from = nick->nick;
03709 
03710     if (addFlood(nick, 3))
03711         return RET_KILLED;
03712 
03713     if (!nick->reg) {
03714         sSend(":%s NOTICE %s :Your present nickname is not registered.",
03715               NickServ, nick->nick);
03716         return RET_EFAULT;
03717     }
03718 
03719     if ((nick->reg->flags & NBANISH)) {
03720         sSend
03721             (":%s NOTICE %s :Sorry, but that nickname is currently banished.",
03722              NickServ, from);
03723         return RET_FAIL;
03724     }
03725 
03726     if (numargs > 1) {
03727         if (!Valid_pw(args[1], nick->reg->password, NickGetEnc(nick->reg))) {
03728             sSend(":%s NOTICE %s :Incorrect password.", NickServ,
03729                   nick->nick);
03730             BadPwNick(nick, nick->reg);
03731             return RET_BADPW;
03732         }
03733         else
03734             GoodPwNick(nick, nick->reg);
03735     }
03736 
03737     if (!isIdentified(nick, nick->reg)) {
03738         sSend(":%s NOTICE %s :You must identify to drop your nick",
03739               NickServ, nick->nick);
03740         return RET_NOPERM;
03741     }
03742 
03743     mostnicks--;
03744     sSend(":%s NOTICE %s :Your nick %s has been dropped.",
03745           NickServ, from, from);
03746     nicklog->log(nick, NS_DROP, nick->nick);
03747     delRegNick(nick->reg);
03748     nick->reg = NULL;
03749     return RET_OK_DB;
03750 }
03751 
03757 NCMD(ns_addmask)
03758 {
03759 
03760     if (addFlood(nick, 2))
03761         return RET_KILLED;
03762 
03763     if (!isIdentified(nick, nick->reg)) {
03764         sSend(":%s NOTICE %s :You must identify to use ADDMASK", NickServ,
03765               nick->nick);
03766         return RET_NOPERM;
03767     }
03768 
03769     if (numargs < 2) {
03770         char *user, *host, theirmask[USERLEN + HOSTLEN + 3];
03771 
03772         user = host = NULL;
03773 
03774         SetDynBuffer(&user, nick->user);
03775         SetDynBuffer(&host, nick->host);
03776         mask(user, host, 0, theirmask);
03777         addAccessMask(theirmask, nick);
03778         SetDynBuffer(&user, NULL);
03779         SetDynBuffer(&host, NULL);
03780 
03781         return RET_OK_DB;
03782     } else if (numargs < 4) {
03783         if (!strcasecmp(args[1], "S")) {
03784             addAccessMask(args[2], nick);
03785             return RET_OK_DB;
03786         }
03787     }
03788 
03789     sSend(":%s NOTICE %s :Incorrect use of ADDMASK", NickServ, nick->nick);
03790     return RET_SYNTAX;
03791 }
03792 
03807 NCMD(ns_access)
03808 {
03809     char *from = nick->nick;
03810     nAccessList *acl;
03811     int idx;
03812 
03813     if (addFlood(nick, 2))
03814         return RET_KILLED;
03815 
03816     if (numargs < 2) {
03817         sSend(":%s NOTICE %s :Your access is %i",
03818               NickServ, nick->nick, nick->caccess);
03819         return RET_OK;
03820     }
03821 
03822     if (strcasecmp(args[1], "list") == 0) {
03823         if (numargs < 3) {
03824             if (!nick->reg) {
03825                 sSend(":%s NOTICE %s :Your nickname is not registered.",
03826                       NickServ, from);
03827                 return RET_FAIL;
03828             }
03829             if (!isIdentified(nick, nick->reg)) {
03830                 sSend(":%s NOTICE %s :You must identify "
03831                       "to get the access list", NickServ, from);
03832                 return RET_NOPERM;
03833             }
03834 
03835             if (LIST_FIRST(&nick->reg->acl) == NULL) {
03836                 sSend(":%s NOTICE %s :Access list for %s"
03837                       " is empty", NickServ, nick->nick, nick->nick);
03838                 return RET_OK;
03839             }
03840 
03841             sSend(":%s NOTICE %s :Access list for %s:",
03842                   NickServ, nick->nick, nick->nick);
03843 
03844             idx = 1;
03845             for (acl = LIST_FIRST(&nick->reg->acl); acl != NULL;
03846                  acl = LIST_NEXT(acl, al_lst)) {
03847                 sSend(":%s NOTICE %s :%2i:  %s",
03848                       NickServ, nick->nick, idx++, acl->mask);
03849             }
03850             sSend(":%s NOTICE %s :End of list for %s",
03851                   NickServ, nick->nick, nick->nick);
03852         } else {
03853             RegNickList *tmpnick;
03854 
03855             tmpnick = getRegNickData(args[2]);
03856 
03857             if (tmpnick == NULL) {
03858                 sSend(":%s NOTICE %s :%s is not registered",
03859                       NickServ, from, args[2]);
03860                 return RET_NOTARGET;
03861             }
03862 
03863             if (!isOper(nick) && !isIdentified(nick, tmpnick)) {
03864                 sSend(":%s NOTICE %s :Access denied to list for %s",
03865                       NickServ, nick->nick, args[2]);
03866                 return RET_NOPERM;
03867             }
03868 
03869             if (LIST_FIRST(&tmpnick->acl) == NULL) {
03870                 sSend(":%s NOTICE %s :Access list for %s"
03871                       " is empty", NickServ, nick->nick, tmpnick->nick);
03872                 return RET_OK;
03873             }
03874 
03875             sSend(":%s NOTICE %s :Access list for %s:",
03876                   NickServ, nick->nick, args[2]);
03877 
03878             idx = 1;
03879             for (acl = LIST_FIRST(&tmpnick->acl); acl != NULL;
03880                  acl = LIST_NEXT(acl, al_lst))
03881                 sSend(":%s NOTICE %s :%2i:  %s",
03882                       NickServ, nick->nick, idx++, acl->mask);
03883 
03884             sSend(":%s NOTICE %s :End of list for %s",
03885                   NickServ, nick->nick, args[2]);
03886         }
03887     } else if (strcasecmp(args[1], "add") == 0) {
03888         if (!nick->reg) {
03889             sSend(":%s NOTICE %s :Your nickname is not registered.",
03890                   NickServ, from);
03891             return RET_FAIL;
03892         }
03893         if (numargs < 3) {
03894             sSend(":%s NOTICE %s :You must specify a mask to add",
03895                   NickServ, nick->nick);
03896             return RET_SYNTAX;
03897         }
03898 
03899         addAccessMask(args[2], nick);
03900         return RET_OK_DB;
03901     } else if (strncasecmp(args[1], "del", 3) == 0) {
03902         /* also accepts delete */
03903         if (numargs < 3) {
03904             sSend(":%s NOTICE %s :You must specify a mask to delete",
03905                   NickServ, nick->nick);
03906             return RET_SYNTAX;
03907         }
03908 
03909         if (!nick->reg) {
03910             sSend(":%s NOTICE %s :Your nickname is not registered.",
03911                   NickServ, from);
03912             return RET_FAIL;
03913         }
03914 
03915         delAccessMask(args[2], nick);
03916         return RET_OK_DB;
03917     } else {
03918         UserList *info;
03919 
03920         info = getNickData(args[1]);
03921 
03922         if (info == NULL) {
03923             sSend(":%s NOTICE %s :%s is not online, access is \0020\002",
03924                   NickServ, nick->nick, args[1]);
03925             return RET_OK;
03926         } else {
03927             if (!isOper(nick) && nick != info)
03928                 sSend
03929                     (":%s NOTICE %s :Current access level for \002%s\002!%s@%s is \002%i\002",
03930                      NickServ, nick->nick, info->nick, info->user, genHostMask(info->host),
03931                      info->caccess);
03932             else
03933                 sSend
03934                     (":%s NOTICE %s :Current access level for \002%s\002!%s@%s is \002%i\002",
03935                      NickServ, nick->nick, info->nick, info->user, info->host,
03936                      info->caccess);
03937             return RET_OK;
03938         }
03939     }
03940     return RET_OK;
03941 }
03942 
03948 NCMD(ns_acc)
03949 {
03950     char *from = nick->nick;
03951     RegNickList *tmpnick;
03952 
03953     if (addFlood(nick, 2))
03954         return RET_KILLED;
03955 
03956     if (numargs < 2) {
03957         tmpnick = getRegNickData(from);
03958     } else {
03959         if (numargs < 3)
03960             tmpnick = getRegNickData(args[1]);
03961         else
03962             tmpnick = getRegNickData(args[2]);
03963     }
03964 
03965     {
03966         UserList *info;
03967         char *ustr;
03968         char *nstr;
03969 
03970         if (numargs >= 2)
03971             info = getNickData(args[1]);
03972         else
03973             info = nick;
03974         ustr = (numargs > 1) ? args[1] : from;
03975         nstr = (numargs > 2) ? args[2] : (numargs > 1) ? args[1] : from;
03976 
03977         if (!tmpnick) {
03978             if ((numargs > 2))
03979                 sSend(":%s NOTICE %s :%s -> %s ACC 0 (not registered)",
03980                       NickServ, nick->nick, ustr, nstr);
03981             else
03982                 sSend(":%s NOTICE %s :%s ACC 0 (not registered)",
03983                       NickServ, nick->nick, ustr);
03984             return RET_OK;
03985         } else if (info == NULL) {
03986             if ((numargs > 2))
03987                 sSend(":%s NOTICE %s :%s -> %s ACC 0 (offline)",
03988                       NickServ, nick->nick, args[1], nstr);
03989             else
03990                 sSend(":%s NOTICE %s :%s ACC 0 (offline)",
03991                       NickServ, nick->nick,
03992                       (numargs > 1) ? args[1] : from);
03993             return RET_OK;
03994         } else {
03995             if ((numargs > 2)) {
03996                 int cacc = 1;
03997 
03998                 if (isRecognized(info, tmpnick))
03999                     cacc = 2;
04000                 if (isIdentified(info, tmpnick))
04001                     cacc = 3;
04002                 if ((info->reg == tmpnick) && (info->caccess > 3))
04003                     cacc = info->caccess;
04004 
04005                 sSend(":%s NOTICE %s :%s -> %s ACC %i",
04006                       NickServ, nick->nick, ustr, nstr, cacc);
04007             } else
04008                 sSend(":%s NOTICE %s :%s ACC %i",
04009                       NickServ, nick->nick, info->nick, info->caccess);
04010         }
04011     }
04012     return RET_OK;
04013 }
04014 
04015 
04035 NCMD(ns_ghost)
04036 {
04037     RegNickList *tmp;
04038     UserList *taruser;
04039     char *from = nick->nick;
04040 
04041     if (addFlood(nick, 3))
04042         return RET_KILLED;
04043 
04044     if (numargs < 2) {
04045         sSend
04046             (":%s NOTICE %s :you must specify an argument after the GHOST command",
04047              NickServ, nick->nick);
04048         return RET_SYNTAX;
04049     }
04050 
04051 #ifndef ALLOW_GHOST_YOURSELF
04052     if (!strcasecmp(nick->nick, args[1])) {
04053         sSend(":%s NOTICE %s :You cannot ghost yourself", NickServ, from);
04054         return RET_EFAULT;
04055     }
04056 #endif
04057 
04058     if (getGhost(args[1])) {
04059         tmp = getRegNickData(args[1]);
04060         if (tmp == NULL) {
04061             sSend(":%s NOTICE %s :%s is not registered", NickServ, from,
04062                   args[1]);
04063             return RET_EFAULT;
04064         }
04065 
04066         if (Valid_pw(args[2], tmp->password, NickGetEnc(tmp)) ||
04067             ( !(tmp->flags & NIDENT) &&
04068               checkAccess(tmp->user, tmp->host, nick->reg) )
04069         )
04070         {
04071             sSend(":%s NOTICE %s :%s has been ghosted", NickServ,
04072                   nick->nick, args[1]);
04073             if (isGhost(args[1])) {
04074                 delGhost(args[1]);
04075             }
04076         }
04077         return RET_OK;
04078     }
04079 
04080 
04081     tmp = getRegNickData(args[1]);
04082     taruser = getNickData(args[1]);
04083 
04084     if (tmp != NULL)
04085         if (checkAccess(nick->user, nick->host, tmp)
04086             || Valid_pw(args[2], tmp->password, NickGetEnc(tmp))) {
04087             taruser = getNickData(args[1]);
04088 
04089             if (!taruser && (getGhost(args[1]) == NULL)) {
04090                 sSend(":%s NOTICE %s :%s is not online.", NickServ,
04091                       nick->nick, args[1]);
04092             }
04093 
04094             if (!taruser)
04095                 sSend(":%s KILL %s :%s!%s (Ghosted. By: %s (%s@%s)", NickServ,
04096                       args[1], services[1].host, NickServ, nick->nick, nick->user, nick->host);
04097             else {
04098                 if (strcmp(nick->host, taruser->host))
04099                     sSend(":%s KILL %s :%s!%s (Ghosted. By: %s (%s@%s))",
04100                           NickServ, args[1], services[1].host, NickServ,
04101                           nick->nick, nick->user,
04102                           (nick->oflags & NOISMASK) ? genHostMask(nick->
04103                                                                   host) :
04104                           nick->host);
04105                 else
04106                     sSend(":%s KILL %s :%s!%s (Ghosted. By: %s)", NickServ,
04107                           args[1], services[1].host, NickServ, nick->nick);
04108 
04109             }
04110 
04111             sSend(":%s NOTICE %s :Removing ghost, '%s'", NickServ,
04112                   nick->nick, args[1]);
04113             remUser(args[1], 1);
04114             if (isGhost(args[1])) {
04115                 delGhost(args[1]);
04116             }
04117             return RET_OK;
04118         } else if ((tmp == NULL)) {
04119             sSend(":%s NOTICE %s :%s is not registered.", NickServ,
04120                   nick->nick, args[1]);
04121             return RET_EFAULT;
04122         } else {
04123             PutReply(NickServ, nick, ERR_NOACCESS, 0, 0, 0);
04124             return RET_NOPERM;
04125         }
04126     return RET_FAIL;
04127 }
04128 
04129 
04145 NCMD(ns_recover)
04146 {
04147     RegNickList *tmp;
04148     UserList *taruser;
04149     char *from = nick->nick;
04150 
04151     if (addFlood(nick, 3))
04152         return RET_KILLED;
04153 
04154     if (numargs < 2) {
04155         sSend
04156             (":%s NOTICE %s :you must specify an argument after the RECOVER command",
04157              NickServ, nick->nick);
04158         return RET_SYNTAX;
04159     }
04160 
04161 
04162     if (!strcasecmp(nick->nick, args[1])) {
04163         sSend(":%s NOTICE %s :You are already using the nickname.", NickServ, from);
04164         return RET_EFAULT;
04165     }
04166 
04167     tmp = getRegNickData(args[1]);
04168     if (tmp == 0) {
04169         PutReply(NickServ, nick, ERR_NICKNOTREG_1ARG, args[1], 0, 0);
04170         return RET_EFAULT;
04171     }
04172     
04173     
04174     if (numargs >= 3)
04175     {
04176         struct auth_data auth_info[] = {{
04177             nick->auth_cookie,
04178             nick->idnum.getHashKey(),
04179             2
04180         }};
04181         
04182         if (isMD5Key(args[2]))
04183         {
04184             if (!Valid_md5key(args[2], auth_info, tmp->nick, tmp->password, NickGetEnc(tmp))) 
04185             {
04186                 sSend(":%s NOTICE %s :Invalid MD5 key.", NickServ, nick->nick);
04187                 nick->auth_cookie = 0;
04188                              if (BadPwNick(nick, tmp))
04189                                      return RET_KILLED;
04190 
04191                 return RET_BADPW;
04192             }
04193             nick->auth_cookie = 0;
04194         }
04195         else if (!Valid_pw(args[2], tmp->password, NickGetEnc(tmp))) {
04196             PutReply(NickServ, nick, ERR_BADPW_NICK_1ARG, args[1], 0, 0);
04197                         if (BadPwNick(nick, tmp))
04198                                 return RET_KILLED;
04199 
04200             return RET_BADPW;
04201         }
04202     }
04203 
04204 #ifndef ALLOW_PASSLESS_RECOVER
04205     if (numargs < 3) {
04206 #else
04207     if ((numargs < 3) && !isFullyRecognized(nick, tmp))
04208 #endif
04209         sSend(":%s NOTICE %s :Permission denied: you will need to specify a password.", NickServ, nick->nick);
04210         PutHelpInfo(NickServ, nick, "HELP RECOVER");
04211         return RET_NOPERM;
04212     }
04213     
04214 
04215     if (isGhost(args[1])) {
04216         sSend(":%s NOTICE %s :%s is currently held by a %s enforcer.", NickServ,
04217               nick->nick, args[1], NickServ);
04218         PutHelpInfo(NickServ, nick, "HELP RELEASE");
04219         return RET_EFAULT;
04220     }
04221 
04222 
04223     if (getGhost(args[1])) {
04224         return RET_OK;
04225     }
04226 
04227     taruser = getNickData(args[1]);
04228 
04229     if (taruser == 0) {
04230         sSend(":%s NOTICE %s :%s is not currently in use.", NickServ,
04231               nick->nick, args[1]);
04232         return RET_NOTARGET;
04233     }
04234 
04235     enforce_nickname (taruser->nick);
04236     sSend(":%s NOTICE %s :Recovering nickname, '%s'", NickServ,
04237           nick->nick, args[1]);
04238     return RET_OK;
04239 }
04240 
04241 
04247 NCMD(ns_release)
04248 {
04249 
04250     char *from = nick->nick;
04251     RegNickList *tmp;
04252 
04253     if (addFlood(nick, 1))
04254         return RET_KILLED;
04255 
04256     if (numargs < 2) {
04257         sSend
04258             (":%s NOTICE %s :You must specify a registered nick and its password after the RELEASE command",
04259              NickServ, from);
04260         return RET_NOTARGET;
04261     }
04262     if (numargs < 3) {
04263         sSend
04264             (":%s NOTICE %s :You must specify the nick's password after the specifed nick",
04265              NickServ, from);
04266         return RET_SYNTAX;
04267     }
04268 
04269     if (isGhost(args[1])) {
04270         tmp = getRegNickData(args[1]);
04271         /* I don't know if this is more readable -- but it helped me */
04272 
04273         if (tmp == NULL) {
04274             sSend(":%s NOTICE %s :The nick %s is not registered.",
04275                   NickServ, from, args[1]);
04276             return RET_NOTARGET;
04277         }
04278 
04279         if ((numargs >= 3) && !Valid_pw(args[2], tmp->password, NickGetEnc(tmp))) {
04280             PutReply(NickServ, nick, ERR_BADPW, 0, 0, 0);
04281             if (BadPwNick(nick, tmp))
04282                 return RET_KILLED;
04283 
04284             return RET_BADPW;
04285         }
04286         else if ((numargs < 3)
04287              && !checkAccess(nick->user, nick->host, tmp)) {
04288             PutReply(NickServ, nick, ERR_NOACCESS, 0, 0, 0);
04289             return RET_NOPERM;
04290         }
04291         else
04292             GoodPwNick(nick, tmp);
04293 
04294         if ((tmp != NULL)) {
04295             if (isGhost(args[1])) {
04296                 delGhost(args[1]);
04297             }
04298             sSend(":%s NOTICE %s :The nick %s has been released",
04299                   NickServ, from, args[1]);
04300         }
04301         return RET_OK;
04302     }
04303 
04304     sSend(":%s NOTICE %s :Services are not currently holding that nick.",
04305           NickServ, from);
04306     return RET_NOTARGET;
04307 }
04308 
04309 
04310 /************************************************************************
04311 * Operator flag system                                                  *
04312 * Nsetopflagscmd()   Change Operator Flags                      -Mysid  *
04313 ************************************************************************/
04314 
04328 
04329 NCMD(ns_setopflags)
04330 {
04331     char *from = nick->nick;
04332     char modebuf[IRCBUF] = "";
04333     char totbuf[IRCBUF] = "";
04334     RegNickList *regnick;
04335     int mode = 1;
04336     flag_t setflags, thisflag;
04337     u_int i, j, x;
04338 
04339     if (isOper(nick) && (numargs < 2)) {
04340         sSend(":%s NOTICE %s :\2Your flag status\2:", OperServ, from);
04341         for (i = 0; opflags[i].symbol; i++) {
04342             if (opflags[i].symbol == 'A' || opflags[i].symbol == '*')
04343                 continue;
04344             j = opFlagged(nick, opflags[i].flag);
04345             sSend(":%s NOTICE %s :%c (%-15s)   : %s", OperServ, from,
04346                   opflags[i].symbol, opflags[i].name, j ? "YES" : "NO ");
04347         }
04348         if (addFlood(nick, 15))
04349             return RET_KILLED;
04350         return RET_OK;
04351     }
04352 
04353     if (addFlood(nick, 1))
04354         return RET_KILLED;
04355     if (!opFlagged(nick, OOPER)) {
04356         sSend
04357             (":%s NOTICE %s :You must be an IRC Operator to use this command.",
04358              OperServ, from);
04359         return RET_NOPERM;
04360     }
04361 
04362     if (numargs < 2) {
04363         sSend(":%s NOTICE %s :You must specify a nick.", OperServ, from);
04364         return RET_SYNTAX;
04365     } else if (!strcasecmp(args[1], "list")) {
04366         OperList *oper;
04367 
04368         for (oper = firstOper; oper; oper = oper->next)
04369             if (oper->who) {
04370                 for (x = 0, j = 0; opflags[j].symbol; j++)
04371                     if ((oper->who->opflags & opflags[j].flag)) {
04372                         if (opflags[j].symbol == '*')
04373                             continue;
04374                         if (!x)
04375                             modebuf[x++] = '+';
04376                         modebuf[x++] = opflags[j].symbol;
04377                     }
04378                 modebuf[x++] = '\0';
04379                 if (!(oper->who->opflags & OROOT))
04380                     sSend(":%s NOTICE %s :%-17s  (\37%-20s\37)", OperServ,
04381                           from, oper->who->nick, modebuf);
04382                 else
04383                     sSend
04384                         (":%s NOTICE %s :%-17s  (\2Root                \2)",
04385                          OperServ, from, oper->who->nick);
04386             }
04387         return RET_OK;
04388     } else if (!strcasecmp(args[1], "add")) {
04389         if (opFlagged(nick, OSETOP | OOPER) == 0) {
04390             PutReply(OperServ, nick, ERR_NOACCESS, 0, 0, 0);
04391             return RET_NOPERM;
04392         }
04393         if (numargs < 3) {
04394             sSend(":%s NOTICE %s :Add opflags to what nick?", OperServ,
04395                   from);
04396             return RET_NOPERM;
04397         }
04398         if (!(regnick = getRegNickData(args[2]))) {
04399             sSend(":%s NOTICE %s :The nick %s is not registered.",
04400                   OperServ, from, args[2]);
04401             return RET_EFAULT;
04402         }
04403         if (regnick->opflags) {
04404             sSend(":%s NOTICE %s :%s already has opflags.", NickServ, from,
04405                   args[2]);
04406             return RET_FAIL;
04407         }
04408         regnick->opflags |= OPFLAG_DEFAULT;
04409         addOpData(regnick);
04410         return RET_OK_DB;
04411     } else if (!strcasecmp(args[1], "del")) {
04412         if (opFlagged(nick, OSETOP | OOPER) == 0) {
04413             PutReply(OperServ, nick, ERR_NOACCESS, 0, 0, 0);
04414             return RET_NOPERM;
04415         }
04416         if (numargs < 3) {
04417             sSend(":%s NOTICE %s :Del opflags from what nick?", OperServ,
04418                   from);
04419             return RET_SYNTAX;
04420         }
04421         if (!(regnick = getRegNickData(args[2]))) {
04422             sSend(":%s NOTICE %s :The nick %s is not registered.",
04423                   OperServ, from, args[2]);
04424             return RET_EFAULT;
04425         }
04426         if (!regnick->opflags) {
04427             sSend(":%s NOTICE %s :%s has no opflags.", OperServ, from,
04428                   args[2]);
04429             return RET_EFAULT;
04430         }
04431         if ((regnick->opflags & (OROOT | OREMROOT))
04432             || ((regnick->opflags & (OPFLAG_ROOTSET))
04433                 && !opFlagged(nick, OOPER | OROOT))) {
04434             sSend
04435                 (":%s NOTICE %s :%s holds one or more flags that you cannot remove.",
04436                  NickServ, from, args[2]);
04437             return RET_EFAULT;
04438         }
04439         regnick->opflags = 0;
04440         delOpData(regnick);
04441         return RET_OK_DB;
04442     }
04443 
04444     if (!(regnick = getRegNickData(args[1]))) {
04445         sSend(":%s NOTICE %s :%s is not registered", OperServ, from,
04446               args[1]);
04447         return RET_EFAULT;
04448     }
04449 
04450     if (numargs < 3) {
04451         for (x = 0, j = 0; opflags[j].symbol; j++)
04452             if ((regnick->opflags & opflags[j].flag)) {
04453                 if (opflags[j].symbol == '*')
04454                     continue;
04455                 if (!x)
04456                     modebuf[x++] = '+';
04457                 modebuf[x++] = opflags[j].symbol;
04458             }
04459         modebuf[x++] = '\0';
04460         sSend(":%s NOTICE %s :Current opflags of user %s are %s.",
04461               OperServ, from, args[1], modebuf);
04462         return RET_OK;
04463     }
04464 
04465     if (!opFlagged(nick, OSETOP | OOPER)) {
04466         PutReply(OperServ, nick, ERR_NOACCESS, 0, 0, 0);
04467         return RET_NOPERM;
04468     }
04469 
04470     if (!opFlagged(nick, OOPER | OROOT)
04471         && (regnick->opflags & (OROOT | OPROT))) {
04472         sSend(":%s NOTICE %s :You cannot alter the opflags of %s.",
04473               OperServ, from, args[1]);
04474         return RET_NOPERM;
04475     }
04476 
04477     setflags = regnick->opflags;
04478 
04479     for (i = 0; args[2] && args[2][i]; i++) {
04480         switch (args[2][i]) {
04481         case '+':
04482             mode = 1;
04483             break;
04484         case '-':
04485             mode = 0;
04486             break;
04487         default:
04488             for (j = 0; opflags[j].symbol; j++)
04489                 if (opflags[j].symbol == args[2][i]) {
04490                     thisflag = opflags[j].flag;
04491 
04492                     if (mode) {
04493                         if (thisflag & OADMIN)
04494                             thisflag |= OPFLAG_ADMIN;
04495                         if (thisflag & OOPER)
04496                             thisflag |= OPFLAG_DEFAULT;
04497                         thisflag &= ~OADMIN;
04498                         if (mode && (thisflag & OSERVOP))
04499                             sSend
04500                                 (":%s NOTICE %s :Note: the servop opflag is deprecate.",
04501                                  OperServ, from);
04502                     }
04503 
04504                     /* flag permissions check */
04505                     if (!isRoot(nick)
04506                         && (OPFLAG_ROOTSET & opflags[j].flag)) {
04507                         sSend
04508                             (":%s NOTICE %s :Setting the flag '%c' requires root access.",
04509                              OperServ, from,
04510                              opflags[j].symbol ? opflags[j].symbol : ' ');
04511                         continue;
04512                     }
04513                     if (opflags[j].flag & (OROOT | OREMROOT)) {
04514                         sSend
04515                             (":%s NOTICE %s :SETOP cannot change this flag.",
04516                              OperServ, from);
04517                         continue;
04518                     }
04519                     if (mode)
04520                         regnick->opflags |= thisflag;
04521                     else
04522                         regnick->opflags &= ~thisflag;
04523                 }
04524             break;
04525         }
04526     }
04527     for (x = 0, j = 0; opflags[j].symbol; j++)
04528         if (!(setflags & opflags[j].flag) &&
04529             (regnick->opflags & opflags[j].flag)) {
04530             if (opflags[j].symbol == '*')
04531                 continue;
04532             if (!x)
04533                 modebuf[x++] = '+';
04534             modebuf[x++] = opflags[j].symbol;
04535         }
04536     for (mode = 0, j = 0; opflags[j].symbol; j++)
04537         if ((setflags & opflags[j].flag) &&
04538             !(regnick->opflags & opflags[j].flag)) {
04539             if (opflags[j].symbol == '*')
04540                 continue;
04541             if (!mode) {
04542                 modebuf[x++] = '-';
04543                 mode++;
04544             }
04545             modebuf[x++] = opflags[j].symbol;
04546         }
04547     modebuf[x++] = '\0';
04548     for (x = 0, j = 0; opflags[j].symbol; j++)
04549         if ((regnick->opflags & opflags[j].flag)) {
04550             if (opflags[j].symbol == '*')
04551                 continue;
04552             if (!x)
04553                 totbuf[x++] = '+';
04554             totbuf[x++] = opflags[j].symbol;
04555         }
04556     totbuf[x++] = '\0';
04557     if (*modebuf && nick->reg && nick->reg != regnick)
04558         sSend(":%s GLOBOPS :%s set opflags %s on user %s.", OperServ, from,
04559               modebuf, regnick->nick);
04560     operlog->log(nick, NS_SETOP, regnick->nick, 0, "%s (%s)", modebuf,
04561                  totbuf);
04562     sSend(":%s NOTICE %s :Opflags for user \2%s\2 are now \2%s\2.",
04563           OperServ, from, regnick->nick, totbuf);
04564     if (regnick->opflags && !setflags)
04565         addOpData(regnick);
04566     else if (setflags && !regnick->opflags)
04567         delOpData(regnick);
04568     return RET_OK_DB;
04569 }
04570 
04571 
04572 /**************************************************************************/
04573 
04586 NCMD(ns_mark)
04587 {
04588     char *from = nick->nick;
04589     RegNickList *target;
04590 
04591     if (isServop(nick) == 0) {
04592         PutReply(NickServ, nick, ERR_NOACCESS, 0, 0, 0);
04593         return RET_NOPERM;
04594     }
04595 
04596     if (numargs < 2) {
04597         sSend(":%s NOTICE %s :Must supply at least one argument",
04598               NickServ, from);
04599         return RET_SYNTAX;
04600     }
04601 
04602     target = getRegNickData(args[1]);
04603     if (target == NULL) {
04604         sSend(":%s NOTICE %s :Nick not found", NickServ, from);
04605         return RET_EFAULT;
04606     }
04607     if (numargs < 3) {
04608         if (!target->markby)
04609             sSend(":%s NOTICE %s :%s is \2%s\2.", NickServ, from, args[1],
04610                   target->flags & NMARK ? "Marked" : "Not Marked");
04611         else if (target->flags & NMARK)
04612             sSend(":%s NOTICE %s :%s was \2%s\2 by %s.", NickServ, from,
04613                   args[1], target->flags & NMARK ? "Marked" : "Not Marked",
04614                   target->markby);
04615         return RET_OK;
04616     }
04617     if (!strcasecmp(args[2], "on") || !strcasecmp(args[2], "yes")) {
04618         if (target->flags & NMARK) {
04619             sSend(":%s NOTICE %s :%s is already marked%s%s.", NickServ,
04620                   from, args[1], target->markby ? " by " : "",
04621                   target->markby ? target->markby : "");
04622             return RET_OK;
04623         }
04624         sSend(":%s NOTICE %s :%s is now \2Marked\2.", NickServ, from,
04625               args[1]);
04626         target->flags |= NMARK;
04627         if (target->markby)
04628             FREE(target->markby);
04629         target->markby = strdup(nick->nick);
04630         nicklog->log(nick, NS_MARK, target->nick, LOGF_ON);
04631         return RET_OK_DB;
04632     } else if (!strcasecmp(args[2], "off") || !strcasecmp(args[2], "no")) {
04633         sSend(":%s NOTICE %s :%s is now \2Unmarked\2.", NickServ, from,
04634               args[1]);
04635         target->flags &= ~NMARK;
04636         if (target->markby)
04637             FREE(target->markby);
04638         target->markby = NULL;
04639         nicklog->log(nick, NS_MARK, target->nick, LOGF_OFF);
04640         return RET_OK_DB;
04641     } else {
04642         sSend(":%s NOTICE %s :Unrecognized usage.", NickServ, from);
04643         sSend(":%s NOTICE %s :MARK <nick> <on|off>", NickServ, from);
04644         return RET_OK;
04645     }
04646     return RET_FAIL;
04647 }
04648 
04649 
04650 /**************************************************************************/
04651 
04657 NCMD(ns_setflags)
04658 {
04659     char *from = nick->nick;
04660     RegNickList *regnick;
04661     int mode = 1;
04662     u_int i;
04663 
04664     if (addFlood(nick, 1))
04665         return RET_KILLED;
04666 
04667     if (opFlagged(nick, OOPER | OSETFLAG) == 0 && isRoot(nick) == 0) {
04668         PutReply(NickServ, nick, ERR_NOACCESS, 0, 0, 0);
04669         return RET_NOPERM;
04670     }
04671 
04672     else if (numargs < 3) {
04673         sSend(":%s NOTICE %s :You must specify at least 2"
04674               " parameters after setflags", NickServ, from);
04675         return RET_SYNTAX;
04676     }
04677 
04678     regnick = getRegNickData(args[1]);
04679     if (regnick == NULL) {
04680         sSend(":%s NOTICE %s :%s is not registered",
04681               NickServ, from, args[1]);
04682         return RET_EFAULT;
04683     }
04684     if (isRoot(nick) == 0 && (regnick->opflags & OROOT)) {
04685         sSend
04686             (":%s NOTICE %s :Permission denied -- in altering flags of %s.",
04687              NickServ, from, args[1]);
04688         return RET_NOPERM;
04689     }
04690 
04691     sSend(":%s NOTICE %s :Flags for %s are now %s",
04692           NickServ, from, args[1], args[2]);
04693     sSend(":%s GLOBOPS :%s set mode %s on %s",
04694           myname, from, args[2], args[1]);
04695     operlog->log(nick, NS_SETFLAG, args[1], 0, "%s", args[2]);
04696 
04697     for (i = 0; i < strlen(args[2]); i++) {
04698         switch (args[2][i]) {
04699         case '+':
04700             mode = 1;
04701             break;
04702         case '-':
04703             mode = 0;
04704             break;
04705         case 'k':
04706             if (mode)
04707                 regnick->flags |= NKILL;
04708             else
04709                 regnick->flags &= ~NKILL;
04710             break;
04711         case 'v':
04712             if (mode)
04713                 regnick->flags |= NVACATION;
04714             else
04715                 regnick->flags &= ~NVACATION;
04716             break;
04717         case 'f':
04718             if (mode && !(regnick->opflags & OROOT))
04719                 regnick->flags |= NFORCEXFER;
04720             else
04721                 regnick->flags &= ~NFORCEXFER;
04722             break;
04723         case 'e':
04724             if (mode)
04725                 regnick->flags |= NEMAIL;
04726             else
04727                 regnick->flags &= ~NEMAIL;
04728         case 'h':
04729             if (isRoot(nick) == 0)
04730                 sSend(":%s NOTICE %s :You cannot set the 'h' flag",
04731                       NickServ, from);
04732             else if (mode)
04733                 regnick->flags |= NHOLD;
04734             else
04735                 regnick->flags &= ~NHOLD;
04736             break;
04737         case 'b':
04738             if (mode)
04739                 regnick->flags |= NBANISH;
04740             else
04741                 regnick->flags &= ~NBANISH;
04742             break;
04743         case 'g':
04744             if (isRoot(nick) == 0)
04745                 sSend(":%s NOTICE %s :You cannot set the 'g' flag",
04746                       NickServ, from);
04747             else if (mode)
04748                 regnick->opflags |= OGRP;
04749             else
04750                 regnick->opflags &= ~OGRP;
04751             break;
04752         case 's':
04753             if (isRoot(nick) == 0)
04754                 sSend(":%s NOTICE %s :You cannot set the 's' flag",
04755                       NickServ, from);
04756             else if (mode)
04757                 regnick->opflags |= OSERVOP;
04758             else
04759                 regnick->opflags &= ~OSERVOP;
04760             break;
04761         case 'B':
04762             if (opFlagged(nick, OAKILL) == 0)
04763                 sSend(":%s NOTICE %s :You cannot set the 'o' flag",
04764                       NickServ, from);
04765             else if (mode)
04766                 regnick->flags |= NBYPASS;
04767             else
04768                 regnick->flags &= ~NBYPASS;
04769             break;
04770         default:
04771             sSend(":%s NOTICE %s :Unknown mode flag: %c", NickServ, from,
04772                   args[2][i]);
04773             break;
04774         }
04775     }
04776     return RET_OK_DB;
04777 }
04778 
04784 NCMD(ns_banish)
04785 {
04786 
04787     char *from = nick->nick;
04788     char buf[IRCBUF];
04789     RegNickList *bannick;
04790 
04791     if (addFlood(nick, 1))
04792         return RET_KILLED;
04793 
04794     if (opFlagged(nick, OOPER | ONBANDEL) == 0) {
04795         PutReply(NickServ, nick, ERR_NOACCESS, 0, 0, 0);
04796         return RET_NOPERM;
04797     }
04798 
04799     if (numargs < 2) {
04800         sSend
04801             (":%s NOTICE %s :You must specify an argument after the banish command",
04802              NickServ, from);
04803         return RET_SYNTAX;
04804     }
04805 
04806     bannick = getRegNickData(args[1]);
04807 
04808     if (bannick == NULL) {
04809         bannick = (RegNickList *) oalloc(sizeof(RegNickList));
04810         strncpyzt(bannick->nick, args[1], NICKLEN);
04811         bannick->regnum.SetNext(top_regnick_idnum);
04812 
04813         addRegNick(bannick);
04814     } else if (isRoot(nick) == 0 && (bannick->opflags & OROOT)) {
04815         sSend(":%s NOTICE %s :Permission denied.", NickServ, from);
04816         return RET_NOPERM;
04817     }
04818 
04819     strncpyzt(bannick->nick, args[1], NICKLEN);
04820 /* #warning XXX This assumes details of RegNickList */
04821     strcpy(bannick->user, "banished");
04822 
04823     snprintf(buf, HOSTLEN, "nicks.%s", NETWORK);
04824     SetDynBuffer(&bannick->host, buf);
04825 
04826     snprintf(bannick->email, EMAILLEN, "nickserv@%s", NETWORK);
04827 
04828     snprintf(buf, URLLEN, "http://www.%s", NETWORK);    /* sprintf is safe */
04829     SetDynBuffer(&bannick->url, buf);
04830 
04831     memset(bannick->password, 0, PASSLEN);
04832     bannick->amasks = 0;
04833     bannick->timereg = 0;
04834     bannick->timestamp = 0;
04835     bannick->flags = 0;
04836     bannick->flags |= NBANISH|NENCRYPT;
04837 
04838     /*
04839      * destroy all access list items
04840      */
04841     while (LIST_FIRST(&bannick->acl))
04842         LIST_REMOVE(LIST_FIRST(&bannick->acl), al_lst);
04843 
04844     sSend(":%s GNOTICE :%s Banished nick %s", myname, from, args[1]);
04845     operlog->log(nick, NS_BANISH, args[1]);
04846     return RET_OK_DB;
04847 }
04848 
04849 #ifdef REQ_EMAIL
04850 NCMD(ns_getkey)
04851 {
04852     char *from = nick->nick;
04853     RegNickList *regnick;
04854 
04855     if(addFlood(nick,5))
04856         return;
04857 
04858     if (numargs<2) {
04859         sSend(":%s NOTICE %s :You must specify a nick to getkey", NickServ, from);
04860         return;
04861     }
04862 
04863     if (!isRoot(nick)) {
04864         sSend(":%s NOTICE %s :Access denied", NickServ, from);
04865         return;
04866     }
04867 
04868     regnick=getRegNickData(args[1]);
04869 
04870     if(!regnick || !(regnick->flags & NREG))
04871         sSend(":%s NOTICE %s :Nick %s is not registered", NickServ, from, args[1]);
04872         else {
04873         sSend(":%s NOTICE %s :The activation code for %s is %lu", NickServ, from, regnick->nick, regnick->email_key);
04874         sSend(":%s GNOTICE :%s used getkey on %s", myname, from, args[1]);
04875     }
04876     return;
04877 }
04878 #endif
04879 
04884 NCMD(ns_getrealpass)
04885 {
04886     char *from = nick->nick;
04887     RegNickList *targetNick;
04888 
04889     if (addFlood(nick, 5))
04890         return RET_KILLED;
04891 
04892     if (numargs < 2) {
04893         sSend(":%s NOTICE %s :You must specify a nick to getrealpass",
04894               NickServ, from);
04895         return RET_SYNTAX;
04896     }
04897 #ifdef ENABLE_GRPOPS
04898     if (isRoot(nick) == 0 && isGRPop(nick) == 0)
04899 #else
04900     if (isRoot(nick) == 0)
04901 #endif
04902     {
04903         PutReply(NickServ, nick, ERR_NOACCESS, 0, 0, 0);
04904         return RET_NOPERM;
04905     }
04906 
04907     sSend(":%s NOTICE %s :Warning -- this command is deprecated.",
04908           NickServ, from);
04909 
04910     targetNick = getRegNickData(args[1]);
04911 
04912     if (targetNick == NULL)
04913         sSend(":%s NOTICE %s :Nick %s is not registered", NickServ, from,
04914               args[1]);
04915     else if (targetNick->flags & NMARK) {
04916         if (targetNick->markby)
04917             sSend
04918                 (":%s NOTICE %s :\2Important Note:\2 %s has been marked by %s -- you need to contact the setter before retrieving the password for the nick in question.",
04919                  NickServ, from, targetNick->nick, targetNick->markby);
04920         else
04921             sSend(":%s NOTICE %s :\2Important Note:\2 %s has been marked.",
04922                   NickServ, from, targetNick->nick);
04923         return RET_OK;
04924     }
04925         else if (!opFlagged(nick, OROOT | OVERRIDE)
04926                  && (targetNick->flags & NOSENDPASS)) {
04927         sSend
04928             (":%s NOTICE %s :Nick %s has enabled the \2NOPWSEND\2 option.",
04929              NickServ, from, args[1]);
04930         return RET_EFAULT;
04931     }
04932         else if ((!isRoot(nick) && (targetNick->opflags & OROOT))
04933                  || (!isServop(nick) && (targetNick->opflags & OSERVOP))) {
04934         sSend
04935             (":%s NOTICE %s :Permission denied -- a GRPop may not GRP a user with root or servop privileges.",
04936              NickServ, from);
04937         sSend(":%s GLOBOPS :%s!%s@%s tries to getrealpass \2%s\2.",
04938               NickServ, from, nick->user, nick->host, args[1]);
04939         operlog->log(nick, NS_GETREALPASS, args[1], RET_FAIL);
04940         return RET_NOPERM;
04941     } else {
04942         if (!(targetNick->flags & NENCRYPT))
04943             sSend(":%s NOTICE %s :The password for %s is %s", NickServ, from,
04944                   targetNick->nick, targetNick->password);
04945         else {
04946             u_char *p;
04947 
04948             sSend(":%s NOTICE %s :The password for %s is encrypted: %s", NickServ, from,
04949                   targetNick->nick, md5_printable(targetNick->password));
04950             p = toBase64(targetNick->password, 16);
04951             if (p != NULL) {
04952                 sSend(":%s NOTICE %s :In Base64 format that is: $%s", NickServ, from,
04953                       p);
04954                 FREE(p);
04955             }
04956         }
04957         sSend(":%s GLOBOPS :%s used getrealpass on %s", myname, from,
04958               args[1]);
04959         operlog->log(nick, NS_GETREALPASS, args[1], 0);
04960     }
04961     return RET_OK;
04962 }
04963 
04971 NCMD(ns_getpass)
04972 {
04973     char buf[MAXBUF];
04974     char *from = nick->nick;
04975     RegNickList *targetNick;
04976     EmailMessage *email;
04977     const char *pwAuthKey;
04978     time_t doot = time(NULL);
04979     int key_new, key_resend, key_transfer, i, nick_arg = 1;
04980 
04981     key_new = key_resend = key_transfer = 0;
04982     srand48(time(NULL));
04983 
04984     if (addFlood(nick, 5))
04985         return RET_KILLED;
04986 
04987     if ((isOper(nick) == 0) && (isHelpop(nick) == 0)) {
04988         PutReply(NickServ, nick, ERR_NOACCESS, 0, 0, 0);
04989         return RET_NOPERM;
04990     }
04991 
04992     if (numargs < 2) {
04993         sSend(":%s NOTICE %s :You must specify a nick to getpass",
04994               NickServ, from);
04995         return RET_SYNTAX;
04996     }
04997 
04998     if (numargs >= 3) {
04999         for(i = 2; i < numargs; i++)
05000         {
05001             if (*args[i] == '-')
05002             {
05003                 if (!strcmp(args[i], "-new") && isOper(nick))
05004                     key_new = 1;
05005                 else if (!strcmp(args[i], "-resend"))
05006                     key_resend = 1;
05007                 else if (opFlagged(nick, OGRP) && !strcmp(args[i], "-transfer"))
05008                     key_transfer = 1;
05009                 else if (args[i][1] == '-') {
05010                     break;
05011                 }
05012                 else
05013                     continue;
05014             }
05015             else {
05016                 break;
05017             }
05018         }
05019     }
05020 
05021     targetNick = getRegNickData(args[nick_arg]);
05022 
05023     if (targetNick == NULL) {
05024         sSend(":%s NOTICE %s :Nick %s is not registered", NickServ, from,
05025               args[nick_arg]);
05026         return RET_EFAULT;
05027     }
05028     if (!key_transfer && (strncmp(targetNick->email, "(none)", 6) == 0
05029         || targetNick->email[0] == 0)) {
05030         sSend(":%s NOTICE %s :Nick %s has not specified an e-mail address",
05031               NickServ, from, args[nick_arg]);
05032         return RET_EFAULT;
05033     }
05034     else if (!opFlagged(nick, OVERRIDE) && !key_transfer
05035          && (targetNick->flags & NOSENDPASS)) {
05036         sSend
05037         (":%s NOTICE %s :Warning: nick %s has enabled the \2NOPWSEND\2 option.",
05038          NickServ, from, args[nick_arg]);
05039         return RET_EFAULT;
05040     } else if (targetNick->chpw_key && !key_new && !key_resend) {
05041         sSend(":%s NOTICE %s :That nickname has already had a change "
05042               "key sent out.  Please specify -new or -resend.",
05043               NickServ, from);
05044     } else if ((key_transfer || (targetNick->flags & NFORCEXFER)) && (!(targetNick->opflags & OROOT))) {
05045         if (!targetNick->chpw_key || !(targetNick->flags & NFORCEXFER))
05046         {
05047             targetNick->chpw_key = (u_int32_t)(lrand48());
05048             if (!targetNick->chpw_key)
05049                 targetNick->chpw_key = 1;
05050         }
05051 
05052         pwAuthKey = GetAuthChKey("-forced-transfer-",
05053                                  PrintPass(targetNick->password, NickGetEnc(targetNick)),
05054                                  targetNick->timereg,
05055                                  targetNick->chpw_key);
05056 
05057         if (key_transfer)
05058             sSend(":%s GLOBOPS :%s used sendpass (transfer) on %s",
05059                   ChanServ, from, args[nick_arg]);
05060         else
05061             sSend(":%s GLOBOPS :%s used sendpass (getkey) on %s",
05062                   ChanServ, from, args[nick_arg]);
05063         sSend(":%s NOTICE %s :Transfer key for %s is %s",
05064               ChanServ, from, args[nick_arg], pwAuthKey);
05065         targetNick->flags |= NFORCEXFER;
05066         operlog->log(nick, NSS_GETPASS_XFER, args[nick_arg]);
05067     } else if ((targetNick->flags & NFORCEXFER) && targetNick->chpw_key && !opFlagged(nick, OGRP | OOPER | OVERRIDE)) {
05068         sSend(":%s NOTICE %s :This nick's pw key is marked for ``nick transfer''",
05069               NickServ, from);
05070     } else {
05071         email = new EmailMessage;
05072 
05073         if (!email) {
05074             sSend(":%s WALLOPS :Fatal error: ns_sendpass: out of memory",
05075                   NickServ);
05076             sSend(":%s NOTICE %s :Fatal error: ns_sendpass: out of memory",
05077                   NickServ, from);
05078             abort();
05079             return RET_EFAULT;
05080         }
05081 
05082         if (key_new || !key_resend || !targetNick->chpw_key) {
05083             targetNick->chpw_key = (u_int32_t)(lrand48());
05084             if (!targetNick->chpw_key)
05085                 targetNick->chpw_key = 1;
05086         }
05087 
05088         pwAuthKey = GetAuthChKey(targetNick->email,
05089                                  PrintPass(targetNick->password, NickGetEnc(targetNick)),
05090                                  targetNick->timereg,
05091                                  targetNick->chpw_key);
05092 
05093         sSend(":%s GNOTICE :%s used sendpass%s on %s", myname, from,
05094               key_resend ? " (resend)" : "", args[nick_arg]);
05095         if (isOper(nick) == 0)
05096             sSend
05097                 (":%s NOTICE %s :The \2password change key\2 has been sent to the email address: (hidden)",
05098                  NickServ, from);
05099         else
05100             sSend
05101                 (":%s NOTICE %s :The \2password change key\2 has been sent to the email address: %s",
05102                  NickServ, from, targetNick->email);
05103         sprintf(buf, "%s Password Recovery <%s@%s>", NickServ, NickServ,
05104                 NETWORK);
05105         email->from = buf;
05106         email->to = targetNick->email;
05107         email->subject = "Password recovery";
05108 
05109         sprintf(buf, "\nThe password change key for %s is %s\n", targetNick->nick,
05110                 pwAuthKey);
05111         email->body = buf;
05112 
05113         email->body += "This key can be used to set a new password "
05114                        "for your nickname.\n";
05115         email->body += "\n";
05116         sprintf(buf, "On IRC, use: /NickServ SETPASS %s %s <password>\n",
05117                 targetNick->nick, pwAuthKey);
05118         email->body += buf;
05119         email->body += "Or navigate to: "
05120         "http://astral.sorcery.net/~sortest/setpass.php?u_nick=";
05121         email->body += urlEncode(targetNick->nick);
05122         email->body += "&u_ck=";
05123         email->body += urlEncode(pwAuthKey);
05124         email->body += "\nTo choose your new password.\n\n";
05125 
05126         sprintf(buf, "This key was recovered by %s at %s\n",
05127                 nick->nick, ctime(&(doot)));
05128         email->body += buf;
05129 
05130         email->send();
05131         email->reset();
05132         delete email;
05133 
05134         operlog->log(nick, NS_GETPASS, args[nick_arg]);
05135     }
05136     return RET_OK_DB;
05137 }
05138 
05143 NCMD(ns_delete)
05144 {
05145     char *from = nick->nick;
05146     RegNickList *targetNick;
05147 
05148     if (opFlagged(nick, OOPER | ONBANDEL) == 0) {
05149         PutReply(NickServ, nick, ERR_NOACCESS, 0, 0, 0);
05150         return RET_NOPERM;
05151     }
05152 
05153     if (numargs < 2) {
05154         sSend(":%s NOTICE %s :You must specify a nick", NickServ, from);
05155         return RET_SYNTAX;
05156     }
05157 
05158     targetNick = getRegNickData(args[1]);
05159     if (targetNick == NULL) {
05160         sSend(":%s NOTICE %s :Nickname %s is not registered",
05161               NickServ, from, args[1]);
05162         return RET_EFAULT;
05163     }
05164 
05165     if (isRoot(nick) == 0 && (targetNick->opflags & OROOT)) {
05166         sSend(":%s NOTICE %s :Permission denied.", NickServ, from);
05167         return RET_NOPERM;
05168     }
05169 
05170     delRegNick(targetNick);
05171     sSend(":%s NOTICE %s :This nick has been deleted by %s."
05172           " To enable you to use this nick, you will need to "
05173           "change nicknames and then change back",
05174           NickServ, args[1], from);
05175 
05176     sSend(":%s NOTICE %s :Deleted nick %s", NickServ, from, args[1]);
05177     sSend(":%s GLOBOPS :%s deleted nick %s", myname, from, args[1]);
05178 
05179     return RET_OK_DB;
05180 }
05181 
05183 /* ARGSUSED1 */
05184 NCMD(ns_save)
05185 {
05186     char *from = nick->nick;
05187 
05188     if (isRoot(nick) == 0) {
05189         PutReply(NickServ, nick, ERR_NOACCESS, 0, 0, 0);
05190         return RET_NOPERM;
05191     }
05192 #ifdef GLOBOP_ON_SAVE
05193     sSend(":%s GLOBOPS :Saving database. (%s)", NickServ, from);
05194 #else
05195     sSend(":%s PRIVMSG " LOGCHAN " :Saving database. (%s)", NickServ,
05196           from);
05197 #endif
05198     saveNickData();
05199     return RET_OK_DB;
05200 }
05201 
05206 NCMD(ns_list)
05207 {
05208     char *from = nick->nick;
05209     RegNickList *reg;
05210     MaskData *umask;
05211     int i = 0, x = 0, bucket = 0;
05212 
05213     if (opFlagged(nick, OLIST) == 0) {
05214         PutReply(NickServ, nick, ERR_NOACCESS, 0, 0, 0);
05215         return RET_NOPERM;
05216     }
05217 
05218     if (numargs != 2) {
05219         sSend(":%s NOTICE %s :You must specify ONE address to search by",
05220               NickServ, from);
05221         return RET_SYNTAX;
05222     }
05223 
05224     umask = make_mask();
05225 
05226     if (split_userhost(args[1], umask) < 0) {
05227         free_mask(umask);
05228 
05229         sSend(":%s NOTICE %s :Unable to read mask.", NickServ, from);
05230         return RET_SYNTAX;
05231     }
05232 
05233     if (!strcmp(umask->nick, "*") && !strcmp(umask->user, "*")
05234         && !strcmp(umask->host, "*")) {
05235         sSend(":%s NOTICE %s :Invalid mask *!*@*.", NickServ, from);
05236         free_mask(umask);
05237         return RET_EFAULT;
05238     }
05239 
05240     for (bucket = 0; bucket < NICKHASHSIZE; bucket++) {
05241         reg = LIST_FIRST(&RegNickHash[bucket]);
05242 
05243         while (reg != NULL) {
05244             if (!match(umask->nick, reg->nick)
05245                 && !match(umask->user, reg->user)
05246                 && !match(umask->host, reg->host)) {
05247                 i++;
05248                 if (i <= 200)
05249                     sSend(":%s NOTICE %s :%4i: %s!%s@%s",
05250                           NickServ, from, i, reg->nick,
05251                           reg->user, reg->host);
05252             }
05253 
05254             reg = LIST_NEXT(reg, rn_lst);
05255             x++;
05256         }
05257     }
05258     if (i > 200)
05259         sSend(":%s NOTICE %s :[Results truncated to 200 items]",
05260               NickServ, from);
05261     sSend(":%s NOTICE %s :%i/%i matched conditions (%s!%s@%s)",
05262           NickServ, from, i, x, umask->nick, umask->user, umask->host);
05263     sSend(":%s GLOBOPS :%s is listing %s!%s@%s (%d/%d matches)",
05264           NickServ, from, umask->nick, umask->user, umask->host, i, x);
05265     free_mask(umask);
05266 
05267     return RET_OK;
05268 }
05269 
05275 NCMD(ns_bypass)
05276 {
05277     RegNickList *targetnick;
05278     char *from;
05279     HashKeyVal hashEnt;
05280 
05281     if (!nick || !(from = nick->nick))
05282         return RET_FAIL;
05283 
05284     if (!opFlagged(nick, OAKILL) && !opFlagged(nick, OAHURT)) {
05285         sSend
05286             (":%s NOTICE %s :You do not have the necessary flags to use this"
05287              " command", NickServ, from);
05288         return RET_NOPERM;
05289     }
05290 
05291     if (numargs < 2) {
05292         sSend(":%s NOTICE %s :Syntax: /msg %s BYPASS <nick> [<on|off>]",
05293               NickServ, from, NickServ);
05294         return RET_SYNTAX;
05295     }
05296 
05297     if (isServop(nick) && !strcasecmp("allon", args[1])) {
05298         char mask[IRCBUF + 2] = "";
05299 
05300         if ((numargs <= 2) && !opFlagged(nick, OROOT | OVERRIDE) ) {
05301             sSend(":%s NOTICE %s :Syntax error, mask required.",
05302                 OperServ, from);
05303             sSend(":%s NOTICE %s :Must use /os override "
05304                   "to set bypass for all nicks in db.",
05305                   OperServ, from);
05306             return RET_NOPERM;
05307         }
05308 
05309         if (numargs > 2)
05310         {
05311             if (!match(args[2], "...!..@...com")
05312                 || !match(args[2], "...!..@...net")
05313                 || !match(args[2], "...!..@...edu")
05314                 || !match(args[2], "...!..@...org")
05315                 || !match(args[2], "...!..@...my")
05316                 || !match(args[2], "...!..@...uk")) 
05317             {
05318                     sSend(":%s NOTICE %s :That %s is too broad.", OperServ,
05319                     from, "bypass mask");
05320                 sSend(":%s GLOBOPS :%s attempts to set %s for %s", OperServ,
05321                         from, "bypass_allon", args[2]);
05322                 return RET_NOPERM;
05323             }
05324             nicklog->log(nick, NS_BYPASS, args[2], LOGF_ON | LOGF_PATTERN);
05325         }
05326         else {
05327             nicklog->log(nick, NS_BYPASS, "*!*@*", LOGF_ON | LOGF_PATTERN);
05328         }
05329 
05330         for (hashEnt = 0; hashEnt < NICKHASHSIZE; hashEnt++) {
05331             for (targetnick = LIST_FIRST(&RegNickHash[hashEnt]);
05332                  targetnick; targetnick = LIST_NEXT(targetnick, rn_lst)) {
05333                 if (numargs >= 3) {
05334                     snprintf(mask, IRCBUF, "%s!%s@%s", targetnick->nick,
05335                              targetnick->user, targetnick->host);
05336                     if ((numargs > 2) 
05337                         && match(args[2], mask))
05338                         continue;
05339                 }
05340                 targetnick->flags |= NBYPASS;
05341                 sSend(":%s NOTICE %s :%s", NickServ, from,
05342                       targetnick->nick);
05343             }
05344         }
05345         sSend(":%s NOTICE %s :End of list", NickServ, from);
05346         return RET_OK_DB;
05347     }
05348 
05349     if (isRoot(nick) && !strcasecmp("alloff", args[1])) {
05350         char mask[IRCBUF + 2] = "";
05351 
05352                 if ((numargs <= 2) && !opFlagged(nick, OROOT | OVERRIDE) ) {
05353                         sSend(":%s NOTICE %s :Syntax error, mask required.",
05354                                 OperServ, from);
05355                         sSend(":%s NOTICE %s :Must use /os override "
05356                               "to clear bypass for all nicks in db.",
05357                               OperServ, from);
05358                         return RET_NOPERM;
05359                 }
05360 
05361                 if (numargs > 2)
05362                 {
05363                         if (!match(args[2], "...!..@...com")
05364                             || !match(args[2], "...!..@...net")
05365                             || !match(args[2], "...!..@...edu")
05366                             || !match(args[2], "...!..@...org")
05367                             || !match(args[2], "...!..@...my")
05368                             || !match(args[2], "...!..@...uk"))
05369                         {
05370                             sSend(":%s NOTICE %s :That %s is too broad.", OperServ,
05371                                         from, "bypass mask");
05372                             sSend(":%s GLOBOPS :%s attempts to set %s for %s", OperServ,
05373                                         from, "bypass_alloff", args[2]);
05374                             return RET_NOPERM;
05375                         }
05376             nicklog->log(nick, NS_BYPASS, args[2], LOGF_OFF | LOGF_PATTERN);
05377         }
05378         else {
05379             nicklog->log(nick, NS_BYPASS, "*!*@*", LOGF_OFF | LOGF_PATTERN);
05380         }
05381 
05382         for (hashEnt = 0; hashEnt < NICKHASHSIZE; hashEnt++) {
05383             for (targetnick = LIST_FIRST(&RegNickHash[hashEnt]);
05384                  targetnick; targetnick = LIST_NEXT(targetnick, rn_lst)) {
05385                 if (numargs >= 3) {
05386                     snprintf(mask, IRCBUF, "%s!%s@%s", targetnick->nick,
05387                              targetnick->user, targetnick->host);
05388                     if (match(args[2], mask))
05389                         continue;
05390                 }
05391                 targetnick->flags &= ~NBYPASS;
05392                 sSend(":%s NOTICE %s :%s", NickServ, from,
05393                       targetnick->nick);
05394             }
05395         }
05396         sSend(":%s NOTICE %s :End of list", NickServ, from);
05397         return RET_OK_DB;
05398     }
05399 
05400 
05401     if (!strcasecmp("list", args[1])) {
05402         char mask[IRCBUF + 2] = "";
05403 
05404         nicklog->log(nick, NS_BYPASS, args[2], LOGF_SCAN | LOGF_PATTERN,
05405                      "LIST");
05406 
05407         for (hashEnt = 0; hashEnt < NICKHASHSIZE; hashEnt++) {
05408             for (targetnick = LIST_FIRST(&RegNickHash[hashEnt]);
05409                  targetnick; targetnick = LIST_NEXT(targetnick, rn_lst)) {
05410                 if (numargs >= 3) {
05411                     snprintf(mask, IRCBUF, "%s!%s@%s", targetnick->nick,
05412                              targetnick->user, targetnick->host);
05413                     if (match(args[2], mask))
05414                         continue;
05415                 }
05416                 if (!(targetnick->flags & NBYPASS))
05417                     continue;
05418                 sSend(":%s NOTICE %s :%s", NickServ, from,
05419                       targetnick->nick);
05420             }
05421         }
05422         sSend(":%s NOTICE %s :End of list", NickServ, from);
05423         return RET_OK;
05424     }
05425 
05426     if (!(targetnick = getRegNickData(args[1]))) {
05427         sSend(":%s NOTICE %s :%s is not registered.",
05428               NickServ, from, args[1]);
05429         return RET_EFAULT;
05430     }
05431 
05432     if (numargs < 3)
05433         sSend(":%s NOTICE %s :%s can%s bypass selective bans (autohurts).",
05434               NickServ, from, args[1],
05435               targetnick->flags & NBYPASS ? "" : "not");
05436     else {
05437         if (!strcasecmp(args[2], "on") || !strcasecmp(args[2], "yes")) {
05438             sSend
05439                 (":%s NOTICE %s :%s is now a nick that can be used to bypass selective bans.",
05440                  NickServ, from, args[1]);
05441             targetnick->flags |= NBYPASS;
05442             return RET_OK_DB;
05443         }
05444             else if (!strcasecmp(args[2], "off")
05445                      || !strcasecmp(args[2], "no")) {
05446             sSend
05447                 (":%s NOTICE %s :%s is no longer a nick that can be used to bypass selective bans.",
05448                  NickServ, from, args[1]);
05449             targetnick->flags &= ~NBYPASS;
05450             return RET_OK_DB;
05451         } else {
05452             sSend
05453                 (":%s NOTICE %s :Turn %s's selective ban bypass ability on or off?",
05454                  NickServ, from, args[1]);
05455             return RET_OK;
05456         }
05457     }
05458     return RET_OK;
05459 }
05460 
05466 NCMD(ns_logoff)
05467 {
05468     char *from = nick->nick;
05469 
05470     clearIdentify(nick);
05471     if (nick->caccess > 2)
05472         nick->caccess = 2;
05473     sSend(":%s NOTICE %s :You are no longer identified with %s.", NickServ,
05474           from, NickServ);
05475     return RET_OK;
05476 }
05477 
05478 #ifdef REQ_EMAIL
05479 
05487 NCMD(ns_activate)
05488 {
05489     char *from = nick->nick;
05490     /* time_t doot; */
05491 
05492     if (addFlood(nick, 5))
05493         return;
05494 
05495     if(numargs < 2)
05496     {
05497         sSend(":%s NOTICE %s :A validation password is required with %s ACTIVATE", NickServ, from, NickServ);
05498         return;
05499     }
05500 
05501     if(!nick->reg || (nick->reg->flags & NBANISH)) {
05502         sSend(":%s NOTICE %s :Your nick is not registered", NickServ, from);
05503         return;
05504     }
05505 
05506     if(atoi(args[1]) != nick->reg->email_key) {
05507         sSend(":%s NOTICE %s :Incorrect activation key.", NickServ, from);
05508         return;
05509     }
05510 
05511     if(strlen(args[2]) > PASSLEN) {
05512         sSend(":%s NOTICE %s :The password you specified is too long to use, please make it 15 characters or less.", NickServ, from);
05513                 return;
05514     }
05515 
05516     if ((nick->reg->flags & NACTIVE) &&
05517         !(nick->reg->flags & NDEACC))
05518     {
05519         sSend(":%s NOTICE %s :This nickname is already active.",
05520             NickServ, from);
05521         return;
05522     }
05523 
05524     doot = time(NULL);
05525 
05526     if (!(nick->reg->flags & NACTIVE))
05527     {
05528         nick->reg->flags |= NACTIVE;
05529         sSend(":%s NOTICE %s :Your nick %s is now activated.", NickServ, from, from);
05530 #ifdef
05531         sSend(":%s NOTICE %s :Your MemoServ memo box has been configured",
05532               NickServ, from);
05533 #endif
05534     }
05535     else
05536     {
05537         nick->reg->flags |= NACTIVE;
05538         nick->reg->flags &= ~NDEACC;
05539         sSend(":%s NOTICE %s :Your nick has been re-activated", NickServ, from);
05540     }
05541 }
05542 #endif
05543 
05544 
05545 #ifdef REQ_EMAIL
05546 
05552 int emailAbuseCheck(UserList *nick, const char *email, int newNick)
05553 {
05554     if (newNick && !addNReg(email)) {
05555         sSend(":%s NOTICE %s :You have too many nicks registered.", NickServ, from);
05556 #ifdef REGLIMITYELL
05557         sSend(":%s GLOBOPS :%s is trying to register too many nicks.", NickServ, from);
05558 #endif
05559         return 1;
05560     }
05561 }
05562 
05566 int addNReg(char *email)
05567 {
05568         nRegList *tmp;
05569         for(tmp = firstReg;tmp;tmp=tmp->next) {
05570                 if(!strcasecmp(email, tmp->email)) {
05571                         tmp->regs++;
05572                         if(tmp->regs > NickLimit) {
05573                                 tmp->regs--;
05574                                 return 0;
05575                         }
05576 
05577                 }
05578         }
05579 
05580         tmp = malloc(sizeof(nRegList));
05581         strcpy(tmp->email, email);
05582         tmp->regs = 1;
05583 
05584         if(!firstReg) {
05585                 firstReg = tmp;
05586                 tmp->previous = NULL;
05587         }
05588         else {
05589                 lastReg->next = tmp;
05590                 tmp->previous = lastReg;
05591         }
05592 
05593         lastReg = tmp;
05594         tmp->next = NULL;
05595         return 1;
05596 }
05597 
05598 void delNReg(char *email) {
05599         nRegList *tmp;
05600 
05601         for(tmp=firstReg;tmp;tmp=tmp->next) {
05602                 if(!strcasecmp(email, tmp->email)) {
05603                         tmp->regs--;
05604                         if(!tmp->regs) {
05605                                 if(tmp->previous)
05606                                   tmp->previous->next = tmp->next;
05607                                 else
05608                                   firstReg = tmp->next;
05609                                 if(tmp->next)
05610                                   tmp->next->previous = tmp->previous;
05611                                 else
05612                                   lastReg = tmp->previous;
05613                                 sfree(tmp);
05614                         }
05615                 }
05616         }
05617 }
05618 #endif
05619 
05626 NCMD(ns_setpass)
05627 {
05628     const char *from = nick->nick;
05629     const char *pwAuthChKey = NULL;
05630     RegNickList *rnl;
05631 
05632     if (numargs < 4)
05633     {
05634         sSend(":%s NOTICE %s :Syntax: SETPASS <nick> <code> <new password>",
05635             NickServ, from);
05636         return RET_SYNTAX;
05637     }
05638 
05639     if ((rnl = getRegNickData(args[1])) == NULL)
05640     {
05641         sSend(":%s NOTICE %s :That nickname is not registered.",
05642               NickServ, from);
05643         return RET_NOTARGET;
05644     }
05645 
05646     if (rnl->chpw_key) {
05647         const char *rnE = rnl->email;
05648         const char *rnP = PrintPass(rnl->password, NickGetEnc(rnl));
05649 
05650         if (rnl->flags & NFORCEXFER)
05651             rnE = "-forced-transfer-";
05652         pwAuthChKey = GetAuthChKey(rnE, rnP,
05653                                  rnl->timereg, rnl->chpw_key);
05654     }
05655 
05656     if (rnl->chpw_key == 0 || strcmp(pwAuthChKey, args[2]))
05657     {
05658         sSend(":%s NOTICE %s :Access Denied.",
05659               NickServ, from);
05660         return RET_FAIL;
05661     }
05662 
05663     if (strlen(args[3]) > PASSLEN)
05664     {
05665         sSend(":%s NOTICE %s :Specified password is too long, please "
05666               "choose a password of %d characters or less.",
05667               NickServ, from, PASSLEN);
05668         return RET_EFAULT;
05669     }
05670 
05671 
05672     if (strcasecmp(args[1], args[3]) == 0 || strcasecmp(args[3], "password") == 0
05673         || strlen(args[3]) < 3)
05674     {
05675         sSend(":%s NOTICE %s :You cannot use \2%s\2 as your nickname password.",
05676               NickServ, from, args[3]);
05677         return RET_EFAULT;
05678     }
05679 
05680     sSend(":%s NOTICE %s :Ok.", NickServ, from);
05681 
05682     pw_enter_password(args[3], rnl->password, NickGetEnc(rnl));
05683     rnl->chpw_key = 0;
05684     rnl->flags &= ~NFORCEXFER;
05685 
05686     sSend(":%s NOTICE %s :Password for %s is now %s, do NOT forget it, we"
05687           " are not responsible for lost passwords.",
05688         NickServ, from, rnl->nick, args[3]);
05689 
05690     return RET_OK_DB;
05691 }
05692 
05699 NCMD(ns_setemail)
05700 {
05701     char *from = nick->nick;
05702     RegNickList *regnick;
05703 
05704     if (isOper(nick) == 0) {
05705         sSend(":%s NOTICE %s :Unknown command %s.\r\n"
05706               ":%s NOTICE %s :Please try /msg %s HELP",
05707               NickServ, from, args[0], NickServ, from, NickServ);
05708         return RET_NOPERM;
05709     }
05710 
05711     if (opFlagged(nick, OOPER | OGRP) == 0) {
05712         sSend(":%s NOTICE %s :Access denied.",
05713             NickServ, from);
05714         return RET_NOPERM;
05715     }
05716 
05717     if (numargs < 3)
05718     {
05719         sSend(":%s NOTICE %s :Syntax: SETEMAIL <nick> <email>",
05720             NickServ, from);
05721         return RET_SYNTAX;
05722     }
05723 
05724     regnick = getRegNickData(args[1]);
05725 
05726     if (!regnick) {
05727         PutError(NickServ, nick, ERR_NICKNOTREG_1ARG, args[1], 0, 0);
05728         PutHelpInfo(NickServ, nick, "HELP");
05729 
05730         return RET_NOTARGET;
05731     }
05732 
05733     if ((regnick->opflags & OROOT) && (opFlagged(nick, OROOT) == 0)) {
05734         sSend(":%s NOTICE %s :Access denied.",
05735             NickServ, from);
05736         return RET_NOPERM;
05737     }
05738 
05739     if (strchr(args[2], '@') == NULL || strchr(args[2], '.') == NULL ||
05740             strlen(args[2]) > EMAILLEN)
05741     {
05742         sSend(":%s NOTICE %s :Invalid e-mail address.", NickServ, from);
05743         return RET_SYNTAX;
05744     }
05745 
05746     sSend(":%s GLOBOPS :%s sets email for nick %s from \"%s\" to \"%s\"", NickServ, from, args[1],
05747         regnick->email, args[2]);
05748     operlog->log(nick, NS_SETEMAIL, regnick->nick, 0, "%s -> %s", regnick->email,
05749                  args[2]);
05750     strncpyzt(regnick->email, args[2], EMAILLEN);
05751     return RET_FAIL;
05752 }
05753 
05754 /**************************************************************************/

Generated at Sat Oct 25 20:56:09 2003 for Services using Doxygen.
Services Copyr. 1996-2001 Chip Norkus, Max Byrd, Greg Poma, Michael Graff, James Hess, Dafydd James. All rights reserved See LICENSE for licensing information.