static int do_userlist(User * u) { char *pattern = strtok(NULL, " "); char *opt = strtok(NULL, " "); Channel *c; int modes = 0; if (opt && !stricmp(opt, "INVISIBLE")) modes |= anope_get_invis_mode(); if (pattern && (c = findchan(pattern))) { struct c_userlist *cu; notice_lang(s_OperServ, u, OPER_USERLIST_HEADER_CHAN, pattern); for (cu = c->users; cu; cu = cu->next) { if (modes && !(cu->user->mode & modes)) continue; notice_lang(s_OperServ, u, OPER_USERLIST_RECORD, cu->user->nick, common_get_vident(cu->user), common_get_vhost(cu->user)); } } else { char mask[BUFSIZE]; int i; User *u2; notice_lang(s_OperServ, u, OPER_USERLIST_HEADER); for (i = 0; i < 1024; i++) { for (u2 = userlist[i]; u2; u2 = u2->next) { if (pattern) { snprintf(mask, sizeof(mask), "%s!%s@%s", u2->nick, common_get_vident(u2), common_get_vhost(u2)); if (!match_wild_nocase(pattern, mask)) continue; if (modes && !(u2->mode & modes)) continue; } notice_lang(s_OperServ, u, OPER_USERLIST_RECORD, u2->nick, common_get_vident(u2), common_get_vhost(u2)); } } } notice_lang(s_OperServ, u, OPER_USERLIST_END); return MOD_CONT; }
void update_host(User * user) { if (user->na && (nick_identified(user) || (!(user->na->nc->flags & NI_SECURE) && nick_recognized(user)))) { if (user->na->last_usermask) free(user->na->last_usermask); user->na->last_usermask = smalloc(strlen(common_get_vident(user)) + strlen(common_get_vhost(user)) + 2); sprintf(user->na->last_usermask, "%s@%s", common_get_vident(user), common_get_vhost(user)); } if (debug) alog("debug: %s changes its host to %s", user->nick, common_get_vhost(user)); }
void change_user_username(User * user, const char *username) { if (user->vident) free(user->vident); user->vident = sstrdup(username); if (user->na && (nick_identified(user) || (!(user->na->nc->flags & NI_SECURE) && nick_recognized(user)))) { if (user->na->last_usermask) free(user->na->last_usermask); user->na->last_usermask = smalloc(strlen(common_get_vident(user)) + strlen(common_get_vhost(user)) + 2); sprintf(user->na->last_usermask, "%s@%s", common_get_vident(user), common_get_vhost(user)); } if (debug) alog("debug: %s changes its username to %s", user->nick, username); }
char *create_mask(User * u) { char *mask, *s, *end; int ulen = strlen(common_get_vident(u)); /* Get us a buffer the size of the username plus hostname. The result * will never be longer than this (and will often be shorter), thus we * can use strcpy() and sprintf() safely. */ end = mask = smalloc(ulen + strlen(common_get_vhost(u)) + 3); end += sprintf(end, "%s%s@", (ulen < (*(common_get_vident(u)) == '~' ? USERMAX + 1 : USERMAX) ? "*" : ""), (*(common_get_vident(u)) == '~' ? common_get_vident(u) + 1 : common_get_vident(u))); if (strspn(common_get_vhost(u), "0123456789.") == strlen(common_get_vhost(u)) && (s = strchr(common_get_vhost(u), '.')) && (s = strchr(s + 1, '.')) && (s = strchr(s + 1, '.')) && (!strchr(s + 1, '.'))) { /* IP addr */ s = sstrdup(common_get_vhost(u)); *strrchr(s, '.') = 0; sprintf(end, "%s.*", s); free(s); } else { if ((s = strchr(common_get_vhost(u), '.')) && strchr(s + 1, '.')) { s = sstrdup(strchr(common_get_vhost(u), '.') - 1); *s = '*'; strcpy(end, s); free(s); } else { strcpy(end, common_get_vhost(u)); } } return mask; }
/** * The /ns identify command. * @param u The user who issued the command * @param MOD_CONT to continue processing other modules, MOD_STOP to stop processing. **/ int do_identify(User * u) { char *pass = strtok(NULL, " "); NickAlias *na; NickRequest *nr; int res; char tsbuf[16]; char modes[512]; int len; if (!pass) { syntax_error(s_NickServ, u, "IDENTIFY", NICK_IDENTIFY_SYNTAX); } else if (!(na = u->na)) { if ((nr = findrequestnick(u->nick))) { notice_lang(s_NickServ, u, NICK_IS_PREREG); } else { notice_lang(s_NickServ, u, NICK_NOT_REGISTERED); } } else if (na->status & NS_VERBOTEN) { notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, na->nick); } else if (na->nc->flags & NI_SUSPENDED) { notice_lang(s_NickServ, u, NICK_X_SUSPENDED, na->nick); } else if (nick_identified(u)) { notice_lang(s_NickServ, u, NICK_ALREADY_IDENTIFIED); } else if (!(res = enc_check_password(pass, na->nc->pass))) { alog("%s: Failed IDENTIFY for %s!%s@%s", s_NickServ, u->nick, u->username, u->host); notice_lang(s_NickServ, u, PASSWORD_INCORRECT); bad_password(u); } else if (res == -1) { notice_lang(s_NickServ, u, NICK_IDENTIFY_FAILED); } else { if (!(na->status & NS_IDENTIFIED) && !(na->status & NS_RECOGNIZED)) { if (na->last_usermask) free(na->last_usermask); na->last_usermask = scalloc(strlen(common_get_vident(u)) + strlen(common_get_vhost(u)) + 2, 1); sprintf(na->last_usermask, "%s@%s", common_get_vident(u), common_get_vhost(u)); if (na->last_realname) free(na->last_realname); na->last_realname = sstrdup(u->realname); } na->status |= NS_IDENTIFIED; na->last_seen = time(NULL); snprintf(tsbuf, sizeof(tsbuf), "%lu", (unsigned long int) u->timestamp); if (ircd->modeonreg) { len = strlen(ircd->modeonreg); strncpy(modes,ircd->modeonreg,512); if(ircd->rootmodeonid && is_services_root(u)) { strncat(modes,ircd->rootmodeonid,512-len); } else if(ircd->adminmodeonid && is_services_admin(u)) { strncat(modes,ircd->adminmodeonid,512-len); } else if(ircd->opermodeonid && is_services_oper(u)) { strncat(modes,ircd->opermodeonid,512-len); } if (ircd->tsonmode) { common_svsmode(u, modes, tsbuf); } else { common_svsmode(u, modes, ""); } } send_event(EVENT_NICK_IDENTIFY, 1, u->nick); alog("%s: %s!%s@%s identified for nick %s", s_NickServ, u->nick, u->username, u->host, u->nick); notice_lang(s_NickServ, u, NICK_IDENTIFY_SUCCEEDED); if (ircd->vhost) { do_on_id(u); } if (NSModeOnID) { do_setmodes(u); } if (NSForceEmail && u->na && !u->na->nc->email) { notice_lang(s_NickServ, u, NICK_IDENTIFY_EMAIL_REQUIRED); notice_help(s_NickServ, u, NICK_IDENTIFY_EMAIL_HOWTO); } if (!(na->status & NS_RECOGNIZED)) check_memos(u); /* Enable nick tracking if enabled */ if (NSNickTracking) nsStartNickTracking(u); /* Clear any timers */ if (na->nc->flags & NI_KILLPROTECT) { del_ns_timeout(na, TO_COLLIDE); } } return MOD_CONT; }
/** * Adds a new user to anopes internal userlist. * * If the SVID passed is 2, the user will not be marked registered or requested to ID. * This is an addition to accomodate IRCds where we cannot determine this based on the NICK * or UID command. Some IRCd's keep +r on when changing nicks and do not use SVID (ex. InspIRCd 1.2). * Instead we get a METADATA command containing the accountname the user was last identified to. * Since this is received after the user is introduced to us we should not yet mark the user * as identified or ask him to identify. We will mark him as recognized for the time being and let * him keep his +r if he has it. * It is the responsibility of the protocol module to make sure that this is either invalidated, * or changed to identified. ~ Viper **/ User *do_nick(const char *source, char *nick, char *username, char *host, char *server, char *realname, time_t ts, uint32 svid, uint32 ip, char *vhost, char *uid) { User *user = NULL; char *tmp = NULL; NickAlias *old_na; /* Old nick rec */ int nc_changed = 1; /* Did nick core change? */ int status = 0; /* Status to apply */ char mask[USERMAX + HOSTMAX + 2]; char *logrealname; char *oldnick; if (!*source) { char ipbuf[16]; struct in_addr addr; if (ircd->nickvhost) { if (vhost) { if (!strcmp(vhost, "*")) { vhost = NULL; if (debug) alog("debug: new user�with no vhost in NICK command: %s", nick); } } } /* This is a new user; create a User structure for it. */ if (debug) alog("debug: new user: %s", nick); if (ircd->nickip) { addr.s_addr = htonl(ip); ntoa(addr, ipbuf, sizeof(ipbuf)); } if (LogUsers) { /** * Ugly swap routine for Flop's bug :) **/ if (realname) { tmp = strchr(realname, '%'); while (tmp) { *tmp = '-'; tmp = strchr(realname, '%'); } } logrealname = normalizeBuffer(realname); /** * End of ugly swap **/ if (ircd->nickvhost) { if (ircd->nickip) { alog("LOGUSERS: %s (%s@%s => %s) (%s) [%s] connected to the network (%s).", nick, username, host, (vhost ? vhost : "none"), logrealname, ipbuf, server); } else { alog("LOGUSERS: %s (%s@%s => %s) (%s) connected to the network (%s).", nick, username, host, (vhost ? vhost : "none"), logrealname, server); } } else { if (ircd->nickip) { alog("LOGUSERS: %s (%s@%s) (%s) [%s] connected to the network (%s).", nick, username, host, logrealname, ipbuf, server); } else { alog("LOGUSERS: %s (%s@%s) (%s) connected to the network (%s).", nick, username, host, logrealname, server); } } Anope_Free(logrealname); } /* We used to ignore the ~ which a lot of ircd's use to indicate no * identd response. That caused channel bans to break, so now we * just take what the server gives us. People are still encouraged * to read the RFCs and stop doing anything to usernames depending * on the result of an identd lookup. */ /* First check for AKILLs. */ /* DONT just return null if its an akill match anymore - yes its more efficent to, however, now that ircd's are * starting to use things like E/F lines, we cant be 100% sure the client will be removed from the network :/ * as such, create a user_struct, and if the client is removed, we'll delete it again when the QUIT notice * comes in from the ircd. **/ if (check_akill(nick, username, host, vhost, ipbuf)) { /* return NULL; */ } /** * DefCon AKILL system, if we want to akill all connecting user's here's where to do it * then force check_akill again on them... **/ /* don't akill on netmerges -Certus */ /* don't akill clients introduced by ulines. -Viper */ if (is_sync(findserver(servlist, server)) && checkDefCon(DEFCON_AKILL_NEW_CLIENTS) && !is_ulined(server)) { strncpy(mask, "*@", 3); strncat(mask, host, HOSTMAX); alog("DEFCON: adding akill for %s", mask); add_akill(NULL, mask, s_OperServ, time(NULL) + dotime(DefConAKILL), DefConAkillReason ? DefConAkillReason : "DEFCON AKILL"); if (check_akill(nick, username, host, vhost, ipbuf)) { /* return NULL; */ } } /* SGLINE */ if (ircd->sgline) { if (check_sgline(nick, realname)) return NULL; } /* SQLINE */ if (ircd->sqline) { if (check_sqline(nick, 0)) return NULL; } /* SZLINE */ if (ircd->szline && ircd->nickip) { if (check_szline(nick, ipbuf)) return NULL; } /* Now check for session limits */ if (LimitSessions && !is_ulined(server) && !add_session(nick, host, ipbuf)) return NULL; /* Allocate User structure and fill it in. */ user = new_user(nick); user->username = sstrdup(username); user->host = sstrdup(host); user->server = findserver(servlist, server); user->realname = sstrdup(realname); user->timestamp = ts; user->my_signon = time(NULL); user->chost = vhost ? sstrdup(vhost) : sstrdup(host); user->vhost = vhost ? sstrdup(vhost) : sstrdup(host); if (uid) { user->uid = sstrdup(uid); /* p10/ts6 stuff */ } else { user->uid = NULL; } user->vident = sstrdup(username); /* We now store the user's ip in the user_ struct, * because we will use it in serveral places -- DrStein */ if (ircd->nickip) { user->hostip = sstrdup(ipbuf); } else { user->hostip = NULL; } if (svid == 0) { display_news(user, NEWS_LOGON); display_news(user, NEWS_RANDOM); } if (svid == 2 && user->na) { /* We do not yet know if the user should be identified or not. * mark him as recognized for now. * It s up to the protocol module to make sure this either becomes ID'd or * is invalidated. ~ Viper */ if (debug) alog("debug: Marking %s as recognized..", user->nick); user->svid = 1; user->na->status |= NS_RECOGNIZED; nc_changed = 0; } else if (svid == ts && user->na) { /* Timestamp and svid match, and nick is registered; automagically identify the nick */ user->svid = svid; user->na->status |= NS_IDENTIFIED; check_memos(user); nc_changed = 0; /* Start nick tracking if available */ if (NSNickTracking) nsStartNickTracking(user); } else if (svid != 1) { /* Resets the svid because it doesn't match */ user->svid = 1; anope_cmd_svid_umode(user->nick, user->timestamp); } else { user->svid = 1; } send_event(EVENT_NEWNICK, 1, nick); } else { /* An old user changing nicks. */ if (UseTS6 && ircd->ts6) user = find_byuid(source); if (!user) user = finduser(source); if (!user) { alog("user: NICK from nonexistent nick %s", source); return NULL; } user->isSuperAdmin = 0; /* Dont let people nick change and stay SuperAdmins */ if (debug) alog("debug: %s changes nick to %s", source, nick); if (LogUsers) { logrealname = normalizeBuffer(user->realname); if (ircd->vhost) { alog("LOGUSERS: %s (%s@%s => %s) (%s) changed nick to %s (%s).", user->nick, user->username, user->host, (user->vhost ? user->vhost : "(none)"), logrealname, nick, user->server->name); } else { alog("LOGUSERS: %s (%s@%s) (%s) changed nick to %s (%s).", user->nick, user->username, user->host, logrealname, nick, user->server->name); } if (logrealname) { free(logrealname); } } user->timestamp = ts; if (stricmp(nick, user->nick) == 0) { /* No need to redo things */ change_user_nick(user, nick); nc_changed = 0; } else { /* Update this only if nicks aren't the same */ user->my_signon = time(NULL); old_na = user->na; if (old_na) { if (nick_recognized(user)) user->na->last_seen = time(NULL); status = old_na->status & NS_TRANSGROUP; cancel_user(user); } oldnick = sstrdup(user->nick); change_user_nick(user, nick); if ((old_na ? old_na->nc : NULL) == (user->na ? user->na->nc : NULL)) nc_changed = 0; if (!nc_changed && (user->na)) user->na->status |= status; else { anope_cmd_nc_change(user); } send_event(EVENT_CHANGE_NICK, 2, nick, oldnick); free(oldnick); } if (ircd->sqline) { if (!is_oper(user) && check_sqline(user->nick, 1)) return NULL; } } /* if (!*source) */ /* Check for nick tracking to bypass identification */ if (NSNickTracking && nsCheckNickTracking(user)) { user->na->status |= NS_IDENTIFIED; nc_changed = 0; } if (nc_changed || !nick_recognized(user)) { if (validate_user(user)) check_memos(user); } else { if (nick_identified(user)) { char tsbuf[16]; user->na->last_seen = time(NULL); if (user->na->last_usermask) free(user->na->last_usermask); user->na->last_usermask = smalloc(strlen(common_get_vident(user)) + strlen(common_get_vhost(user)) + 2); sprintf(user->na->last_usermask, "%s@%s", common_get_vident(user), common_get_vhost(user)); snprintf(tsbuf, sizeof(tsbuf), "%lu", (unsigned long int) user->timestamp); anope_cmd_svid_umode2(user, tsbuf); alog("%s: %s!%s@%s automatically identified for nick %s", s_NickServ, user->nick, user->username, user->host, user->nick); } } /* Bahamut sets -r on every nick changes, so we must test it even if nc_changed == 0 */ if (ircd->check_nick_id) { if (nick_identified(user)) { char tsbuf[16]; snprintf(tsbuf, sizeof(tsbuf), "%lu", (unsigned long int) user->timestamp); anope_cmd_svid_umode3(user, tsbuf); } } return user; }
int do_addnick(User * u) { NickAlias *na, *target; NickCore *nc; char *nick = strtok(NULL, " "); char *pass = strtok(NULL, " "); int i; char tsbuf[16]; char modes[512]; int len; if (NSEmailReg && (findrequestnick(u->nick))) { notice_lang(s_NickServ, u, NS_REQUESTED); return MOD_CONT; } if (readonly) { notice_lang(s_NickServ, u, NS_ADDNICK_DISABLED); return MOD_CONT; } if (checkDefCon(DEFCON_NO_NEW_NICKS)) { notice_lang(s_NickServ, u, OPER_DEFCON_DENIED); return MOD_CONT; } if (RestrictOperNicks) { for (i = 0; i < RootNumber; i++) { if (stristr(u->nick, ServicesRoots[i]) && !is_oper(u)) { notice_lang(s_NickServ, u, NICK_CANNOT_BE_REGISTERED, u->nick); return MOD_CONT; } } for (i = 0; i < servadmins.count && (nc = servadmins.list[i]); i++) { if (stristr(u->nick, nc->display) && !is_oper(u)) { notice_lang(s_NickServ, u, NICK_CANNOT_BE_REGISTERED, u->nick); return MOD_CONT; } } for (i = 0; i < servopers.count && (nc = servopers.list[i]); i++) { if (stristr(u->nick, nc->display) && !is_oper(u)) { notice_lang(s_NickServ, u, NICK_CANNOT_BE_REGISTERED, u->nick); return MOD_CONT; } } } if (!nick || !pass) { syntax_error(s_NickServ, u, "ADDNICK", NS_ADDNICK_SYNTAX); } else if (!(target = findnick(nick))) { notice_lang(s_NickServ, u, NICK_X_NOT_REGISTERED, nick); } else if (time(NULL) < u->lastnickreg + NSRegDelay) { notice_lang(s_NickServ, u, NS_ADDNICK_PLEASE_WAIT, NSRegDelay); } else if (u->na && (u->na->status & NS_VERBOTEN)) { alog("%s: %s@%s tried to use ADDNICK from forbidden nick %s.", s_NickServ, u->username, u->host, u->nick); notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, u->nick); } else if (u->na && (u->na->nc->flags & NI_SUSPENDED)) { alog("%s: %s!%s@%s tried to use ADDNICK from suspended nick %s.", s_NickServ, u->nick, u->username, u->host, target->nick); notice_lang(s_NickServ, u, NICK_X_SUSPENDED, u->nick); } else if (u->na && NSNoGroupChange) { notice_lang(s_NickServ, u, NS_ADDNICK_CHANGE_DISABLED, s_NickServ); } else if (u->na && !nick_identified(u)) { notice_lang(s_NickServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ); } else if (target && (target->nc->flags & NI_SUSPENDED)) { alog("%s: %s!%s@%s tried to use GROUP from SUSPENDED nick %s", s_NickServ, u->nick, u->username, u->host, target->nick); notice_lang(s_NickServ, u, NICK_X_SUSPENDED, target->nick); } else if (target->status & NS_VERBOTEN) { notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, nick); } else if (u->na && target->nc == u->na->nc) { notice_lang(s_NickServ, u, NS_ADDNICK_SAME, target->nick); } else if (NSMaxAliases && (target->nc->aliases.count >= NSMaxAliases) && !nick_is_services_admin(target->nc)) { notice_lang(s_NickServ, u, NS_ADDNICK_TOO_MANY, target->nick, s_NickServ, s_NickServ); } else if (enc_check_password(pass, target->nc->pass) != 1) { alog("%s: Failed ADDNICK for %s!%s@%s (invalid password).", s_NickServ, u->nick, u->username, u->host); notice_lang(s_NickServ, u, PASSWORD_INCORRECT); bad_password(u); } else { /* If the nick is already registered, drop it. * If not, check that it is valid. */ if (u->na) { delnick(u->na); } else { int prefixlen = strlen(NSGuestNickPrefix); int nicklen = strlen(u->nick); if (nicklen <= prefixlen + 7 && nicklen >= prefixlen + 1 && stristr(u->nick, NSGuestNickPrefix) == u->nick && strspn(u->nick + prefixlen, "1234567890") == nicklen - prefixlen) { notice_lang(s_NickServ, u, NICK_CANNOT_BE_REGISTERED, u->nick); return MOD_CONT; } } na = makealias(u->nick, target->nc); if (na) { na->last_usermask = scalloc(strlen(common_get_vident(u)) + strlen(common_get_vhost(u)) + 2, 1); sprintf(na->last_usermask, "%s@%s", common_get_vident(u), common_get_vhost(u)); na->last_realname = sstrdup(u->realname); na->time_registered = na->last_seen = time(NULL); na->status = (int16) (NS_IDENTIFIED | NS_RECOGNIZED); if (!(na->nc->flags & NI_SERVICES_ROOT)) { for (i = 0; i < RootNumber; i++) { if (!stricmp(ServicesRoots[i], u->nick)) { na->nc->flags |= NI_SERVICES_ROOT; break; } } } u->na = na; na->u = u; #ifdef USE_RDB /* Is this really needed? Since this is a new alias it will get * its unique id on the next update, since it was previously * deleted by delnick. Must observe... */ if (rdb_open()) { rdb_save_ns_alias(na); rdb_close(); } #endif send_event(EVENT_GROUP, 1, u->nick); alog("%s: %s!%s@%s makes %s join group of %s (%s) (e-mail: %s)", s_NickServ, u->nick, u->username, u->host, u->nick, target->nick, target->nc->display, (target->nc->email ? target->nc->email : "none")); notice_lang(s_NickServ, u, NS_ADDNICK_SUCCESS, target->nick); u->lastnickreg = time(NULL); snprintf(tsbuf, sizeof(tsbuf), "%lu", (unsigned long int) u->timestamp); if (ircd->modeonreg) { len = strlen(ircd->modeonreg); strncpy(modes,ircd->modeonreg,512); if(ircd->rootmodeonid && is_services_root(u)) { strncat(modes,ircd->rootmodeonid,512-len); } else if(ircd->adminmodeonid && is_services_admin(u)) { strncat(modes,ircd->adminmodeonid,512-len); } else if(ircd->opermodeonid && is_services_oper(u)) { strncat(modes,ircd->opermodeonid,512-len); } if (ircd->tsonmode) { common_svsmode(u, modes, tsbuf); } else { common_svsmode(u, modes, NULL); } } check_memos(u); } else { alog("%s: makealias(%s) failed", s_NickServ, u->nick); notice_lang(s_NickServ, u, NS_ADDNICK_FAILED); } } return MOD_CONT; }