u_link_origin *u_link_origin_create_from_fd(mowgli_eventloop_t *ev, int fd) { const char *operation; u_link_origin *origin = NULL; /* Set the fd to be close-on-exec. All listening sockets will be closed when * we upgrade. This may cause some slight disturbance for users currently * connecting, but this is acceptable. */ operation = "set close-on-exec"; if (set_cloexec(fd) < 0) goto error; u_log(LG_DEBUG, "u_link_origin_create_from_fd: %d", fd); origin = malloc(sizeof(*origin)); operation = "create pollable"; if (!(origin->poll = mowgli_pollable_create(ev, fd, origin))) { errno = -EINVAL; /* XXX */ goto error; } mowgli_node_add(origin, &origin->n, &all_origins); mowgli_pollable_setselect(ev, origin->poll, MOWGLI_EVENTLOOP_IO_READ, accept_ready); return origin; error: u_perror(operation); free(origin); return NULL; }
static void add_client(void *client, void *unused) { struct a_client *cli = client; if (cli->net == NULL) return; mowgli_node_add(cli, mowgli_node_create(), cli->net->clients); }
void _modinit(module_t *m) { MODULE_TRY_REQUEST_SYMBOL(m, mechanisms, "saslserv/main", "sasl_mechanisms"); if ((base_dhparams = DH_generate_parameters(256, 5, NULL, NULL)) == NULL) return; mnode = mowgli_node_create(); mowgli_node_add(&mech, mnode, mechanisms); }
static void xmlrpc_config_ready(void *vptr) { /* Note: handle_xmlrpc.path may point to freed memory between * reading the config and here. */ handle_xmlrpc.path = xmlrpc_config.path; if (handle_xmlrpc.handler != NULL) { if (mowgli_node_find(&handle_xmlrpc, httpd_path_handlers)) return; mowgli_node_add(&handle_xmlrpc, mowgli_node_create(), httpd_path_handlers); } else slog(LG_ERROR, "xmlrpc_config_ready(): xmlrpc {} block missing or invalid"); }
void _modinit(module_t *m) { MODULE_TRY_REQUEST_SYMBOL(m, mechanisms, "saslserv/main", "sasl_mechanisms"); mnode = mowgli_node_create(); mowgli_node_add(&mech, mnode, mechanisms); }
/* * server_add(const char *name, unsigned int hops, const char *uplink, * const char *id, const char *desc) * * Server object factory. * * Inputs: * - name of server object to create or NULL if it's a masked server * - amount of hops server has from services * - name of server's uplink or NULL if it's us * - SID of uplink if applicable otherwise NULL * - server's description * * Outputs: * - on success, a new server object * * Side Effects: * - the new server object is added to the server and sid DTree. */ server_t *server_add(const char *name, unsigned int hops, server_t *uplink, const char *id, const char *desc) { server_t *s; const char *tld; /* Masked servers must have a SID */ return_val_if_fail(name != NULL || id != NULL, NULL); /* Masked servers must be behind something else */ return_val_if_fail(name != NULL || uplink != NULL, NULL); if (uplink) { if (name == NULL) slog(LG_NETWORK, "server_add(): %s (%s), masked", uplink->name, id); else if (id != NULL) slog(LG_NETWORK, "server_add(): %s (%s), uplink %s", name, id, uplink->name); else slog(LG_NETWORK, "server_add(): %s, uplink %s", name, uplink->name); } else slog(LG_DEBUG, "server_add(): %s, root", name); s = mowgli_heap_alloc(serv_heap); if (id != NULL) { s->sid = sstrdup(id); mowgli_patricia_add(sidlist, s->sid, s); } /* check to see if it's hidden */ if (!strncmp(desc, "(H)", 3)) { s->flags |= SF_HIDE; desc += 3; if (*desc == ' ') desc++; } s->name = sstrdup(name != NULL ? name : uplink->name); s->desc = sstrdup(desc); s->hops = hops; s->connected_since = CURRTIME; if (name != NULL) mowgli_patricia_add(servlist, s->name, s); else s->flags |= SF_MASKED; if (uplink) { s->uplink = uplink; mowgli_node_add(s, mowgli_node_create(), &uplink->children); } /* tld list for global noticer */ tld = strrchr(s->name, '.'); if (tld != NULL) { if (!tld_find(tld)) tld_add(tld); } cnt.server++; hook_call_server_add(s); return s; }
static void ns_cmd_register(sourceinfo_t *si, int parc, char *parv[]) { myuser_t *mu; mynick_t *mn = NULL; mowgli_node_t *n; const char *account; const char *pass; const char *email; char lau[BUFSIZE], lao[BUFSIZE]; hook_user_register_check_t hdata; hook_user_req_t req; if (si->smu) { command_fail(si, fault_already_authed, _("You are already logged in as \2%s\2."), entity(si->smu)->name); if (si->su != NULL && !mynick_find(si->su->nick) && command_find(si->service->commands, "GROUP")) command_fail(si, fault_already_authed, _("Use %s to register %s to your account."), "GROUP", si->su->nick); return; } if (nicksvs.no_nick_ownership || si->su == NULL) account = parv[0], pass = parv[1], email = parv[2]; else account = si->su->nick, pass = parv[0], email = parv[1]; if (!account || !pass || !email) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "REGISTER"); if (nicksvs.no_nick_ownership || si->su == NULL) command_fail(si, fault_needmoreparams, _("Syntax: REGISTER <account> <password> <email>")); else command_fail(si, fault_needmoreparams, _("Syntax: REGISTER <password> <email>")); return; } if (strlen(pass) >= PASSLEN) { command_fail(si, fault_badparams, STR_INVALID_PARAMS, "REGISTER"); command_fail(si, fault_badparams, _("Registration passwords may not be longer than \2%d\2 characters."), PASSLEN - 1); return; } if (!nicksvs.no_nick_ownership && si->su == NULL && user_find_named(account)) { command_fail(si, fault_noprivs, _("A user matching this account is already on IRC.")); return; } if (!nicksvs.no_nick_ownership && IsDigit(*account)) { command_fail(si, fault_badparams, _("For security reasons, you can't register your UID.")); command_fail(si, fault_badparams, _("Please change to a real nickname, and try again.")); return; } if (nicksvs.no_nick_ownership || si->su == NULL) { if (strchr(account, ' ') || strchr(account, '\n') || strchr(account, '\r') || account[0] == '=' || account[0] == '#' || account[0] == '@' || account[0] == '+' || account[0] == '%' || account[0] == '!' || strchr(account, ',')) { command_fail(si, fault_badparams, _("The account name \2%s\2 is invalid."), account); return; } } if (strlen(account) >= NICKLEN) { command_fail(si, fault_badparams, _("The account name \2%s\2 is invalid."), account); return; } if ((si->su != NULL && !strcasecmp(pass, si->su->nick)) || !strcasecmp(pass, account)) { command_fail(si, fault_badparams, _("You cannot use your nickname as a password.")); if (nicksvs.no_nick_ownership || si->su == NULL) command_fail(si, fault_needmoreparams, _("Syntax: REGISTER <account> <password> <email>")); else command_fail(si, fault_needmoreparams, _("Syntax: REGISTER <password> <email>")); return; } /* make sure it isn't registered already */ if (nicksvs.no_nick_ownership ? myuser_find(account) != NULL : mynick_find(account) != NULL) { command_fail(si, fault_alreadyexists, _("\2%s\2 is already registered."), account); return; } if ((unsigned int)(CURRTIME - ratelimit_firsttime) > config_options.ratelimit_period) ratelimit_count = 0, ratelimit_firsttime = CURRTIME; /* Still do flood priv checking because the user may be in the ircop operclass */ if (ratelimit_count > config_options.ratelimit_uses && !has_priv(si, PRIV_FLOOD)) { command_fail(si, fault_toomany, _("The system is currently too busy to process your registration, please try again later.")); slog(LG_INFO, "NICKSERV:REGISTER:THROTTLED: \2%s\2 by \2%s\2", account, si->su != NULL ? si->su->nick : get_source_name(si)); return; } hdata.si = si; hdata.account = account; hdata.email = email; hdata.password = pass; hdata.approved = 0; hook_call_user_can_register(&hdata); if (hdata.approved != 0) return; if (!nicksvs.no_nick_ownership) { hook_call_nick_can_register(&hdata); if (hdata.approved != 0) return; } if (!validemail(email)) { command_fail(si, fault_badparams, _("\2%s\2 is not a valid email address."), email); return; } if (!email_within_limits(email)) { command_fail(si, fault_toomany, _("\2%s\2 has too many accounts registered."), email); return; } mu = myuser_add(account, auth_module_loaded ? "*" : pass, email, config_options.defuflags | MU_NOBURSTLOGIN | (auth_module_loaded ? MU_CRYPTPASS : 0)); mu->registered = CURRTIME; mu->lastlogin = CURRTIME; if (!nicksvs.no_nick_ownership) { mn = mynick_add(mu, entity(mu)->name); mn->registered = CURRTIME; mn->lastseen = CURRTIME; } if (config_options.ratelimit_uses && config_options.ratelimit_period) ratelimit_count++; if (auth_module_loaded) { if (!verify_password(mu, pass)) { command_fail(si, fault_authfail, _("Invalid password for \2%s\2."), entity(mu)->name); bad_password(si, mu); object_unref(mu); return; } } if (me.auth == AUTH_EMAIL) { char *key = random_string(12); mu->flags |= MU_WAITAUTH; metadata_add(mu, "private:verify:register:key", key); metadata_add(mu, "private:verify:register:timestamp", number_to_string(time(NULL))); if (!sendemail(si->su != NULL ? si->su : si->service->me, mu, EMAIL_REGISTER, mu->email, key)) { command_fail(si, fault_emailfail, _("Sending email failed, sorry! Registration aborted.")); object_unref(mu); free(key); return; } command_success_nodata(si, _("An email containing nickname activation instructions has been sent to \2%s\2."), mu->email); command_success_nodata(si, _("If you do not complete registration within one day, your nickname will expire.")); free(key); } if (si->su != NULL) { si->su->myuser = mu; n = mowgli_node_create(); mowgli_node_add(si->su, n, &mu->logins); if (!(mu->flags & MU_WAITAUTH)) /* only grant ircd registered status if it's verified */ ircd_on_login(si->su, mu, NULL); } command_add_flood(si, FLOOD_MODERATE); if (!nicksvs.no_nick_ownership && si->su != NULL) logcommand(si, CMDLOG_REGISTER, "REGISTER: \2%s\2 to \2%s\2", account, email); else logcommand(si, CMDLOG_REGISTER, "REGISTER: \2%s\2 to \2%s\2 by \2%s\2", account, email, si->su != NULL ? si->su->nick : get_source_name(si)); if (is_soper(mu)) { wallops("%s registered the nick \2%s\2 and gained services operator privileges.", get_oper_name(si), entity(mu)->name); logcommand(si, CMDLOG_ADMIN, "SOPER: \2%s\2 as \2%s\2", get_oper_name(si), entity(mu)->name); } command_success_nodata(si, _("\2%s\2 is now registered to \2%s\2, with the password \2%s\2."), entity(mu)->name, mu->email, pass); hook_call_user_register(mu); if (si->su != NULL) { snprintf(lau, BUFSIZE, "%s@%s", si->su->user, si->su->vhost); metadata_add(mu, "private:host:vhost", lau); snprintf(lao, BUFSIZE, "%s@%s", si->su->user, si->su->host); metadata_add(mu, "private:host:actual", lao); } if (!(mu->flags & MU_WAITAUTH)) { req.si = si; req.mu = mu; req.mn = mn; hook_call_user_verify_register(&req); } }
static void ms_cmd_fsend(sourceinfo_t *si, int parc, char *parv[]) { /* misc structs etc */ user_t *tu; myuser_t *tmu; mowgli_node_t *n; mymemo_t *memo; service_t *memoserv; /* Grab args */ char *target = parv[0]; char *m = parv[1]; /* Arg validation */ if (!target || !m) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "FSEND"); command_fail(si, fault_needmoreparams, "Syntax: FSEND <user> <memo>"); return; } if (!si->smu) { command_fail(si, fault_noprivs, _("You are not logged in.")); return; } /* rate limit it -- jilles */ if (CURRTIME - si->smu->memo_ratelimit_time > MEMO_MAX_TIME) si->smu->memo_ratelimit_num = 0; if (si->smu->memo_ratelimit_num > MEMO_MAX_NUM && !has_priv(si, PRIV_FLOOD)) { command_fail(si, fault_toomany, _("You have used this command too many times; please wait a while and try again.")); return; } /* Check for memo text length -- includes/common.h */ if (strlen(m) >= MEMOLEN) { command_fail(si, fault_badparams, "Please make sure your memo is less than %d characters", MEMOLEN); return; } /* Check to make sure the memo doesn't contain hostile CTCP responses. * realistically, we'll probably want to check the _entire_ message for this... --nenolod */ if (*m == '\001') { command_fail(si, fault_badparams, _("Your memo contains invalid characters.")); return; } memoserv = service_find("memoserv"); if (memoserv == NULL) memoserv = si->service; if (*target != '#' && *target != '!') { /* See if target is valid */ if (!(tmu = myuser_find_ext(target))) { command_fail(si, fault_nosuch_target, "\2%s\2 is not registered.", target); return; } si->smu->memo_ratelimit_num++; si->smu->memo_ratelimit_time = CURRTIME; /* Check to make sure target inbox not full */ if (tmu->memos.count >= me.mdlimit) { command_fail(si, fault_toomany, _("%s's inbox is full"), target); logcommand(si, CMDLOG_SET, "failed SEND to \2%s\2 (target inbox full)", entity(tmu)->name); return; } logcommand(si, CMDLOG_ADMIN, "FSEND: to \2%s\2", entity(tmu)->name); /* Malloc and populate struct */ memo = smalloc(sizeof(mymemo_t)); memo->sent = CURRTIME; memo->status = 0; mowgli_strlcpy(memo->sender,entity(si->smu)->name,NICKLEN); mowgli_strlcpy(memo->text, "[FORCE] ", FMEMOLEN); mowgli_strlcat(memo->text, m, FMEMOLEN); /* Create a linked list node and add to memos */ n = mowgli_node_create(); mowgli_node_add(memo, n, &tmu->memos); tmu->memoct_new++; /* Should we email this? */ if (tmu->flags & MU_EMAILMEMOS) { compat_sendemail(si->su, tmu, EMAIL_MEMO, tmu->email, memo->text); } /* Note: do not disclose other nicks they're logged in with * -- jilles * * Actually, I don't see the point in this at all. If they want this information, * they should use WHOIS. --nenolod */ tu = user_find_named(target); if (tu != NULL && tu->myuser == tmu) command_success_nodata(si, _("%s is currently online, and you may talk directly, by sending a private message."), target); /* Is the user online? If so, tell them about the new memo. */ if (si->su == NULL || !irccasecmp(si->su->nick, entity(si->smu)->name)) myuser_notice(memoserv->nick, tmu, "You have a new memo from %s (%zu).", entity(si->smu)->name, MOWGLI_LIST_LENGTH(&tmu->memos)); else myuser_notice(memoserv->nick, tmu, "You have a new memo from %s (nick: %s) (%zu).", entity(si->smu)->name, si->su->nick, MOWGLI_LIST_LENGTH(&tmu->memos)); myuser_notice(memoserv->nick, tmu, _("To read it, type /%s%s READ %zu"), ircd->uses_rcommand ? "" : "msg ", memoserv->disp, MOWGLI_LIST_LENGTH(&tmu->memos)); /* Tell user memo sent */ command_success_nodata(si, _("The memo has been successfully sent to \2%s\2."), target); } else if (*target == '#') { command_fail(si, fault_nosuch_target, _("Channel memos may not be forced.")); } else { command_fail(si, fault_nosuch_target, _("Group memos may not be forced.")); } return; }
/* * user_add(const char *nick, const char *user, const char *host, const char *vhost, const char *ip, * const char *uid, const char *gecos, server_t *server, time_t ts); * * User object factory. * * Inputs: * - nickname of new user * - username of new user * - hostname of new user * - virtual hostname of new user if applicable otherwise NULL * - ip of user if applicable otherwise NULL * - unique identifier (UID) of user if appliable otherwise NULL * - gecos of new user * - pointer to server new user is on * - user's timestamp * * Outputs: * - on success, a new user * - on failure, NULL * * Side Effects: * - if successful, a user is created and added to the users DTree. * - if unsuccessful, a kill has been sent if necessary */ user_t *user_add(const char *nick, const char *user, const char *host, const char *vhost, const char *ip, const char *uid, const char *gecos, server_t *server, time_t ts) { user_t *u, *u2; hook_user_nick_t hdata; slog(LG_DEBUG, "user_add(): %s (%s@%s) -> %s", nick, user, host, server->name); u2 = user_find_named(nick); if (u2 != NULL) { if (server == me.me) { /* caller should not let this happen */ slog(LG_ERROR, "user_add(): tried to add local nick %s which already exists", nick); return NULL; } slog(LG_INFO, "user_add(): nick collision on %s", nick); if (u2->server == me.me) { if (uid != NULL) { /* If the new client has a UID, our * client will have a UID too and the * remote server will send us a kill * if it kills our client. So just kill * their client and continue. */ kill_id_sts(NULL, uid, "Nick collision with services (new)"); return NULL; } if (ts == u2->ts || ((ts < u2->ts) ^ (!irccasecmp(user, u2->user) && !irccasecmp(host, u2->host)))) { /* If the TSes are equal, or if their TS * is less than our TS and the u@h differs, * or if our TS is less than their TS and * the u@h is equal, our client will be * killed. * * Hope that a kill has arrived just before * for our client; we will have reintroduced * it. */ return NULL; } else /* Our client will not be killed. */ return NULL; } else { wallops("Server %s is introducing nick %s which already exists on %s", server->name, nick, u2->server->name); if (uid != NULL && u2->uid != NULL) { kill_id_sts(NULL, uid, "Ghost detected via nick collision (new)"); kill_id_sts(NULL, u2->uid, "Ghost detected via nick collision (old)"); user_delete(u2, "Ghost detected via nick collision (old)"); } else { /* There is no way we can do this properly. */ kill_id_sts(NULL, nick, "Ghost detected via nick collision"); user_delete(u2, "Ghost detected via nick collision"); } return NULL; } } u = mowgli_heap_alloc(user_heap); object_init(object(u), nick, (destructor_t) user_delete); if (uid != NULL) { u->uid = strshare_get(uid); mowgli_patricia_add(uidlist, u->uid, u); } u->nick = strshare_get(nick); u->user = strshare_get(user); u->host = strshare_get(host); u->gecos = strshare_get(gecos); u->chost = strshare_get(vhost ? vhost : host); u->vhost = strshare_get(vhost ? vhost : host); if (ip && strcmp(ip, "0") && strcmp(ip, "0.0.0.0") && strcmp(ip, "255.255.255.255")) u->ip = strshare_get(ip); u->server = server; u->server->users++; mowgli_node_add(u, &u->snode, &u->server->userlist); u->ts = ts ? ts : CURRTIME; mowgli_patricia_add(userlist, u->nick, u); cnt.user++; hdata.u = u; hdata.oldnick = NULL; hook_call_user_add(&hdata); return hdata.u; }
/* * Implementation functions: load or unload a perl script. */ static module_t *do_script_load(const char *filename) { /* Remember, this must now be re-entrant. The use of the static * perl_error buffer is still OK, as it's only used immediately after * setting, without control passing from this function. */ perl_script_module_t *m = mowgli_heap_alloc(perl_script_module_heap); mowgli_strlcpy(m->filename, filename, sizeof(m->filename)); snprintf(perl_error, sizeof(perl_error), "Unknown error attempting to load perl script %s", filename); dSP; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(newRV_noinc((SV*)get_cv("Atheme::Init::load_script", 0))); XPUSHs(sv_2mortal(newSVpv(filename, 0))); PUTBACK; int perl_return_count = call_pv("Atheme::Init::call_wrapper", G_EVAL | G_SCALAR); SPAGAIN; if (SvTRUE(ERRSV)) { mowgli_strlcpy(perl_error, SvPV_nolen(ERRSV), sizeof(perl_error)); goto fail; } if (1 != perl_return_count) { snprintf(perl_error, sizeof(perl_error), "Script load didn't return a package name"); goto fail; } /* load_script should have returned the package name that was just * loaded... */ const char *packagename = POPp; char info_varname[BUFSIZE]; snprintf(info_varname, BUFSIZE, "%s::Info", packagename); /* ... so use that name to grab the script information hash... */ HV *info_hash = get_hv(info_varname, 0); if (!info_hash) { snprintf(perl_error, sizeof(perl_error), "Couldn't get package info hash %s", info_varname); goto fail; } /* ..., extract the canonical name... */ SV **name_var = hv_fetch(info_hash, "name", 4, 0); if (!name_var) { snprintf(perl_error, sizeof(perl_error), "Couldn't find canonical name in package info hash"); goto fail; } mowgli_strlcpy(m->mod.name, SvPV_nolen(*name_var), sizeof(m->mod.name)); /* ... and dependency list. */ SV **deplist_var = hv_fetch(info_hash, "depends", 7, 0); /* Not declaring this is legal... */ if (deplist_var) { /* ... but having it as anything but an arrayref isn't. */ if (!SvROK(*deplist_var) || SvTYPE(SvRV(*deplist_var)) != SVt_PVAV) { snprintf(perl_error, sizeof(perl_error), "$Info::depends must be an array reference"); goto fail; } AV *deplist = (AV*)SvRV(*deplist_var); I32 len = av_len(deplist); /* av_len returns max index, not number of items */ for (I32 i = 0; i <= len; ++i) { SV **item = av_fetch(deplist, i, 0); if (!item) continue; const char *dep_name = SvPV_nolen(*item); if (!module_request(dep_name)) { snprintf(perl_error, sizeof(perl_error), "Dependent module %s failed to load", dep_name); goto fail; } module_t *dep_mod = module_find_published(dep_name); mowgli_node_add(dep_mod, mowgli_node_create(), &m->mod.deplist); mowgli_node_add(m, mowgli_node_create(), &dep_mod->dephost); } } FREETMPS; LEAVE; invalidate_object_references(); /* Now that everything's loaded, do the module housekeeping stuff. */ m->mod.unload_handler = perl_script_module_unload_handler; /* Can't do much better than the address of the module_t here */ m->mod.address = m; m->mod.can_unload = MODULE_UNLOAD_CAPABILITY_OK; return (module_t*)m; fail: slog(LG_ERROR, "Failed to load Perl script %s: %s", filename, perl_error); if (info_hash) SvREFCNT_dec((SV*)info_hash); do_script_unload(filename); mowgli_heap_free(perl_script_module_heap, m); POPs; FREETMPS; LEAVE; invalidate_object_references(); return NULL; }