#include "module.h" #define AUTHOR "aquanight" #define VERSION "1.0.2" /* FOR UNREALIRCD 3.2* AND LATER ONLY! */ /* ******************************************** * * Configuration section - YOU SHOULD EDIT THIS * * ******************************************** */ /* NOTE: Read the Unreal3.2 Documentation for help with usermodes and operflags! */ /* What are the OFlags for a Global IRCop? */ #define OFLAG_IRCOP "OrhgwckbBnLKG" /* What usermodes should be added to an IRCop? */ #define UMODE_IRCOP "oh" /* What vhost should IRCops get? Comment out or set to NULL if you don't want ircops to have an auto-vhost. */ #define VHOST_IRCOP "ircop.mynetwork.net" /* What are the OFlags for a CoAdmin? */ #define OFLAG_COADMIN "OrhgwckbBnLKGCd" /* What usermodes should be added to a CoAdmin? */ #define UMODE_COADMIN "ohC" /* What vhost should CoAdmins get? */ #define VHOST_COADMIN "coadmin.mynetwork.net" /* What are the OFlags for a Server Admin? */ /* NOTE: DO NOT PUT C HERE! */ #define OFLAG_SERVADMIN "OrhgwckbBnLKGAd" /* What usermodes should be added to a Server Admin? */ #define UMODE_SERVADMIN "ohA" /* What vhost should Server Admins get? */ #define VHOST_SERVADMIN "admin.mynetwork.net" /* What are the OFlags for a Services Administrator? */ /* NOTE: This does NOT grant actual Service Admin access in services - only in the IRCd. */ #define OFLAG_SVSADMIN "OrhgwckbBnLKGdqa" /* What usermodes should be added to a Services Administrator? */ #define UMODE_SVSADMIN "oha" /* What vhost should Service Admins get? */ #define VHOST_SVSADMIN "admin.services.mynetwork.net" /* What are the OFlags for a Network Administrator? */ #define OFLAG_NETADMIN "OrhgwckbBnLKGdqAaN" /* What usermodes should be added to a Network Administrator? */ #define UMODE_NETADMIN "ohAaN" /* What vhost should Net Admins get? */ #define VHOST_NETADMIN "netadmin.mynetwork.net" /* Remove this. Trust me, you WANT to remove this :P . */ #define DIE /* Define this to enable awareness of Unreal 3.2.2 functions - namely snomask +o. */ #define UNREAL32_2 /* Define this if you want to set SNoMasks on Opers. Set it to the snomasks they should get * automatically. */ #define OPERUP_SNOMASKS "cefFGknNoqsSv" /* Everything but junk notices. */ /* Maximum number of hosts an oper may have? This must be at least 1, but 3 is recommended * if you want to take advantage of both host-based and registered-nick based authentications. */ #define MAX_OPERHOSTS 3 /* Define this if you want existing oper permissions reset prior to giving them the oper privileges * stored here. This could be useful if you don't want an oper to be able to add /oper server-given * privileges to their services oper-privileges. */ /* #define OPERUP_RESETPERMS */ /* Define this if you want services (root) admins to be given +a no matter what when they /ns oper. */ /* #define OPERUP_SERVICEADMIN_FORCESADMIN */ /* Define this to use the numeric "You are IRC Operator" reply. (Also uses numeric error replies.) */ #define NSOPER_NUMERICREPLY /* Currently, only Service Admins may add any IRCop. Net admins may only be added by the SRA(s). */ /* ******************************************** * * END CONFIGURATION SECTION Don't edit below! * * ******************************************** */ #ifndef OFLAG_IRCOP #error OFLAG_IRCOP definition is missing. Please #define it. #endif #ifndef UMODE_IRCOP #error UMODE_IRCOP definition is missing. Please #define it. #endif #ifndef OFLAG_COADMIN #error OFLAG_COADMIN definition is missing. Please #define it. #endif #ifndef UMODE_COADMIN #error UMODE_COADMIN definition is missing. Please #define it. #endif #ifndef OFLAG_SERVADMIN #error OFLAG_SERVADMIN definition is missing. Please #define it. #endif #ifndef UMODE_SERVADMIN #error UMODE_SERVADMIN definition is missing. Please #define it. #endif #ifndef OFLAG_SVSADMIN #error OFLAG_SVSADMIN definition is missing. Please #define it. #endif #ifndef UMODE_SVSADMIN #error UMODE_SVSADMIN definition is missing. Please #define it. #endif #ifndef OFLAG_NETADMIN #error OFLAG_NETADMIN definition is missing. Please #define it. #endif #ifndef UMODE_NETADMIN #error UMODE_NETADMIN definition is missing. Please #define it. #endif #if MAX_OPERHOSTS < 1 #error MAX_OPERHOSTS is too small. It needs to be greater than or equal to 1. #endif int my_ns_oper(User* u); int my_os_oplist(User* u); void ircd_oper_help_oper(User* u); int ircd_oper_help_oper_full(User* u); void ircd_oper_help_oplist(User* u); int ircd_oper_help_oplist_full(User* u); #define OPERLVL_IRCOP 0 #define OPERLVL_COADMIN 1 #define OPERLVL_SERVADMIN 2 #define OPERLVL_SVSADMIN 3 #define OPERLVL_NETADMIN 4 #define OPERLVL_CUSTOMLEVEL 5 typedef struct _CUSTOMINFO { char* szOFlag; char* szUMode; char* szVHost; } CUSTOMINFO, *PCUSTOMINFO; typedef struct _OPERINFO { char* szLogin; char* szPass; char* szHosts[MAX_OPERHOSTS]; int level; PCUSTOMINFO custominfo; struct _OPERINFO* prev; struct _OPERINFO* next; } OPERINFO, *POPERINFO; /* pHead is the start of our linked list. */ static POPERINFO pHead = 0; static Command* cOper = 0; static Command* cOpList = 0; static POPERINFO FindOper(const char* szLogin) { POPERINFO pCur = 0; if (!szLogin) return 0; for (pCur = pHead; pCur; pCur = pCur->next) { if (!strcmp(pCur->szLogin, szLogin)) return pCur; } return 0; } /* Create an OPERINFO record with the given login and add it to the list. */ static POPERINFO CreateOper(const char* szLogin) { POPERINFO p = 0; int idx = 0; if (!szLogin || *szLogin == '\0' || FindOper(szLogin)) return 0; if (!(p = malloc(sizeof(OPERINFO)))) return 0; /* Initialize the struct... */ p->szLogin = sstrdup(szLogin); p->szPass = 0; for (idx = 0; idx < MAX_OPERHOSTS; p->szHosts[idx++] = NULL); p->custominfo = 0; p->level = 0; p->prev = 0; p->next = 0; /* Ok, so now we insert it into the linked list. The bigger question is, where? * Fastest solution would be insert it at the beginning... */ if (!pHead) { /* First item in the list! */ pHead = p; } else { /* There's an item there... */ /* Link this one in. */ pHead->prev = p; p->next = pHead; pHead = p; } return p; } static int AddOperHost(POPERINFO pOper, const char* szHost) { /* Add a hostmask or registered nick to the oper account. * Need to find out if we can count on the NickServ DB being loaded here, but since the timer will probably take care of it anyway, blah :/ . */ /* Let's see if there's room for one. */ int idx = 0; for (idx = 0; idx < MAX_OPERHOSTS; idx++) { if (!(pOper->szHosts[idx])) { /* It's null! Take it! */ pOper->szHosts[idx] = sstrdup(szHost); return 1; /* OK */ } } /* No room :( */ return 0; } static int DelOperHost(POPERINFO pOper, const char* szHost) { /* Find the hostmask given and remove it. */ int idx = 0; for (idx = 0; idx < MAX_OPERHOSTS; idx++) { if (pOper->szHosts[idx] && !stricmp(pOper->szHosts[idx], szHost)) { free(pOper->szHosts[idx]); /* We used sstrdup to set it, we should use free to unset it :P */ pOper->szHosts[idx] = NULL; return 1; } } return 0; /* Not found :( */ } /* Remove an OPERINFO record and free it. */ static void DeleteOper(POPERINFO p) { int idx = 0; if (!p) return; /* NULL */ /* Unlink p and relink whatever comes after p to be linked to whatever comes before. */ if (p->prev) { p->prev->next = p->next; } if (p->next) { p->next->prev = p->prev; } /* If p is the head, we have to set the head to the new head. */ if (p == pHead) pHead = p->next; p->prev = 0; p->next = 0; /* Ok it's unlinked, now trash it. */ /* First delete all of its hosts. */ for (idx = 0; idx < MAX_OPERHOSTS; idx++) if (p->szHosts[idx]) { free(p->szHosts[idx]); p->szHosts[idx] = NULL; } /* Junk the custom info if necessary... */ if (p->custominfo) { if (p->custominfo->szOFlag) free(p->custominfo->szOFlag); if (p->custominfo->szUMode) free(p->custominfo->szUMode); if (p->custominfo->szVHost) free(p->custominfo->szVHost); free(p->custominfo); p->custominfo = NULL; } /* Release the password stuffs. */ free(p->szPass); free(p->szLogin); free(p); } static void ChangeOperPass(POPERINFO p, const char* szNewPass) { if (p->szPass) free(p->szPass); p->szPass = sstrdup(szNewPass); } static int LoadDB() { /* Our DB is oplist.db which we expect to be in the data folder. Unlike Anope's FFF databases * our databases are potentially HUMAN READABLE. They are plain text file formats using the ircd.conf * style. Here are some samples: * O:lameuser:lamepass:*@*.aol.com:registerednick * C:coadmin:anotherpass:*user@*.cableone.net:anotherreggednick * A:admin:password:*@*:mynick * S:sadmin:blarp:user@somewhere.com:yayanothernick * N:root:dumbpassword:user@really.strict.host:somenick * ?:customoper:custompass:Ot:oh:*:user@host.name:nick * It is VERY IMPORTANT that you protect these files. Passwords are not yet crypted! MAKE SURE YOU * SET YOUR CHMOD CORRECTLY! If you are unsure, simply do `chmod 600 oplist.db`. */ FILE* fd; char cType = '\0'; char* szCurToken = 0; POPERINFO pOper = NULL; alog("[ircd_oper] Loading database oplist.db..."); if (debug) { alog("[ircd_oper] Attempting to open oplist.db for reading."); } if (!(fd = fopen("oplist.db", "r"))) { alog("[ircd_oper] Read error (oplist.db): %d (%s)", errno, strerror(errno)); return 0; } while (!feof(fd)) { char buf[BUFSIZE + 1]; fgets(buf, BUFSIZE, fd); /* fgets() reads up to and including the first newline. We need to get rid of it. */ szCurToken = strchr(buf, '\n'); if (szCurToken) *szCurToken = '\0'; /* Ok, now remember the delimiter is :. Read the first token to determine the type. */ szCurToken = strtok(buf, ":"); if (!szCurToken || *szCurToken == '\n') { continue; } /* Not reading a blank line, good :P . */ cType = szCurToken[0]; szCurToken = strtok(NULL, ":"); if (!szCurToken) { alog("[ircd_oper] oplist.db: Ignoring invalid entry: no username field"); continue; } if (!(cType == 'O' || cType == 'C' || cType == 'A' || cType == 'S' || cType == 'N' || cType == '?')) { alog("[ircd_oper] oplist.db: Ignoring invalid entry: unknown oper type %c", cType); continue; } /* Ok, now we have the login. Allocate the OPERINFO struct. */ if (!(pOper = CreateOper(szCurToken))) { alog("[ircd_oper] oplist.db: Error Reading OLine %s: Corrupted or duplicate entry, or not enough memory.", szCurToken); continue; } /* Now try to set the level... */ switch (cType) { case 'O': pOper->level = OPERLVL_IRCOP; break; case 'C': pOper->level = OPERLVL_COADMIN; break; case 'A': pOper->level = OPERLVL_SERVADMIN; break; case 'S': pOper->level = OPERLVL_SVSADMIN; break; case 'N': pOper->level = OPERLVL_NETADMIN; break; case '?': pOper->level = OPERLVL_CUSTOMLEVEL; break; default: /* Didn't we already verify this? */ alog("[ircd_oper] EEEK! PANIC! PANIC! INVALID OPER TYPE IN RECORD %s! This shouldn't happen!", pOper->szLogin); raise(SIGSEGV); /* Raise a stink. */ abort(); /* In case SEGV gets ignored. */ return -1; } if (!(szCurToken = strtok(NULL, ":"))) { alog("[ircd_oper] oplist.db: Ignoring invalid entry %s: no password.", pOper->szLogin); DeleteOper(pOper); continue; } pOper->szPass = sstrdup(szCurToken); /* If this is a custom account, read the oflags, umode, and vhost. */ if (pOper->level == OPERLVL_CUSTOMLEVEL) { char *szOFlag, *szUMode, *szVHost; szOFlag = strtok(NULL, ":"); if (!szOFlag) { alog("[ircd_oper] olist.db: Ignoring invald entry %s: Custom type (?) with no operflag field.", pOper->szLogin); DeleteOper(pOper); continue; } szOFlag = sstrdup(szOFlag); szUMode = strtok(NULL, ":"); if (!szUMode) { alog("[ircd_oper] olist.db: Ignoring invald entry %s: Custom type (?) with no usermode field.", pOper->szLogin); DeleteOper(pOper); free(szOFlag); continue; } szUMode = sstrdup(szUMode); szVHost = strtok(NULL, ":"); if (!szOFlag) { alog("[ircd_oper] olist.db: Ignoring invald entry %s: Custom type (?) with no vhost field.", pOper->szLogin); DeleteOper(pOper); free(szOFlag); free(szUMode); continue; } szVHost = sstrdup(szVHost); pOper->custominfo = malloc(sizeof(CUSTOMINFO)); pOper->custominfo->szOFlag = szOFlag; pOper->custominfo->szUMode = szUMode; pOper->custominfo->szVHost = szVHost; } else { pOper->custominfo = NULL; } /* Now for the hostmasks... */ while ((szCurToken = strtok(NULL, ":"))) { if (!AddOperHost(pOper, szCurToken)) { alog("[ircd_oper] Failed adding host %s to %s", szCurToken, pOper->szLogin); } } /* That's all folks! */ } /* Read them all. End Transimission. */ fclose(fd); return 1; } static int SaveDB() { FILE* fd; char buf[BUFSIZE]; char* buf2 = 0; POPERINFO p = 0; int idx = 0; /* Save the database... */ alog("[ircd_oper] Saving database oplist.db..."); if (debug) { alog("[ircd_oper] Attempting to open oplist.db for writing..."); } if (!(fd = fopen("oplist.db", "w"))) { alog("[ircd_oper] Write error (oplist.db): %d (%s)", errno, strerror(errno)); return 0; } /* Now we have to write our stuff :/ */ for (p = pHead; p; p = p->next) { /* Cleanse the buffer of trash from the stack or from the last time 'round. */ memset(buf, 0, BUFSIZE); /* Set the first character to our Oper Level. */ switch (p->level) { case OPERLVL_IRCOP: *buf = 'O'; break; case OPERLVL_COADMIN: *buf = 'C'; break; case OPERLVL_SERVADMIN: *buf = 'A'; break; case OPERLVL_SVSADMIN: *buf = 'S'; break; case OPERLVL_NETADMIN: *buf = 'N'; break; case OPERLVL_CUSTOMLEVEL: *buf = '?'; break; default: alog("[ircd_oper] Record %s with unknown oper type not saved.", p->szLogin); break; } if (!(*buf)) continue; if (!(p->szLogin) || !(p->szPass)) { alog("[ircd_oper] Record with no login or password not saved."); continue; } if (debug) alog("[ircd_oper] DEBUG: Doing snprintf before save. Current state: buf == %s, p->szLogin == %s, p->szPass == %s" , (buf ? buf : ""), (p->szLogin ? p->szLogin : ""), (p->szPass ? p->szPass : "")); buf2 = sstrdup(buf); snprintf(buf, BUFSIZE - 1, "%s:%s:%s", buf2, p->szLogin, p->szPass); free(buf2); if (debug) alog("[ircd_oper] DEBUG: printf result: %s", buf); /* If it's a custom account, save the oflags/umodes/vhost */ if (p->level == OPERLVL_CUSTOMLEVEL) { if (debug) alog("[ircd_oper] DEBUG: Doing snprintf before save. Current state: buf == %s, p->custominfo->szOFlag == %s, p->custominfo->szUMode == %s, p->custominfo->szVHost == %s" , (buf ? buf : ""), (p->custominfo->szOFlag ? p->custominfo->szOFlag : ""), (p->custominfo->szUMode ? p->custominfo->szUMode : ""), (p->custominfo->szVHost ? p->custominfo->szVHost : "")); buf2 = sstrdup(buf); snprintf(buf, BUFSIZE - 1, "%s:%s:%s:%s", buf2, p->custominfo->szOFlag, p->custominfo->szUMode, (p->custominfo->szVHost ? p->custominfo->szVHost : "")); free(buf2); if (debug) alog("[ircd_oper] DEBUG: printf result: %s", buf); } for (idx = 0; idx < MAX_OPERHOSTS; idx ++) { if (p->szHosts[idx]) { if (debug) alog("[ircd_oper] DEBUG: Doing snprintf before save. Current state: buf == %s, idx == %d, p->szHosts[idx] == %s", (buf ? buf : ""), idx, (p->szHosts[idx] ? p->szHosts[idx] : "")); buf2 = sstrdup(buf); snprintf(buf, BUFSIZE - 1, "%s:%s", buf2, p->szHosts[idx]); free(buf2); if (debug) alog("[ircd_oper] DEBUG: printf result: %s", buf); } } /* Ok, it's all set, write it! */ if (debug) alog("[ircd_oper] Writing database line: %s", buf); fprintf(fd, "%s\n", buf); } /* That's all folks! */ fclose(fd); return 1; } int AnopeInit(int argc, char** argv) { #ifdef DIE alog("[ircd_oper] And the Lord came forth and smote the ignorant n00b!"); alog("[ircd_oper] You did not read through ircd_oper.c before compiling and loading!"); alog("[ircd_oper] Consider this a hint to you that you should read the .c before you crank it up!"); return MOD_STOP; #endif if (!LoadDB()) { if (errno == ENOENT) { alog("[ircd_oper] Database empty."); } else { alog("[ircd_oper] This your captain speaking. We've just hit a bit of turbulance while reading the database."); alog("[ircd_oper] Not loading because of database read error."); return MOD_STOP; } } cOper = createCommand("oper", my_ns_oper, NULL, -1, -1, -1, -1, -1); cOpList = createCommand("oplist", my_os_oplist, is_services_admin, -1, -1, -1, -1, -1); alog("Loading ircd_oper module..."); alog("[ircd_oper] Adding command: /msg NickServ OPER login password [Status: %d]", moduleAddCommand(NICKSERV, cOper, MOD_HEAD)); alog("[ircd_oper] Adding command: /msg NickServ OPLIST [ADD|DEL|LIST] [login] [password] [type] [Status: %d]", moduleAddCommand(NICKSERV, cOpList, MOD_HEAD)); alog("[ircd_oper] Adding help entries..."); moduleAddHelp(cOper, ircd_oper_help_oper_full); moduleSetNickHelp(ircd_oper_help_oper); moduleAddHelp(cOpList, ircd_oper_help_oplist_full); moduleSetNickHelp(ircd_oper_help_oplist); moduleAddAuthor(AUTHOR); moduleAddVersion(VERSION); alog("[ircd_oper] Module loaded."); return MOD_CONT; } void AnopeFini(void) { alog("[ircd_oper] Unloading..."); SaveDB(); alog("[ircd_oper] Deleting /nickserv OPLIST"); moduleDelCommand(NICKSERV, "oplist"); destroyCommand(cOpList); cOpList = 0; alog("[ircd_oper] Deleting /nickserv OPER"); moduleDelCommand(NICKSERV, "oper"); destroyCommand(cOper); alog("[ircd_oper] Releasing operator data."); while (pHead) DeleteOper(pHead); alog("[ircd_oper] Module unloaded."); cOper = 0; } void opernotice(char* format, ...) { va_list args; char buf[BUFSIZE]; va_start(args, format); vsnprintf(buf, sizeof(buf), format, args); va_end(args); #ifdef UNREAL32_2 /* Unreal3.2.2 has SNoMask +o for operup notices. */ send_cmd(NULL, "SENDSNO o :*** Notice -- %s", buf); #else /* Unreal3.2.1 and earlier sent operups to snomask +s, but I hate that, so we're going to send to opers with umode +g :) . */ wallops(NULL, "%s", buf); #endif } void operup(User* u, const char* oflags, const char* umodes, const char* vhost, const char* login, const char* announce) { char* av[1] = {0}; #ifdef OPERUP_RESETPERMS send_cmd(s_NickServ, "SVSO %s -", u->nick); #endif send_cmd(s_NickServ, "SVSO %s +%s", u->nick, oflags); send_cmd(s_NickServ, "SVS2MODE %s +%s", u->nick, umodes); av[0] = sstrdup(umodes); set_umode(u, 1, av); free(av[0]); #ifdef OPERUP_SNOMASKS send_cmd(s_NickServ, "SVS2MODE %s +s", u->nick); send_cmd(s_NickServ, "SVS2SNO %s +%s", u->nick, OPERUP_SNOMASKS); av[0] = sstrdup("+s"); set_umode(u, 1, av); free(av[0]); #endif #ifdef OPERUP_SERVICEADMIN_FORCESADMIN if (is_services_admin(u)) { send_cmd(s_NickServ, "SVSO %s +a", u->nick); send_cmd(s_NickServ, "SVS2MODE %s +a", u->nick); av[0] = sstrdup("+a"); set_umode(u, 1, av); free(av[0]); } #endif if (vhost && *vhost != '\0' && *vhost != '*') { send_cmd(s_NickServ, "CHGHOST %s %s", u->nick, vhost); u->vhost = sstrdup(vhost); } alog("Sucessful OPER from %s (%s@%s) [%s]", u->nick, u->username, u->host, login); opernotice("%s (%s@%s) [%s] is now %s.", u->nick, u->username, u->host, login, announce); } int my_ns_oper(User* u) { char* login; char* pass; POPERINFO pOper; int found = 0; char szHost[128]; int idx = 0; if (!(login = strtok(NULL, " "))) { notice_user(s_NickServ, u, "Syntax: \2OPER \37login\37 \37password\37\2"); return MOD_CONT; } if (!(pass = strtok(NULL, " "))) { notice_user(s_NickServ, u, "Syntax: \2OPER \37login\37 \37password\37\2"); return MOD_CONT; } pOper = FindOper(login); sprintf(szHost, "%s@%s", u->username, u->host); /* Does it exist? */ if (!pOper) { #ifdef NSOPER_NUMERICREPLY send_cmd(NULL, "491 %s :No O-lines for your host", u->nick); #else notice_user(s_NickServ, u, "No O-lines for your host."); #endif alog("Failed OPER from %s (%s@%s) [%s] [unknown oper]", u->nick, u->username, u->host, login); opernotice("Failed OPER from %s (%s@%s) [%s] [unknown oper]", u->nick, u->username, u->host, login); return MOD_CONT; } /* Does he match any of the hosts? */ for (idx = 0; idx < MAX_OPERHOSTS; idx++) { if (pOper->szHosts[idx]) { if (strchr(pOper->szHosts[idx], '@')) { /* user@host mask */ if (match_wild_nocase(pOper->szHosts[idx], szHost)) { found = 1; break; } } else { /* Registered and identified to this nick? */ if (stricmp(u->nick, pOper->szHosts[idx]) == 0 && nick_identified(u)) { found = 1; break; } } } } if (!found) { #ifdef NSOPER_NUMERICREPLY send_cmd(NULL, "491 %s :No O-lines for your host", u->nick); #else notice_user(s_NickServ, u, "No O-lines for your host."); #endif alog("Failed OPER from %s (%s@%s) [%s] [no hostmask]", u->nick, u->username, u->host, login); opernotice("Failed OPER from %s (%s@%s) [%s] [no hostmask]", u->nick, u->username, u->host, login); return MOD_CONT; } /* Password correct? */ if (strcmp(pOper->szPass, pass)) { #ifdef NSOPER_NUMERICREPLY send_cmd(NULL, "464 %s :Password incorrect", u->nick); #else notice_user(s_NickServ, u, "Password incorrect. Your attempt has been logged."); #endif alog("Failed OPER from %s (%s@%s) [%s] [bad password]", u->nick, u->username, u->host, login); opernotice("Failed OPER from %s (%s@%s) [%s] [bad password]", u->nick, u->username, u->host, login); bad_password(u); return MOD_CONT; } /* I guess all validations pass. Give him the +o! */ #ifdef NSOPER_NUMERICREPLY send_cmd(NULL, "381 %s :You are now an IRC Operator", u->nick); #else notice_user(s_NickServ, u, "Password accepted. You are now an IRC Operator."); #endif switch (pOper->level) { case OPERLVL_IRCOP: operup(u, OFLAG_IRCOP, UMODE_IRCOP, #ifdef VHOST_IRCOP VHOST_IRCOP, #else NULL, #endif login, "an operator (O)"); break; case OPERLVL_COADMIN: operup(u, OFLAG_COADMIN, UMODE_COADMIN, #ifdef VHOST_COADMIN VHOST_COADMIN, #else NULL, #endif login, "a co-administrator (C)"); break; case OPERLVL_SERVADMIN: operup(u, OFLAG_SERVADMIN, UMODE_SERVADMIN, #ifdef VHOST_SERVADMIN VHOST_SERVADMIN, #else NULL, #endif login, "an administrator (A)"); break; case OPERLVL_SVSADMIN: operup(u, OFLAG_SVSADMIN, UMODE_SVSADMIN, #ifdef VHOST_SVSADMIN VHOST_SVSADMIN, #else NULL, #endif login, "a services administrator (a)"); break; case OPERLVL_NETADMIN: operup(u, OFLAG_NETADMIN, UMODE_NETADMIN, #ifdef VHOST_NETADMIN VHOST_NETADMIN, #else NULL, #endif login, "a network administrator (N)"); break; case OPERLVL_CUSTOMLEVEL: operup(u, pOper->custominfo->szOFlag, pOper->custominfo->szUMode, pOper->custominfo->szVHost, login, "an operator (O)"); break; } return MOD_CONT; } int my_os_oplist_add(User* u, const char* szLogin, const char* szPass, const char* szType); int my_os_oplist_addcustom(User* u, const char* szLogin, const char* szPass, const char* szOFlag, const char* szUMode, const char* szVHost); int my_os_oplist_addhost(User* u, POPERINFO pAccount, const char* szNewHost); int my_os_oplist_delhost(User* u, POPERINFO pAccount, const char* szHost); int my_os_oplist_hosts(User* u, POPERINFO pAccount); int my_os_oplist_del(User* u, POPERINFO pAccount); int my_os_oplist_list(User* u); int my_os_oplist_save(User* u); int my_os_oplist(User* u) { char* szSubcommand = 0; char* szLogin = 0; char* szPass = 0; char* szType = 0; POPERINFO p = NULL; szSubcommand = strtok(NULL, " "); if (!szSubcommand) { notice_user(s_NickServ, u, "Syntax: \2OPLIST [ADD|DEL|ADDHOST|DELHOST|HOSTS|LIST] [...]\2"); notice_user(s_NickServ, u, "Type \2/msg %s HELP OPLIST\2 for help.", s_NickServ); return MOD_CONT; } else if (!stricmp(szSubcommand, "ADD")) { szLogin = strtok(NULL, " "); if (!szLogin) { notice_user(s_NickServ, u, "Syntax: \2OPLIST ADD \37login\37 \37password\37 [GLOBAL|COADMIN|ADMIN|SVSADMIN|NETADMIN|CUSTOM] [\37oflags\37] [\37umodes\37] [\37vhost\37]\2"); notice_user(s_NickServ, u, "Type \2/msg %s HELP OPLIST\2 for help.", s_NickServ); return MOD_CONT; } szPass = strtok(NULL, " "); if (!szPass) { notice_user(s_NickServ, u, "Syntax: \2OPLIST ADD \37login\37 \37password\37 [GLOBAL|COADMIN|ADMIN|SVSADMIN|NETADMIN|CUSTOM] [\37oflags\37] [\37umodes\37] [\37vhost\37]\2"); notice_user(s_NickServ, u, "Type \2/msg %s HELP OPLIST\2 for help.", s_NickServ); return MOD_CONT; } szType = strtok(NULL, " "); if (!szType) { notice_user(s_NickServ, u, "Syntax: \2OPLIST ADD \37login\37 \37password\37 [GLOBAL|COADMIN|ADMIN|SVSADMIN|NETADMIN|CUSTOM] [\37oflags\37] [\37umodes\37] [\37vhost\37]\2"); notice_user(s_NickServ, u, "Type \2/msg %s HELP OPLIST\2 for help.", s_NickServ); return MOD_CONT; } if (!stricmp(szType, "CUSTOM")) { char *szOFlag, *szUMode, *szVHost; szOFlag = strtok(NULL, " "); if (!szOFlag) { notice_user(s_NickServ, u, "Syntax: \2OPLIST ADD \37login\37 \37password\37 [GLOBAL|COADMIN|ADMIN|SVSADMIN|NETADMIN|CUSTOM] [\37oflags\37] [\37umodes\37] [\37vhost\37]\2"); notice_user(s_NickServ, u, "Type \2/msg %s HELP OPLIST\2 for help.", s_NickServ); return MOD_CONT; } szUMode = strtok(NULL, " "); if (!szUMode) { notice_user(s_NickServ, u, "Syntax: \2OPLIST ADD \37login\37 \37password\37 [GLOBAL|COADMIN|ADMIN|SVSADMIN|NETADMIN|CUSTOM] [\37oflags\37] [\37umodes\37] [\37vhost\37]\2"); notice_user(s_NickServ, u, "Type \2/msg %s HELP OPLIST\2 for help.", s_NickServ); return MOD_CONT; } szVHost = strtok(NULL, " "); if (!szVHost) { notice_user(s_NickServ, u, "Syntax: \2OPLIST ADD \37login\37 \37password\37 [GLOBAL|COADMIN|ADMIN|SVSADMIN|NETADMIN|CUSTOM] [\37oflags\37] [\37umodes\37] [\37vhost\37]\2"); notice_user(s_NickServ, u, "Type \2/msg %s HELP OPLIST\2 for help.", s_NickServ); notice_user(s_NickServ, u, "Hint: use a VHost of * if you do not want the operator to have a vhost."); return MOD_CONT; } return my_os_oplist_addcustom(u, szLogin, szPass, szOFlag, szUMode, szVHost); } return my_os_oplist_add(u, szLogin, szPass, szType); } else if (!stricmp(szSubcommand, "ADDHOST")) { szLogin = strtok(NULL, " "); if (!szLogin) { notice_user(s_NickServ, u, "Syntax: \2OPLIST ADDHOST \37login\37 \37hostmask\37\2"); notice_user(s_NickServ, u, "Type \2/msg %s HELP OPLIST\2 for help.", s_NickServ); return MOD_CONT; } szType = strtok(NULL, " "); /* Borrow one of my existing string variables instead of making another one :) */ if (!szType) { notice_user(s_NickServ, u, "Syntax: \2OPLIST ADDHOST \37login\37 \37hostmask\37\2"); notice_user(s_NickServ, u, "Type \2/msg %s HELP OPLIST\2 for help.", s_NickServ); return MOD_CONT; } p = FindOper(szLogin); if (!p) { notice_user(s_NickServ, u, "Account \2%s\2 doesn't exist.", szLogin); return MOD_CONT; } return my_os_oplist_addhost(u, p, szType); } else if (!stricmp(szSubcommand, "DELHOST")) { szLogin = strtok(NULL, " "); if (!szLogin) { notice_user(s_NickServ, u, "Syntax: \2OPLIST DELHOST \37login\37 \37hostmask\37\2"); notice_user(s_NickServ, u, "Type \2/msg %s HELP OPLIST\2 for help.", s_NickServ); return MOD_CONT; } szType = strtok(NULL, " "); /* Borrow one of my existing string variables instead of making another one :) */ if (!szType) { notice_user(s_NickServ, u, "Syntax: \2OPLIST ADDHOST \37login\37 \37hostmask\37\2"); notice_user(s_NickServ, u, "Type \2/msg %s HELP OPLIST\2 for help.", s_NickServ); return MOD_CONT; } p = FindOper(szLogin); if (!p) { notice_user(s_NickServ, u, "Account \2%s\2 doesn't exist.", szLogin); return MOD_CONT; } return my_os_oplist_delhost(u, p, szType); } else if (!stricmp(szSubcommand, "HOSTS")) { szLogin = strtok(NULL, " "); if (!szLogin) { notice_user(s_NickServ, u, "Syntax: \2OPLIST HOSTS \37login\37\2"); notice_user(s_NickServ, u, "Type \2/msg %s HELP OPLIST\2 for help.", s_NickServ); return MOD_CONT; } p = FindOper(szLogin); if (!p) { notice_user(s_NickServ, u, "Account \2%s\2 doesn't exist.", szLogin); return MOD_CONT; } return my_os_oplist_hosts(u, p); } else if (!stricmp(szSubcommand, "DEL")) { szLogin = strtok(NULL, " "); if (!szLogin) { notice_user(s_NickServ, u, "Syntax: \2OPLIST DEL \37login\37\2"); notice_user(s_NickServ, u, "Type \2/msg %s HELP OPLIST\2 for help.", s_NickServ); return MOD_CONT; } p = FindOper(szLogin); if (!p) { notice_user(s_NickServ, u, "Account \2%s\2 doesn't exist.", szLogin); return MOD_CONT; } return my_os_oplist_del(u, p); } else if (!stricmp(szSubcommand, "LIST")) { return my_os_oplist_list(u); } else if (!stricmp(szSubcommand, "SAVE")) { return my_os_oplist_save(u); } else { notice_user(s_NickServ, u, "Unknown subcommand \2%s\2", szSubcommand); notice_user(s_NickServ, u, "Syntax: \2OPLIST [ADD|DEL|ADDHOST|DELHOST|HOSTS|LIST] [...]\2"); notice_user(s_NickServ, u, "Type \2/msg %s HELP OPLIST\2 for help.", s_NickServ); return MOD_CONT; } } int my_os_oplist_add(User* u, const char* szLogin, const char* szPass, const char* szType) { POPERINFO p = NULL; if (!is_services_admin(u)) { notice_lang(s_NickServ, u, PERMISSION_DENIED); return MOD_CONT; } p = FindOper(szLogin); if (p && p->level >= OPERLVL_SVSADMIN && !is_services_root(u)) { notice_lang(s_NickServ, u, PERMISSION_DENIED); return MOD_CONT; } if (!stricmp(szType, "GLOBAL")) { if (p) { p->level = OPERLVL_IRCOP; ChangeOperPass(p, szPass); notice_user(s_NickServ, u, "Account \2%s\2 has been changed to a \2Global Operator\2 with password \2%s\2.", szLogin, szPass); alog("OPLIST: %s changed account %s to type Global.", u->nick, szLogin); } else { p = CreateOper(szLogin); if (p == NULL) { notice_user(s_NickServ, u, "UGH! No memory to create oper record!"); wallops(s_NickServ, "Out of memory while allocating oper record!"); return MOD_STOP; } ChangeOperPass(p, szPass); p->level = OPERLVL_IRCOP; notice_user(s_NickServ, u, "Account \2%s\2 has been created as a \2Global Operator\2 with password \2%s\2.", szLogin, szPass); notice_user(s_NickServ, u, "The account will not be usable until you add a permitted host. Use \2OPLIST ADDHOST\2 to do this."); alog("OPLIST: %s added account %s of type Global.", u->nick, szLogin); } } else if (!stricmp(szType, "COADMIN")) { if (p) { p->level = OPERLVL_COADMIN; ChangeOperPass(p, szPass); notice_user(s_NickServ, u, "Account \2%s\2 has been changed to a \2Server CoAdministrator\2 with password \2%s\2.", szLogin, szPass); alog("OPLIST: %s changed account %s to type CoAdmin.", u->nick, szLogin); } else { p = CreateOper(szLogin); if (p == NULL) { notice_user(s_NickServ, u, "UGH! No memory to create oper record!"); wallops(s_NickServ, "Out of memory while allocating oper record!"); return MOD_STOP; } ChangeOperPass(p, szPass); p->level = OPERLVL_COADMIN; notice_user(s_NickServ, u, "Account \2%s\2 has been created as a \2Server CoAdministrator\2 with password \2%s\2.", szLogin, szPass); notice_user(s_NickServ, u, "The account will not be usable until you add a permitted host. Use \2OPLIST ADDHOST\2 to do this."); alog("OPLIST: %s added account %s of type CoAdmin.", u->nick, szLogin); } } else if (!stricmp(szType, "ADMIN")) { if (p) { p->level = OPERLVL_SERVADMIN; ChangeOperPass(p, szPass); notice_user(s_NickServ, u, "Account \2%s\2 has been changed to a \2Server Administrator\2 with password \2%s\2.", szLogin, szPass); alog("OPLIST: %s changed account %s to type Admin.", u->nick, szLogin); } else { p = CreateOper(szLogin); if (p == NULL) { notice_user(s_NickServ, u, "UGH! No memory to create oper record!"); wallops(s_NickServ, "Out of memory while allocating oper record!"); return MOD_STOP; } ChangeOperPass(p, szPass); p->level = OPERLVL_SERVADMIN; notice_user(s_NickServ, u, "Account \2%s\2 has been created as a \2Server Administrator\2 with password \2%s\2.", szLogin, szPass); notice_user(s_NickServ, u, "The account will not be usable until you add a permitted host. Use \2OPLIST ADDHOST\2 to do this."); alog("OPLIST: %s added account %s of type Admin.", u->nick, szLogin); } } else if (!stricmp(szType, "SVSADMIN")) { if (!is_services_root(u)) { notice_lang(s_NickServ, u, PERMISSION_DENIED); return MOD_CONT; } if (p) { p->level = OPERLVL_SVSADMIN; ChangeOperPass(p, szPass); notice_user(s_NickServ, u, "Account \2%s\2 has been changed to a \2Services Administrator\2 with password \2%s\2.", szLogin, szPass); alog("OPLIST: %s changed account %s to type Services Admin.", u->nick, szLogin); } else { p = CreateOper(szLogin); if (p == NULL) { notice_user(s_NickServ, u, "UGH! No memory to create oper record!"); wallops(s_NickServ, "Out of memory while allocating oper record!"); return MOD_STOP; } ChangeOperPass(p, szPass); p->level = OPERLVL_SVSADMIN; notice_user(s_NickServ, u, "Account \2%s\2 has been created as a \2Services Administrator\2 with password \2%s\2.", szLogin, szPass); notice_user(s_NickServ, u, "The account will not be usable until you add a permitted host. Use \2OPLIST ADDHOST\2 to do this."); alog("OPLIST: %s added account %s of type Services Admin.", u->nick, szLogin); } } else if (!stricmp(szType, "NETADMIN")) { if (!is_services_root(u)) { notice_lang(s_NickServ, u, PERMISSION_DENIED); return MOD_CONT; } if (p) { p->level = OPERLVL_NETADMIN; ChangeOperPass(p, szPass); notice_user(s_NickServ, u, "Account \2%s\2 has been changed to a \2Network Administrator\2 with password \2%s\2.", szLogin, szPass); alog("OPLIST: %s changed account %s to type NetAdmin.", u->nick, szLogin); } else { p = CreateOper(szLogin); if (p == NULL) { notice_user(s_NickServ, u, "UGH! No memory to create oper record!"); wallops(s_NickServ, "Out of memory while allocating oper record!"); return MOD_STOP; } ChangeOperPass(p, szPass); p->level = OPERLVL_NETADMIN; notice_user(s_NickServ, u, "Account \2%s\2 has been created as a \2Network Administrator\2 with password \2%s\2.", szLogin, szPass); notice_user(s_NickServ, u, "The account will not be usable until you add a permitted host. Use \2OPLIST ADDHOST\2 to do this."); alog("OPLIST: %s added account %s of type NetAdmin.", u->nick, szLogin); } } else { notice_user(s_NickServ, u, "Unrecognized oper type. Use \2/msg %s HELP OPLIST\2 for information.", s_NickServ); return MOD_CONT; } /* Now if the thing got switched off of custom, we need to wipe out the custom info stuff. */ if (p->custominfo && p->level != OPERLVL_CUSTOMLEVEL) { if (p->custominfo->szOFlag) free(p->custominfo->szOFlag); if (p->custominfo->szUMode) free(p->custominfo->szUMode); if (p->custominfo->szVHost) free(p->custominfo->szVHost); free(p->custominfo); p->custominfo = NULL; } wallops(s_NickServ, "%s used \2OPLIST ADD\2 for \2%s\2.", u->nick, szLogin); return MOD_CONT; } int my_os_oplist_addcustom(User* u, const char* szLogin, const char* szPass, const char* szOFlag, const char* szUMode, const char* szVHost) { POPERINFO p = NULL; if (!is_services_root(u)) { notice_lang(s_NickServ, u, PERMISSION_DENIED); return MOD_CONT; } p = FindOper(szLogin); if (p) { p->level = OPERLVL_CUSTOMLEVEL; ChangeOperPass(p, szPass); if (!(p->custominfo)) { p->custominfo = malloc(sizeof(CUSTOMINFO)); memset(p->custominfo, 0, sizeof(CUSTOMINFO)); } if (p->custominfo->szOFlag) free(p->custominfo->szOFlag); p->custominfo->szOFlag = sstrdup(szOFlag); if (p->custominfo->szUMode) free(p->custominfo->szUMode); p->custominfo->szUMode = sstrdup(szUMode); if (p->custominfo->szVHost) free(p->custominfo->szVHost); p->custominfo->szVHost = sstrdup(szVHost); notice_user(s_NickServ, u, "Account \2%s\2 has been changed to a \2Custom Operator\2 with password \2%s\2, permissions \2%s\2, usermodes \2%s\2, and vhost \2%s\2", szLogin, szPass, szOFlag, szUMode, szVHost); alog("OPLIST: %s changed account %s to type Custom = %s %s %s .", szOFlag, szUMode, szVHost); } else { p = CreateOper(szLogin); if (p == NULL) { notice_user(s_NickServ, u, "UGH! No memory to create oper record!"); wallops(s_NickServ, "Out of memory while allocating oper record!"); return MOD_STOP; } p->level = OPERLVL_CUSTOMLEVEL; ChangeOperPass(p, szPass); p->custominfo = malloc(sizeof(CUSTOMINFO)); memset(p->custominfo, 0, sizeof(CUSTOMINFO)); p->custominfo->szOFlag = sstrdup(szOFlag); p->custominfo->szUMode = sstrdup(szUMode); p->custominfo->szVHost = sstrdup(szVHost); notice_user(s_NickServ, u, "Account \2%s\2 has been created as a \2Custom Operator\2 with password \2%s\2, permissions \2%s\2, usermodes \2%s\2, and vhost \2%s\2", szLogin, szPass, szOFlag, szUMode, szVHost); notice_user(s_NickServ, u, "The account will not be usable until you add a permitted host. Use \2OPLIST ADDHOST\2 to do this."); alog("OPLIST: %s added account %s of type Custom = %s %s %s .", szOFlag, szUMode, szVHost); } return MOD_CONT; } int my_os_oplist_addhost(User* u, POPERINFO pAccount, const char* szNewHost) { if (!is_services_admin(u)) { notice_lang(s_NickServ, u, PERMISSION_DENIED); return MOD_CONT; } if (pAccount->level >= OPERLVL_SVSADMIN && !is_services_root(u)) { notice_lang(s_NickServ, u, PERMISSION_DENIED); return MOD_CONT; } if (!strchr(szNewHost, '@')) { /* Check if it's registered. */ if (!findnick(szNewHost)) { notice_lang(s_NickServ, u, NICK_X_NOT_REGISTERED, szNewHost); return MOD_CONT; } } if (AddOperHost(pAccount, szNewHost)) { notice_user(s_NickServ, u, "Host \2%s\2 added to IRCop \2%s\2.", szNewHost, pAccount->szLogin); wallops(s_NickServ, "%s added host \2%s\2 to \2%s\2.", u->nick, szNewHost, pAccount->szLogin); alog("OPLIST: %s added host %s to %s", u->nick, szNewHost, pAccount->szLogin); } else { notice_user(s_NickServ, u, "No space to add host \2%s\2 to IRCop \2%s\2. (Maximum hosts = %d)", szNewHost, pAccount->szLogin, MAX_OPERHOSTS); } return MOD_CONT; } int my_os_oplist_delhost(User* u, POPERINFO pAccount, const char* szHost) { if (!is_services_admin(u)) { notice_lang(s_NickServ, u, PERMISSION_DENIED); return MOD_CONT; } if (pAccount->level >= OPERLVL_SVSADMIN && !is_services_root(u)) { notice_lang(s_NickServ, u, PERMISSION_DENIED); return MOD_CONT; } if (DelOperHost(pAccount, szHost)) { notice_user(s_NickServ, u, "Host \2%s\2 deleted from IRCop \2%s\2.", szHost, pAccount->szLogin); wallops(s_NickServ, "%s removed host \2%s\2 from \2%s\2.", u->nick, szHost, pAccount->szLogin); alog("OPLIST: %s removed host %s from %s", u->nick, szHost, pAccount->szLogin); } else { notice_user(s_NickServ, u, "Host \2%s\2 not on hostlist for IRCop \2%s\2.", szHost, pAccount->szLogin); } return MOD_CONT; } int my_os_oplist_hosts(User* u, POPERINFO pAccount) { int idx = 0; if (!is_services_admin(u)) { notice_lang(s_NickServ, u, PERMISSION_DENIED); return MOD_CONT; } alog("OPLIST: %s requested hostlist for %s", u->nick, pAccount->szLogin); notice_user(s_NickServ, u, "Host list for \2%s\2.", pAccount->szLogin); for (idx = 0; idx < MAX_OPERHOSTS; idx++) { if (pAccount->szHosts[idx]) { notice_user(s_NickServ, u, "Host: %s", pAccount->szHosts[idx]); } } return MOD_CONT; } int my_os_oplist_del(User* u, POPERINFO pAccount) { char* szName = sstrdup(pAccount->szLogin); if (!is_services_admin(u)) { notice_lang(s_NickServ, u, PERMISSION_DENIED); return MOD_CONT; } if (pAccount->level >= OPERLVL_SVSADMIN && !is_services_root(u)) { notice_lang(s_NickServ, u, PERMISSION_DENIED); return MOD_CONT; } DeleteOper(pAccount); alog("OPLIST: %s removed operator %s", u->nick, szName); notice_user(s_NickServ, u, "Operator \2%s\2 removed.", szName); wallops(s_NickServ, "%s removed operator \2%s\2.", u->nick, szName); free(szName); return MOD_CONT; } int my_os_oplist_list(User* u) { const char* szTypes[5] = { "IRCop", "CoAdmin", "Admin", "ServiceAdmin", "NetAdmin" }; POPERINFO p = NULL; if (!is_services_admin(u)) { notice_lang(s_NickServ, u, PERMISSION_DENIED); return MOD_CONT; } alog("OPLIST: %s requested operator list", u->nick); notice_user(s_NickServ, u, "Begin Oper List"); for (p = pHead; p; p = p->next) { if (p->level == OPERLVL_CUSTOMLEVEL) { notice_user(s_NickServ, u, "%s * Custom %s %s %s", p->szLogin, p->custominfo->szOFlag, p->custominfo->szUMode, (p->custominfo->szVHost ? p->custominfo->szVHost : "*")); } else { notice_user(s_NickServ, u, "%s * %s", p->szLogin, szTypes[p->level]); } } return MOD_CONT; } int my_os_oplist_save(User* u) { if (!is_services_admin(u)) { notice_lang(s_NickServ, u, PERMISSION_DENIED); return MOD_CONT; } alog("[ircd_oper] Saving databases on request of %s", u->nick); notice_user(s_NickServ, u, "Saving oplist databases..."); SaveDB(); return MOD_CONT; } void ircd_oper_help_oper(User* u) { /* We probably shouldn't tell people about this command :p . */ } int ircd_oper_help_oper_full(User* u) { /* But if they know about it already then... */ notice_user(s_NickServ, u, "Syntax: \2OPER \37login\37 \37password\37\37\2"); notice_user(s_NickServ, u, " "); notice_user(s_NickServ, u, "Activates your service-controlled O:Line."); notice_user(s_NickServ, u, "Arguments are essentially the same as the IRC /OPER command."); notice_user(s_NickServ, u, "Note that any use of this command - failure or not - will be logged!"); notice_user(s_NickServ, u, "Also note that this is in no way associated with nickname registration,"); notice_user(s_NickServ, u, "however, you may be required to register and identify to a nick in order to succeed."); return MOD_CONT; } void ircd_oper_help_oplist(User* u) { if (is_services_admin(u)) { notice_user(s_NickServ, u, " OPLIST Manage the list of service controlled O:Lines."); } } int ircd_oper_help_oplist_full(User* u) { if (is_oper(u)) { notice_user(s_NickServ, u, "Syntax: \2OPLIST ADD \37login\37 \37password\37 \37level\37\2 [\37oflags\37] [\37umodes\37] [\37vhost\37]\2"); notice_user(s_NickServ, u, " \2OPLIST ADDHOST \37login\37 \37hostmask|nick\37\2"); notice_user(s_NickServ, u, " \2OPLIST DELHOST \37login\37 \37hostmask|nick\37\2"); notice_user(s_NickServ, u, " \2OPLIST HOSTS \37login\37\2"); notice_user(s_NickServ, u, " \2OPLIST DEL \37login\37\2"); notice_user(s_NickServ, u, " \2OPLIST LIST\2"); notice_user(s_NickServ, u, " "); notice_user(s_NickServ, u, "The \2ADD\2 subcommand adds an O:Line controlled by services, given"); notice_user(s_NickServ, u, "the login name, password, and level of access. \2\37login\37\2 and"); notice_user(s_NickServ, u, "\2\37password\37\2 will be used by the IRCop in /msg %s OPER", s_NickServ); notice_user(s_NickServ, u, "\2\37level\37\2 will be the level of access the IRCop will have. It can be"); notice_user(s_NickServ, u, "GLOBAL, COADMIN, ADMIN, SVSADMIN, or NETADMIN or CUSTOM."); notice_user(s_NickServ, u, "Attempting to add an already existing login will update the existing login"); notice_user(s_NickServ, u, "with the new information, if possible."); notice_user(s_NickServ, u, "The \2\37oflags\37\2, \2\37umodes\37\2 and \2\37vhosts\37\2 parameters are required and used only with type CUSTOM."); notice_user(s_NickServ, u, " "); notice_user(s_NickServ, u, "\2ADDHOST\2 adds a user@host mask or a registered nick that the OPER account"); notice_user(s_NickServ, u, "may be activated from. Multiple hosts and/or registered nicks may be assigned"); notice_user(s_NickServ, u, "but only one needs to be matched to be permitted use of the account. \2DELHOST\2"); notice_user(s_NickServ, u, "removes an existing host from the account. \2HOSTS\2 will list all privileged hosts"); notice_user(s_NickServ, u, "or registered nicks for the account."); notice_user(s_NickServ, u, " "); notice_user(s_NickServ, u, "A user need not register or identify to a nick for user@host masks to work - this is"); notice_user(s_NickServ, u, "to emulate the IRCd's mechanism of user@host authentication. If a user you with to grant"); notice_user(s_NickServ, u, "oper privileges to has many hostmasks however, you may prefer to simply specify his or her"); notice_user(s_NickServ, u, "registered nick (you may not add unregistered nicks). In this case, the ircop may OPER from"); notice_user(s_NickServ, u, "anywhere, under the condition that he or she has first identified to his nick (must explicitly"); notice_user(s_NickServ, u, "identify, matching a nick access list entry with the Secure option OFF will NOT work.)"); notice_user(s_NickServ, u, "NOTE: If a nick expires, is dropped, or is forbidden, it is not currently removed from the oper's access list."); notice_user(s_NickServ, u, "It is suggested that nicks used in an oper's host be set NOEXPIRE."); notice_user(s_NickServ, u, " "); notice_user(s_NickServ, u, "The \2DEL\2 subcommand removes an O:Line if possible."); notice_user(s_NickServ, u, " "); notice_user(s_NickServ, u, "The \2LIST\2 subcommand will show all stored O:Lines with the login name and level."); notice_user(s_NickServ, u, "(For security, passwords are not shown, even for Service Roots.)"); notice_user(s_NickServ, u, " "); notice_user(s_NickServ, u, "Limited to \2Services Administrators\2. Adding, removing, or editing a Service or Net Admin"); notice_user(s_NickServ, u, "account or a Custom account is limited to \2Services Roots\2."); } return MOD_CONT; }