Esempio n. 1
0
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;
}
Esempio n. 2
0
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));
}
Esempio n. 3
0
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);
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
/**
 * 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;
}
Esempio n. 6
0
/**
 * 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;
}
Esempio n. 7
0
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;
}