/* allow_vhost_change: * * Determines whether the source is permitted to change the * services-based vhost for the target user. * * Inputs: si - User executing the command. target - target user * Side Effects: None * Output: True if permitted, otherwise false. */ bool allow_vhost_change(sourceinfo_t *si, myuser_t *target, bool shownotice) { metadata_t *md_vhosttime; time_t vhosttime; unsigned int request_time = get_hostsvs_req_time(); bool limit_first_req = get_hostsvs_limit_first_req(); if (!has_priv(si, PRIV_USER_VHOSTOVERRIDE) && !has_priv(si, PRIV_ADMIN)) { md_vhosttime = metadata_find(target, "private:usercloak-timestamp"); if (md_vhosttime == NULL) { /* If first request isn't limited, always return true. */ if (!limit_first_req) return true; /* If here, limit_first_req must be true, and the user must have never held a vhost before. */ /* 86,400 seconds per day */ if (CURRTIME - target->registered < (request_time * 86400)) { if (shownotice) { if (si->smu == target) command_fail(si, fault_noprivs, _("New users must wait %u days before getting a new vhost setting. %s remaining."), request_time, timediff(target->registered + request_time * 86400 - CURRTIME)); else command_fail(si, fault_noprivs, _("New users must wait %u days before getting a new vhost setting. %s remaining for: %s"), request_time, timediff(target->registered + request_time * 86400 - CURRTIME), entity(target)->name); } return false; } else return true; } vhosttime = atoi(md_vhosttime->value); if (vhosttime + (request_time * 86400) > CURRTIME) { if (shownotice) { if (si->smu == target) command_fail(si, fault_noprivs, _("You may only get new vhosts every %u days. %s remaining."), request_time, timediff(vhosttime + request_time * 86400 - CURRTIME)); else command_fail(si, fault_noprivs, _("Users may only get new vhosts every %u days. %s remaining for: %s"), request_time, timediff(vhosttime + request_time * 86400 - CURRTIME), entity(target)->name); } return false; } } return true; };
static void cs_cmd_drop(char *origin) { user_t *u = user_find_named(origin); mychan_t *mc; char *name = strtok(NULL, " "); if (!name) { notice(chansvs.nick, origin, STR_INSUFFICIENT_PARAMS, "DROP"); notice(chansvs.nick, origin, "Syntax: DROP <#channel>"); return; } if (*name != '#') { notice(chansvs.nick, origin, STR_INVALID_PARAMS, "DROP"); notice(chansvs.nick, origin, "Syntax: DROP <#channel>"); return; } if (!(mc = mychan_find(name))) { notice(chansvs.nick, origin, "\2%s\2 is not registered.", name); return; } if (!is_founder(mc, u->myuser) && !has_priv(u, PRIV_CHAN_ADMIN)) { notice(chansvs.nick, origin, "You are not authorized to perform this operation."); return; } if (metadata_find(mc, METADATA_CHANNEL, "private:close:closer") && !has_priv(u, PRIV_CHAN_ADMIN)) { logcommand(chansvs.me, u, CMDLOG_REGISTER, "%s failed DROP (closed)", mc->name); notice(chansvs.nick, origin, "The channel \2%s\2 is closed; it cannot be dropped.", mc->name); return; } if (!is_founder(mc, u->myuser)) { logcommand(chansvs.me, u, CMDLOG_ADMIN, "%s DROP", mc->name); wallops("%s dropped the channel \2%s\2", origin, name); } else logcommand(chansvs.me, u, CMDLOG_REGISTER, "%s DROP", mc->name); snoop("DROP: \2%s\2 by \2%s\2 as \2%s\2", mc->name, u->nick, u->myuser->name); hook_call_event("channel_drop", mc); if ((config_options.chan && irccasecmp(mc->name, config_options.chan)) || !config_options.chan) part(mc->name, chansvs.nick); mychan_delete(mc->name); notice(chansvs.nick, origin, "The channel \2%s\2 has been dropped.", name); return; }
static void show_setpass(hook_user_req_t *hdata) { if (has_priv(hdata->si, PRIV_USER_AUSPEX)) { if (metadata_find(hdata->mu, "private:setpass:key")) command_success_nodata(hdata->si, "%s has an active password reset key", entity(hdata->mu)->name); metadata_t *md; char strfbuf[BUFSIZE]; if ((md = metadata_find(hdata->mu, "private:sendpass:sender")) != NULL) { const char *sender = md->value; time_t ts; struct tm tm; md = metadata_find(hdata->mu, "private:sendpass:timestamp"); ts = md != NULL ? atoi(md->value) : 0; tm = *localtime(&ts); strftime(strfbuf, sizeof strfbuf, TIME_FORMAT, &tm); command_success_nodata(hdata->si, _("%s was \2SENDPASSED\2 by %s on %s"), entity(hdata->mu)->name, sender, strfbuf); } } }
static void show_setpass(hook_user_req_t *hdata) { if (has_priv(hdata->si, PRIV_USER_AUSPEX)) { if (get_setpass_key(hdata->mu) != NULL) { metadata_t *md; char strfbuf[BUFSIZE]; char buf[BUFSIZE]; size_t buflen = 0; buf[0] = '\0'; if ((md = metadata_find(hdata->mu, "private:sendpass:sender")) != NULL) buflen += snprintf(buf + buflen, sizeof(buf) - buflen, " by %s", md->value); if ((md = metadata_find(hdata->mu, "private:sendpass:timestamp")) != NULL) { time_t ts; struct tm tm; ts = atoi(md->value); tm = *localtime(&ts); strftime(strfbuf, sizeof strfbuf, TIME_FORMAT, &tm); buflen += snprintf(buf + buflen, sizeof(buf) - buflen, " on %s (%s ago)", strfbuf, time_ago(ts)); } if (buf[0] != '\0') command_success_nodata(hdata->si, _("%s has an active \2SETPASS\2 key (sent%s)"), entity(hdata->mu)->name, buf); else command_success_nodata(hdata->si, _("%s has an active \2SETPASS\2 key"), entity(hdata->mu)->name); } } }
void fcgi_delete_file(void) { const char *rev = get_arg("rev"); const sx_hashfs_volume_t *vol; rc_ty s; s = sx_hashfs_volume_by_name(hashfs, volume, &vol); if(s != OK) quit_errmsg(rc2http(s), msg_get_reason()); if(!sx_hashfs_is_or_was_my_volume(hashfs, vol, 0)) quit_errnum(404); if(has_priv(PRIV_CLUSTER)) { /* Request comes in from the cluster: apply locally */ s = sx_hashfs_file_delete(hashfs, vol, path, rev); if(s != OK) quit_errmsg(rc2http(s), msg_get_reason()); CGI_PUTS("\r\n"); } else { /* Request comes in from the user: create job */ job_t job; s = sx_hashfs_filedelete_job(hashfs, uid, vol, path, rev, &job); if(s != OK) quit_errmsg(rc2http(s), msg_get_reason()); send_job_info(job); } }
static void bs_cmd_set_nobot(sourceinfo_t *si, int parc, char *parv[]) { char *channel = parv[0]; char *option = parv[1]; mychan_t *mc; metadata_t *md; if (parc < 2 || !channel || !option) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "SET NOBOT"); command_fail(si, fault_needmoreparams, _("Syntax: SET <#channel> NOBOT {ON|OFF}")); return; } mc = mychan_find(channel); if (!mc) { command_fail(si, fault_nosuch_target, _("Channel \2%s\2 is not registered."), channel); return; } if (!si->smu) { command_fail(si, fault_noprivs, _("You are not logged in.")); return; } if (!has_priv(si, PRIV_CHAN_ADMIN)) { command_fail(si, fault_noprivs, _("You are not authorized to perform this operation.")); return; } if (!irccasecmp(option, "ON")) { metadata_add(mc, "private:botserv:no-bot", "ON"); if ((md = metadata_find(mc, "private:botserv:bot-assigned")) != NULL) { if (mc->flags & MC_GUARD && (!config_options.leave_chans || (mc->chan != NULL && LIST_LENGTH(&mc->chan->members) > 1))) join(mc->name, chansvs.nick); part(mc->name, md->value); metadata_delete(mc, "private:botserv:bot-assigned"); metadata_delete(mc, "private:botserv:bot-handle-fantasy"); } command_success_nodata(si, _("No Bot mode is now \2ON\2 on channel %s."), mc->name); } else if(!irccasecmp(option, "OFF")) { metadata_delete(mc, "private:botserv:no-bot"); command_success_nodata(si, _("No Bot mode is now \2OFF\2 on channel %s."), mc->name); } else { command_fail(si, fault_badparams, STR_INVALID_PARAMS, "SET NOBOT"); command_fail(si, fault_badparams, _("Syntax: SET <#channel> NOBOT {ON|OFF}")); } }
static void gs_cmd_register(struct sourceinfo *si, int parc, char *parv[]) { struct mygroup *mg; if (!parv[0]) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "REGISTER"); command_fail(si, fault_needmoreparams, _("To register a group: REGISTER <!groupname>")); return; } if (*parv[0] != '!') { command_fail(si, fault_needmoreparams, STR_INVALID_PARAMS, "REGISTER"); command_fail(si, fault_needmoreparams, _("To register a group: REGISTER <!groupname>")); return; } if (si->smu->flags & MU_WAITAUTH) { command_fail(si, fault_notverified, STR_EMAIL_NOT_VERIFIED); return; } if (mygroup_find(parv[0])) { command_fail(si, fault_alreadyexists, _("The group \2%s\2 already exists."), parv[0]); return; } if (strlen(parv[0]) > GROUPLEN) { command_fail(si, fault_badparams, _("The group name \2%s\2 is invalid."), parv[0]); return; } if (myentity_count_group_flag(entity(si->smu), GA_FOUNDER) > gs_config->maxgroups && !has_priv(si, PRIV_REG_NOLIMIT)) { command_fail(si, fault_toomany, _("You have too many groups registered.")); return; } if (metadata_find(si->smu, "private:restrict:setter")) { command_fail(si, fault_noprivs, _("You have been restricted from registering groups by network staff.")); return; } mg = mygroup_add(parv[0]); groupacs_add(mg, entity(si->smu), GA_ALL | GA_FOUNDER); hook_call_group_register(mg); logcommand(si, CMDLOG_REGISTER, "REGISTER: \2%s\2", entity(mg)->name); command_success_nodata(si, _("The group \2%s\2 has been registered to \2%s\2."), entity(mg)->name, entity(si->smu)->name); }
static void ns_cmd_acc(sourceinfo_t *si, int parc, char *parv[]) { const char *targuser = parv[0]; const char *targaccount = parv[1]; user_t *u; myuser_t *mu; mynick_t *mn; bool show_id = config_options.show_entity_id || has_priv(si, PRIV_USER_AUSPEX); if (!targuser) { u = si->su; targuser = u != NULL ? u->nick : "?"; } else u = user_find_named(targuser); if (!u) { command_fail(si, fault_nosuch_target, _("%s%s%s ACC 0 (offline)"), targuser, parc >= 2 ? " -> " : "", parc >= 2 ? targaccount : ""); return; } if (!targaccount) targaccount = u->nick; if (!strcmp(targaccount, "*")) mu = u->myuser; else mu = myuser_find_ext(targaccount); if (!mu) { command_fail(si, fault_nosuch_target, _("%s%s%s ACC 0 (not registered)"), u->nick, parc >= 2 ? " -> " : "", parc >= 2 ? targaccount : ""); return; } if (u->myuser == mu) command_success_nodata(si, "%s%s%s ACC 3 %s", u->nick, parc >= 2 ? " -> " : "", parc >= 2 ? entity(mu)->name : "", show_id ? entity(mu)->id : ""); else if ((mn = mynick_find(u->nick)) != NULL && mn->owner == mu && myuser_access_verify(u, mu)) command_success_nodata(si, "%s%s%s ACC 2 %s", u->nick, parc >= 2 ? " -> " : "", parc >= 2 ? entity(mu)->name : "", show_id ? entity(mu)->id : ""); else command_success_nodata(si, "%s%s%s ACC 1 %s", u->nick, parc >= 2 ? " -> " : "", parc >= 2 ? entity(mu)->name : "", show_id ? entity(mu)->id : ""); }
static void info_hook(hook_user_req_t *hdata) { metadata_t *md; if (!(hdata->mu->flags & MU_PRIVATE) || hdata->si->smu == hdata->mu || has_priv(hdata->si, PRIV_USER_AUSPEX)) { md = metadata_find(hdata->mu, "private:lastquit:message"); if (md != NULL) command_success_nodata(hdata->si, "Last quit : %s", md->value); } }
static void can_register(hook_channel_register_check_t *hdata) { const char *name = hdata->name; sourceinfo_t *si = hdata->si; if ( !has_priv(si, PRIV_CHAN_ADMIN) && ( strlen(name) < 2 || *(name + 1) != '#' ) ) { command_fail(si, fault_noprivs, _("\2%s\2 cannot be registered outside of GMS. For more information, see http://freenode.net/policy.shtml#channelnaming"), name); hdata->approved = 1; } else { hdata->approved = 0; } }
static bool cmdperm_command_authorize(service_t *svs, sourceinfo_t *si, command_t *c, const char *userlevel) { char permbuf[BUFSIZE], *cp; snprintf(permbuf, sizeof permbuf, "command:%s:%s", svs->internal_name, c->name); for (cp = permbuf; *cp != '\0'; cp++) *cp = ToLower(*cp); if (!has_priv(si, permbuf)) { logaudit_denycmd(si, c, permbuf); return false; } return parent_command_authorize(svs, si, c, userlevel); }
static bool evaluate_condition(sourceinfo_t *si, const char *s) { char word[80]; char *p, *q; while (*s == ' ' || *s == '\t') s++; if (*s == '!') return !evaluate_condition(si, s + 1); mowgli_strlcpy(word, s, sizeof word); p = strchr(word, ' '); if (p != NULL) { *p++ = '\0'; while (*p == ' ' || *p == '\t') p++; } if (!strcmp(word, "halfops")) return ircd->uses_halfops; else if (!strcmp(word, "owner")) return ircd->uses_owner; else if (!strcmp(word, "protect")) return ircd->uses_protect; else if (!strcmp(word, "anyprivs")) return has_any_privs(si); else if (!strcmp(word, "priv")) { if (p != NULL && (q = strchr(p, ' ')) != NULL) *q = '\0'; return has_priv(si, p); } else if (!strcmp(word, "module")) { if (p != NULL && (q = strchr(p, ' ')) != NULL) *q = '\0'; return module_find_published(p) != NULL; } else if (!strcmp(word, "auth")) return me.auth != AUTH_NONE; else return false; }
static void helpserv_cmd_helpme(sourceinfo_t *si, int parc, char *parv[]) { char *topic = parv[0]; if ((unsigned int)(CURRTIME - ratelimit_firsttime) > config_options.ratelimit_period) ratelimit_count = 0, ratelimit_firsttime = CURRTIME; 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 help request, please try again later.")); slog(LG_INFO, "HELPME:THROTTLED: %s", si->su->nick); return; } if (si->smu != NULL && metadata_find(si->smu, "private:restrict:setter")) { command_fail(si, fault_noprivs, _("You have been restricted from requesting help by network staff.")); return; } command_add_flood(si, FLOOD_HEAVY); if (topic) { logcommand(si, CMDLOG_ADMIN, "HELPME: \2%s\2", topic); wallops("\2%s\2 has requested help about \2%s\2", get_source_name(si), topic); } else { logcommand(si, CMDLOG_ADMIN, "HELPME"); wallops("\2%s\2 has requested help.", get_source_name(si)); } command_success_nodata(si, "The network staff has been notified that you need help and will be with you shortly."); if (config_options.ratelimit_uses && config_options.ratelimit_period) ratelimit_count++; return; }
static void bs_cmd_set_private(sourceinfo_t *si, int parc, char *parv[]) { char *botserv = parv[0]; char *option = parv[1]; botserv_bot_t *bot; if (parc < 2 || !botserv || !option) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "SET PRIVATE"); command_fail(si, fault_needmoreparams, _("Syntax: SET <botnick> PRIVATE {ON|OFF}")); return; } bot = botserv_bot_find(botserv); if (!bot) { command_fail(si, fault_nosuch_target, _("\2%s\2 is not a bot."), botserv); return; } if (!si->smu) { command_fail(si, fault_noprivs, _("You are not logged in.")); return; } if (!has_priv(si, PRIV_CHAN_ADMIN)) { command_fail(si, fault_noprivs, _("You are not authorized to perform this operation.")); return; } if (!irccasecmp(option, "ON")) { bot->private = true; botserv_save_database(NULL); command_success_nodata(si, _("Private mode of bot %s is now \2ON\2."), bot->nick); }
static void info_hook(hook_user_req_t *hdata) { metadata_t *md; if (has_priv(hdata->si, PRIV_USER_AUSPEX) && (md = metadata_find(hdata->mu, "private:restrict:setter"))) { const char *setter = md->value; const char *reason; time_t ts; struct tm tm; char strfbuf[BUFSIZE]; md = metadata_find(hdata->mu, "private:restrict:reason"); reason = md != NULL ? md->value : "unknown"; md = metadata_find(hdata->mu, "private:restrict:timestamp"); ts = md != NULL ? atoi(md->value) : 0; tm = *localtime(&ts); strftime(strfbuf, sizeof strfbuf, TIME_FORMAT, &tm); command_success_nodata(hdata->si, _("%s was \2RESTRICTED\2 by %s on %s (%s)"), entity(hdata->mu)->name, setter, strfbuf, reason); } }
static void ns_cmd_sendpass(struct sourceinfo *si, int parc, char *parv[]) { struct myuser *mu; char *name = parv[0]; char *key; enum specialoperation op = op_none; bool ismarked = false; if (!name) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "SENDPASS"); command_fail(si, fault_needmoreparams, _("Syntax: SENDPASS <account>")); return; } if (parc > 1) { if (!has_priv(si, PRIV_USER_SENDPASS)) { command_fail(si, fault_noprivs, STR_NOT_AUTHORIZED); return; } else if (!strcasecmp(parv[1], "FORCE")) op = op_force; else if (!strcasecmp(parv[1], "CLEAR")) op = op_clear; else { command_fail(si, fault_badparams, STR_INVALID_PARAMS, "SENDPASS"); command_fail(si, fault_badparams, _("Syntax: SENDPASS <account> [FORCE|CLEAR]")); return; } } if (!(mu = myuser_find_by_nick(name))) { command_fail(si, fault_nosuch_target, STR_IS_NOT_REGISTERED, name); return; } if (mu->flags & MU_WAITAUTH) { command_fail(si, fault_badparams, _("\2%s\2 is not verified."), entity(mu)->name); return; } if (metadata_find(mu, "private:mark:setter")) { ismarked = true; // don't want to disclose this, so just go ahead... } if (op == op_clear) { if (metadata_find(mu, "private:setpass:key")) { logcommand(si, CMDLOG_ADMIN, "SENDPASS:CLEAR: \2%s\2", entity(mu)->name); metadata_delete(mu, "private:setpass:key"); metadata_delete(mu, "private:sendpass:sender"); metadata_delete(mu, "private:sendpass:timestamp"); command_success_nodata(si, _("The password change key for \2%s\2 has been cleared."), entity(mu)->name); } else command_fail(si, fault_nochange, _("\2%s\2 did not have a password change key outstanding."), entity(mu)->name); return; } if (MOWGLI_LIST_LENGTH(&mu->logins) > 0) { if (si->smu == mu) command_fail(si, fault_already_authed, _("You are logged in and can change your password using the SET PASSWORD command.")); else command_fail(si, fault_noprivs, _("This operation cannot be performed on %s, because someone is logged in to it."), entity(mu)->name); return; } if (metadata_find(mu, "private:freeze:freezer")) { command_fail(si, fault_noprivs, _("%s has been frozen by the %s administration."), entity(mu)->name, me.netname); return; } if (metadata_find(mu, "private:setpass:key")) { command_fail(si, fault_alreadyexists, _("\2%s\2 already has a password change key outstanding."), entity(mu)->name); if (has_priv(si, PRIV_USER_SENDPASS)) command_fail(si, fault_alreadyexists, _("Use SENDPASS %s CLEAR to clear it so that a new one can be sent."), entity(mu)->name); return; } key = random_string(12); const char *const hash = crypt_password(key); if (!hash) { command_fail(si, fault_internalerror, _("Hash generation for password change key failed.")); sfree(key); return; } if (sendemail(si->su != NULL ? si->su : si->service->me, mu, EMAIL_SETPASS, mu->email, key)) { if (ismarked) wallops("%s sent the password for the \2MARKED\2 account %s.", get_oper_name(si), entity(mu)->name); logcommand(si, CMDLOG_ADMIN, "SENDPASS: \2%s\2 (change key)", name); metadata_add(mu, "private:sendpass:sender", get_oper_name(si)); metadata_add(mu, "private:sendpass:timestamp", number_to_string(time(NULL))); metadata_add(mu, "private:setpass:key", hash); command_success_nodata(si, _("The password change key for \2%s\2 has been sent to the corresponding email address."), entity(mu)->name); } else command_fail(si, fault_emailfail, _("Email send failed.")); sfree(key); }
static void cs_cmd_register(struct sourceinfo *si, int parc, char *parv[]) { struct channel *c; struct chanuser *cu; struct mychan *mc; char *name = parv[0]; char str[21]; hook_channel_register_check_t hdatac; hook_channel_req_t hdata; unsigned int fl; /* This command is not useful on registered channels, ignore it if * it is a fantasy command so users can program bots to react on * it without interference from ChanServ. */ if (si->c != NULL) return; if (!name) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "REGISTER"); command_fail(si, fault_needmoreparams, _("To register a channel: REGISTER <#channel>")); return; } if (*name != '#') { command_fail(si, fault_badparams, STR_INVALID_PARAMS, "REGISTER"); command_fail(si, fault_badparams, _("Syntax: REGISTER <#channel>")); return; } if (si->smu->flags & MU_WAITAUTH) { command_fail(si, fault_notverified, _("You need to verify your email address before you may register channels.")); return; } // make sure it isn't already registered if ((mc = mychan_find(name))) { if (! (mc->flags & MC_PRIVATE)) command_fail(si, fault_alreadyexists, _("\2%s\2 is already registered to \2%s\2."), mc->name, mychan_founder_names(mc)); else command_fail(si, fault_alreadyexists, _("\2%s\2 is already registered."), mc->name); return; } // make sure the channel exists if (!(c = channel_find(name))) { command_fail(si, fault_nosuch_target, _("The channel \2%s\2 must exist in order to register it."), name); return; } // make sure they're in it if (!(cu = chanuser_find(c, si->su))) { command_fail(si, fault_noprivs, _("You must be in \2%s\2 in order to register it."), name); return; } // make sure they're opped (or protected/owner on unreal/inspircd) if (!((CSTATUS_OP | CSTATUS_PROTECT | CSTATUS_OWNER) & cu->modes)) { command_fail(si, fault_noprivs, _("You must be a channel operator in \2%s\2 in order to register it."), name); return; } if (metadata_find(si->smu, "private:restrict:setter")) { command_fail(si, fault_noprivs, _("You have been restricted from registering channels by network staff.")); return; } if ((unsigned int)(CURRTIME - ratelimit_firsttime) > config_options.ratelimit_period) { ratelimit_count = 0; ratelimit_firsttime = CURRTIME; } 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, "CHANSERV:REGISTER:THROTTLED: \2%s\2 by \2%s\2", name, entity(si->smu)->name); return; } hdatac.si = si; hdatac.name = name; hdatac.chan = c; hdatac.approved = 0; hook_call_channel_can_register(&hdatac); if (hdatac.approved != 0) return; if (!myentity_can_register_channel(entity(si->smu))) { command_fail(si, fault_toomany, _("You have too many channels registered.")); return; } if (config_options.ratelimit_uses && config_options.ratelimit_period) ratelimit_count++; logcommand(si, CMDLOG_REGISTER, "REGISTER: \2%s\2", name); mc = mychan_add(name); mc->registered = CURRTIME; mc->used = CURRTIME; mc->mlock_on |= (CMODE_NOEXT | CMODE_TOPIC); if (c->limit == 0) mc->mlock_off |= CMODE_LIMIT; if (c->key == NULL) mc->mlock_off |= CMODE_KEY; mc->flags |= config_options.defcflags; chanacs_add(mc, entity(si->smu), custom_founder_check(), CURRTIME, entity(si->smu)); if (c->ts > 0) { snprintf(str, sizeof str, "%lu", (unsigned long)c->ts); metadata_add(mc, "private:channelts", str); } if (chansvs.deftemplates != NULL && *chansvs.deftemplates != '\0') metadata_add(mc, "private:templates", chansvs.deftemplates); command_success_nodata(si, _("\2%s\2 is now registered to \2%s\2."), mc->name, entity(si->smu)->name); hdata.si = si; hdata.mc = mc; hook_call_channel_register(&hdata); // Allow the hook to override this. fl = chanacs_source_flags(mc, si); cu = chanuser_find(mc->chan, si->su); if (cu == NULL) ; else if (ircd->uses_owner && fl & CA_USEOWNER && fl & CA_AUTOOP && !(cu->modes & CSTATUS_OWNER)) { modestack_mode_param(si->service->nick, mc->chan, MTYPE_ADD, ircd->owner_mchar[1], CLIENT_NAME(si->su)); cu->modes |= CSTATUS_OWNER; } else if (ircd->uses_protect && fl & CA_USEPROTECT && fl & CA_AUTOOP && !(cu->modes & CSTATUS_PROTECT)) { modestack_mode_param(si->service->nick, mc->chan, MTYPE_ADD, ircd->protect_mchar[1], CLIENT_NAME(si->su)); cu->modes |= CSTATUS_PROTECT; } }
static void cs_cmd_set_mlock(struct sourceinfo *si, int parc, char *parv[]) { struct mychan *mc; char modebuf[32], *end, c; int dir = MTYPE_NUL; int newlock_on = 0, newlock_off = 0, newlock_limit = 0, flag = 0; unsigned int mask, changed; bool mask_ext; char newlock_key[KEYLEN + 1]; char newlock_ext[ignore_mode_list_size][512]; bool newlock_ext_off[ignore_mode_list_size]; char newext[512]; char ext_plus[ignore_mode_list_size + 1]; char ext_minus[ignore_mode_list_size + 1]; size_t i; char *letters = strtok(parv[1], " "); char *arg; struct metadata *md; if (!(mc = mychan_find(parv[0]))) { command_fail(si, fault_nosuch_target, STR_IS_NOT_REGISTERED, parv[0]); return; } if (!chanacs_source_has_flag(mc, si, CA_SET)) { if (ircd->oper_only_modes == 0 || !has_priv(si, PRIV_CHAN_CMODES) || !has_priv(si, PRIV_CHAN_ADMIN)) { command_fail(si, fault_noprivs, STR_NOT_AUTHORIZED); return; } mask = ~ircd->oper_only_modes; mask_ext = true; } else { mask = has_priv(si, PRIV_CHAN_CMODES) ? 0 : ircd->oper_only_modes; mask_ext = false; } for (i = 0; i < ignore_mode_list_size; i++) { newlock_ext[i][0] = '\0'; newlock_ext_off[i] = false; } newlock_key[0] = '\0'; while (letters && *letters) { if (*letters != '+' && *letters != '-' && dir == MTYPE_NUL) { letters++; continue; } switch ((c = *letters++)) { case '+': dir = MTYPE_ADD; break; case '-': dir = MTYPE_DEL; break; case 'k': if (dir == MTYPE_ADD) { arg = strtok(NULL, " "); if (!arg) { command_fail(si, fault_badparams, _("You need to specify a value for mode +%c."), 'k'); return; } else if (strlen(arg) > KEYLEN) { command_fail(si, fault_badparams, _("MLOCK key is too long (%zu > %u)."), strlen(arg), KEYLEN); return; } else if (strchr(arg, ',') || arg[0] == ':') { command_fail(si, fault_badparams, _("MLOCK key contains invalid characters.")); return; } mowgli_strlcpy(newlock_key, arg, sizeof newlock_key); newlock_off &= ~CMODE_KEY; } else { newlock_key[0] = '\0'; newlock_off |= CMODE_KEY; } break; case 'l': if (dir == MTYPE_ADD) { arg = strtok(NULL, " "); if(!arg) { command_fail(si, fault_badparams, _("You need to specify a value for mode +%c."), 'l'); return; } if (atol(arg) <= 0) { command_fail(si, fault_badparams, _("You must specify a positive integer for limit.")); return; } newlock_limit = atol(arg); newlock_off &= ~CMODE_LIMIT; } else { newlock_limit = 0; newlock_off |= CMODE_LIMIT; } break; default: flag = mode_to_flag(c); if (flag) { if (dir == MTYPE_ADD) { newlock_on |= flag; newlock_off &= ~flag; } else { newlock_off |= flag; newlock_on &= ~flag; } break; } for (i = 0; ignore_mode_list[i].mode != '\0'; i++) { if (c == ignore_mode_list[i].mode) { if (dir == MTYPE_ADD) { arg = strtok(NULL, " "); if(!arg) { command_fail(si, fault_badparams, _("You need to specify a value for mode +%c."), c); return; } if (strlen(arg) > 350) { command_fail(si, fault_badparams, _("Invalid value \2%s\2 for mode +%c."), arg, c); return; } if ((mc->chan == NULL || mc->chan->extmodes[i] == NULL || strcmp(mc->chan->extmodes[i], arg)) && !ignore_mode_list[i].check(arg, mc->chan, mc, si->su, si->smu)) { command_fail(si, fault_badparams, _("Invalid value \2%s\2 for mode +%c."), arg, c); return; } mowgli_strlcpy(newlock_ext[i], arg, sizeof newlock_ext[i]); newlock_ext_off[i] = false; } else { newlock_ext[i][0] = '\0'; newlock_ext_off[i] = true; } } } } } // note: the following does not treat +lk and extmodes correctly changed = ((newlock_on ^ mc->mlock_on) | (newlock_off ^ mc->mlock_off)); changed &= ~mask; /* if they're only allowed to alter oper only modes, require * them to actually change such modes -- jilles */ if (!changed && mask_ext) { command_fail(si, fault_noprivs, _("You may only alter \2+%s\2 modes."), flags_to_string(~mask)); return; } // save it to mychan, leave the modes in mask unchanged -- jilles mc->mlock_on = (newlock_on & ~mask) | (mc->mlock_on & mask); mc->mlock_off = (newlock_off & ~mask) | (mc->mlock_off & mask); if (!(mask & CMODE_LIMIT)) mc->mlock_limit = newlock_limit; if (!(mask & CMODE_KEY)) { sfree(mc->mlock_key); mc->mlock_key = *newlock_key != '\0' ? sstrdup(newlock_key) : NULL; } ext_plus[0] = '\0'; ext_minus[0] = '\0'; if (mask_ext) { md = metadata_find(mc, "private:mlockext"); if (md != NULL) { arg = md->value; while (*arg != '\0') { modebuf[0] = *arg; modebuf[1] = '\0'; mowgli_strlcat(arg[1] == ' ' || arg[1] == '\0' ? ext_minus : ext_plus, modebuf, ignore_mode_list_size + 1); arg++; while (*arg != ' ' && *arg != '\0') arg++; while (*arg == ' ') arg++; } } } else { newext[0] = '\0'; for (i = 0; i < ignore_mode_list_size; i++) { if (newlock_ext[i][0] != '\0' || newlock_ext_off[i]) { if (*newext != '\0') { modebuf[0] = ' '; modebuf[1] = '\0'; mowgli_strlcat(newext, modebuf, sizeof newext); } modebuf[0] = ignore_mode_list[i].mode; modebuf[1] = '\0'; mowgli_strlcat(newext, modebuf, sizeof newext); mowgli_strlcat(newlock_ext_off[i] ? ext_minus : ext_plus, modebuf, ignore_mode_list_size + 1); if (!newlock_ext_off[i]) mowgli_strlcat(newext, newlock_ext[i], sizeof newext); } } if (newext[0] != '\0') metadata_add(mc, "private:mlockext", newext); else metadata_delete(mc, "private:mlockext"); } end = modebuf; *end = 0; if (mc->mlock_on || mc->mlock_key || mc->mlock_limit || *ext_plus) end += snprintf(end, sizeof(modebuf) - (end - modebuf), "+%s%s%s%s", flags_to_string(mc->mlock_on), mc->mlock_key ? "k" : "", mc->mlock_limit ? "l" : "", ext_plus); if (mc->mlock_off || *ext_minus) end += snprintf(end, sizeof(modebuf) - (end - modebuf), "-%s%s%s%s", flags_to_string(mc->mlock_off), mc->mlock_off & CMODE_KEY ? "k" : "", mc->mlock_off & CMODE_LIMIT ? "l" : "", ext_minus); if (*modebuf) { command_success_nodata(si, _("The MLOCK for \2%s\2 has been set to \2%s\2."), mc->name, modebuf); logcommand(si, CMDLOG_SET, "SET:MLOCK: \2%s\2 to \2%s\2", mc->name, modebuf); verbose(mc, "\2%s\2 set the mode lock to \2%s\2", get_source_name(si), modebuf); } else { command_success_nodata(si, _("The MLOCK for \2%s\2 has been removed."), mc->name); logcommand(si, CMDLOG_SET, "SET:MLOCK:NONE: \2%s\2", mc->name); } if (changed & ircd->oper_only_modes) logcommand(si, CMDLOG_SET, "SET:MLOCK: \2%s\2 to \2%s\2 by \2%s\2", mc->name, *modebuf != '\0' ? modebuf : "+", get_oper_name(si)); check_modes(mc, true); if (mc->chan != NULL) mlock_sts(mc->chan); return; }
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; }
static void ns_cmd_resetpass(sourceinfo_t *si, int parc, char *parv[]) { myuser_t *mu; metadata_t *md; char *name = parv[0]; char *newpass; if (!name) { command_fail(si, fault_needmoreparams, STR_INVALID_PARAMS, "RESETPASS"); command_fail(si, fault_needmoreparams, _("Syntax: RESETPASS <account>")); return; } if (!(mu = myuser_find_by_nick(name))) { command_fail(si, fault_nosuch_target, _("\2%s\2 is not registered."), name); return; } if (is_soper(mu) && !has_priv(si, PRIV_ADMIN)) { logcommand(si, CMDLOG_ADMIN, "failed RESETPASS \2%s\2 (is SOPER)", name); command_fail(si, fault_badparams, _("\2%s\2 belongs to a services operator; you need %s privilege to reset the password."), name, PRIV_ADMIN); return; } if ((md = metadata_find(mu, "private:mark:setter"))) { if (has_priv(si, PRIV_MARK)) { wallops("%s reset the password for the \2MARKED\2 account %s.", get_oper_name(si), entity(mu)->name); logcommand(si, CMDLOG_ADMIN, "RESETPASS: \2%s\2 (overriding mark by \2%s\2)", entity(mu)->name, md->value); command_success_nodata(si, _("Overriding MARK placed by %s on the account %s."), md->value, entity(mu)->name); } else { logcommand(si, CMDLOG_ADMIN, "failed RESETPASS \2%s\2 (marked by \2%s\2)", entity(mu)->name, md->value); command_fail(si, fault_badparams, _("This operation cannot be performed on %s, because the account has been marked by %s."), entity(mu)->name, md->value); return; } } else { wallops("%s reset the password for the account %s", get_oper_name(si), entity(mu)->name); logcommand(si, CMDLOG_ADMIN, "RESETPASS: \2%s\2", entity(mu)->name); } newpass = random_string(12); metadata_delete(mu, "private:setpass:key"); metadata_add(mu, "private:sendpass:sender", get_oper_name(si)); metadata_add(mu, "private:sendpass:timestamp", number_to_string(time(NULL))); set_password(mu, newpass); free(newpass); command_success_nodata(si, _("The password for \2%s\2 has been changed to \2%s\2."), entity(mu)->name, newpass); if (mu->flags & MU_NOPASSWORD) { mu->flags &= ~MU_NOPASSWORD; command_success_nodata(si, _("The \2%s\2 flag has been removed for account \2%s\2."), "NOPASSWORD", entity(mu)->name); } }
static void ns_cmd_group(sourceinfo_t *si, int parc, char *parv[]) { mynick_t *mn; hook_user_req_t hdata; hook_user_register_check_t hdata_reg; if (si->su == NULL) { command_fail(si, fault_noprivs, _("\2%s\2 can only be executed via IRC."), "GROUP"); return; } if (nicksvs.no_nick_ownership) { command_fail(si, fault_noprivs, _("Nickname ownership is disabled.")); return; } if (MOWGLI_LIST_LENGTH(&si->smu->nicks) >= nicksvs.maxnicks && !has_priv(si, PRIV_REG_NOLIMIT)) { command_fail(si, fault_noprivs, _("You have too many nicks registered already.")); return; } mn = mynick_find(si->su->nick); if (mn != NULL) { if (mn->owner == si->smu) command_fail(si, fault_nochange, _("Nick \2%s\2 is already registered to your account."), mn->nick); else command_fail(si, fault_alreadyexists, _("Nick \2%s\2 is already registered to \2%s\2."), mn->nick, entity(mn->owner)->name); return; } if (IsDigit(si->su->nick[0])) { command_fail(si, fault_badparams, _("For security reasons, you can't register your UID.")); return; } if (metadata_find(si->smu, "private:restrict:setter")) { command_fail(si, fault_noprivs, _("You have been restricted from grouping nicks by network staff.")); return; } hdata_reg.si = si; hdata_reg.account = si->su->nick; hdata_reg.email = si->smu->email; hdata_reg.approved = 0; hook_call_nick_can_register(&hdata_reg); if (hdata_reg.approved != 0) return; logcommand(si, CMDLOG_REGISTER, "GROUP: \2%s\2 to \2%s\2", si->su->nick, entity(si->smu)->name); mn = mynick_add(si->smu, si->su->nick); mn->registered = CURRTIME; mn->lastseen = CURRTIME; command_success_nodata(si, _("Nick \2%s\2 is now registered to your account."), mn->nick); hdata.si = si; hdata.mu = si->smu; hdata.mn = mn; hook_call_nick_group(&hdata); }
void handle_request(worker_type_t wtype) { const char *param, *p_method, *p_uri; char *argp; unsigned int plen; int cluster_readonly = 0, s2sreq = 0; if(sx_hashfs_cluster_get_mode(hashfs, &cluster_readonly)) { CRIT("Failed to get cluster operating mode"); quit_errmsg(500, "Internal error: failed to check cluster operating mode"); } if(sx_hashfs_distcheck(hashfs) < 0) { CRIT("Failed to reload distribution"); quit_errmsg(503, "Internal error: failed to load distribution"); } if(sx_hashfs_is_orphan(hashfs)) quit_errmsg(410, "This node is no longer a cluster member"); msg_new_id(); verb = VERB_UNSUP; p_method = FCGX_GetParam("REQUEST_METHOD", envp); if(p_method) { plen = strlen(p_method); switch(plen) { case 3: if(!memcmp(p_method, "GET", 4)) verb = VERB_GET; else if(!memcmp(p_method, "PUT", 4)) verb = VERB_PUT; break; case 4: if(!memcmp(p_method, "HEAD", 5)) verb = VERB_HEAD; else if(!memcmp(p_method, "POST", 5)) verb = VERB_POST; break; case 6: if(!memcmp(p_method, "DELETE", 7)) verb = VERB_DELETE; break; case 7: if(!memcmp(p_method, "OPTIONS", 8)) { CGI_PUTS("Allow: GET,HEAD,OPTIONS,PUT,DELETE\r\nContent-Length: 0\r\n\r\n"); return; } break; } } if(verb == VERB_UNSUP) quit_errmsg(405, "Method Not Allowed"); if(content_len()<0 || (verb != VERB_PUT && content_len())) quit_errmsg(400, "Invalid Content-Length: must be positive and method must be PUT"); p_uri = param = FCGX_GetParam("REQUEST_URI", envp); if(!p_uri) quit_errmsg(400, "No URI provided"); plen = strlen(p_uri); if(*p_uri != '/') quit_errmsg(400, "URI must start with /"); if(plen > sizeof(reqbuf) - 1) quit_errmsg(414, "URL too long: request line must be <8k"); do { param++; plen--; } while(*param == '/'); if(!strncmp(param, ".s2s/", lenof(".s2s/"))) { param += lenof(".s2s/"); plen -= lenof(".s2s/"); while(*param == '/') { param++; plen--; } s2sreq = 1; } if(wtype == WORKER_S2S && !s2sreq) WARN("Misconfiguration detected. Please make sure your restricted-socket config option is properly set."); /* FIXME: we could detect the opposite kind of mismatch * at the cost of extra complications in the wtype definition * I prefer to privilege simplicity at this point */ memcpy(reqbuf, param, plen+1); argp = memchr(reqbuf, '?', plen); nargs = 0; if(argp) { unsigned int argslen = plen - (argp - reqbuf); plen = argp - reqbuf; do { *argp = '\0'; argp++; argslen--; } while(*argp == '?'); if(!argslen) argp = NULL; else { do { char *nextarg; if(nargs >= MAX_ARGS) quit_errmsg(414, "Too many parameters"); nextarg = memchr(argp, '&', argslen); if(nextarg) { do { *nextarg = '\0'; nextarg++; } while(*nextarg == '&'); } if(*argp) { if(!(args[nargs] = inplace_urldecode(argp, 0, 0, NULL, 1))) quit_errmsg(400, "Invalid URL encoding"); if(sxi_utf8_validate_len(args[nargs]) < 0) quit_errmsg(400, "Parameters with invalid utf-8 encoding"); nargs++; } argslen -= nextarg - argp; argp = nextarg; } while (argp); } } while(plen && reqbuf[plen-1] == '/') { plen--; reqbuf[plen] = '\0'; } path = memchr(reqbuf, '/', plen); if(path) { do { *path = '\0'; path ++; } while(*path == '/'); if(!*path) path = NULL; } volume = *reqbuf ? reqbuf : NULL; int forbidden = 0; if((volume && !inplace_urldecode(volume, '/', 0, &forbidden, 0)) || (path && !inplace_urldecode(path, '/', '/', &forbidden, 0))) { if (forbidden) quit_errmsg(400, "Volume or path with forbidden %2f or %00"); else quit_errmsg(400, "Invalid URL encoding"); } int vlen = volume ? sxi_utf8_validate_len(volume) : 0; int flen = path ? strlen(path) : 0; if (vlen < 0 || flen < 0) quit_errmsg(400, "URL with invalid utf-8 encoding"); if (is_reserved()) { /* No UTF8/url-encoding used on reserved volumes, allow higher limit. * Otherwise we hit the 1024 limit with batch requests already */ if (path && strlen(path) > SXLIMIT_MAX_FILENAME_LEN * 3) { msg_set_reason("Path too long: filename must be <%d bytes (%ld)", SXLIMIT_MAX_FILENAME_LEN*3+ 1, strlen(path)); quit_errmsg(414, msg_get_reason()); } } else { if (flen > SXLIMIT_MAX_FILENAME_LEN) { msg_set_reason("Path too long: filename must be <%d bytes (%d)", SXLIMIT_MAX_FILENAME_LEN + 1, flen); quit_errmsg(414, msg_get_reason()); } } if (volume && strlen(volume) > SXLIMIT_MAX_VOLNAME_LEN) { msg_set_reason("Volume name too long: must be <= %d bytes", SXLIMIT_MAX_VOLNAME_LEN); quit_errmsg(414, msg_get_reason()); } body_ctx = sxi_md_init(); if (!body_ctx || !sxi_sha1_init(body_ctx)) quit_errmsg(500, "Failed to initialize crypto engine"); hmac_ctx = sxi_hmac_sha1_init(); if (!hmac_ctx) quit_errmsg(503, "Cannot initialize crypto library"); authed = AUTH_NOTAUTH; role = PRIV_NONE; /* Begin auth check */ uint8_t buf[AUTHTOK_BIN_LEN], key[AUTH_KEY_LEN]; unsigned int blen = sizeof(buf); time_t reqdate, now; param = FCGX_GetParam("HTTP_AUTHORIZATION", envp); if(!param || strlen(param) != lenof("SKY ") + AUTHTOK_ASCII_LEN || strncmp(param, "SKY ", 4)) { if(volume) { send_authreq(); return; } quit_home(); } if(sxi_b64_dec_core(param+4, buf, &blen) || blen != sizeof(buf)) { send_authreq(); return; } memcpy(user, buf, sizeof(user)); memcpy(rhmac, buf+20, sizeof(rhmac)); if(sx_hashfs_get_user_info(hashfs, user, &uid, key, &role, NULL, &user_quota) != OK) /* no such user */ { DEBUG("No such user: %s", param+4); send_authreq(); return; } DEBUG("Request from uid %lld", (long long)uid); if(cluster_readonly && (verb == VERB_PUT || verb == VERB_DELETE) && !has_priv(PRIV_CLUSTER) && !has_priv(PRIV_ADMIN)) quit_errmsg(503, "Cluster is in read-only mode"); if(s2sreq && !has_priv(PRIV_CLUSTER)) { send_authreq(); return; } if(!sxi_hmac_sha1_init_ex(hmac_ctx, key, sizeof(key))) { WARN("hmac_init failed"); quit_errmsg(500, "Failed to initialize crypto engine"); } if(!sxi_hmac_sha1_update_str(hmac_ctx, p_method)) quit_errmsg(500, "Crypto error authenticating the request"); if(!sxi_hmac_sha1_update_str(hmac_ctx, p_uri+1)) quit_errmsg(500, "Crypto error authenticating the request"); param = FCGX_GetParam("HTTP_DATE", envp); if(!param) quit_errmsg(400, "Missing Date: header"); if(httpdate_to_time_t(param, &reqdate)) quit_errmsg(400, "Date header in wrong format"); now = time(NULL); if(reqdate < now - MAX_CLOCK_DRIFT * 60 || reqdate > now + MAX_CLOCK_DRIFT * 60) { CGI_PUTS("WWW-Authenticate: SKY realm=\"SXCLOCK\"\r\n"); quit_errmsg(401, "Client clock drifted more than "STRIFY(MAX_CLOCK_DRIFT)" minutes"); } if(!sxi_hmac_sha1_update_str(hmac_ctx, param)) quit_errmsg(500, "Crypto error authenticating the request"); if(!content_len()) { /* If no body is present, complete authentication now */ uint8_t chmac[20]; unsigned int chmac_len = 20; if(!sxi_hmac_sha1_update_str(hmac_ctx, "da39a3ee5e6b4b0d3255bfef95601890afd80709")) quit_errmsg(500, "Crypto error authenticating the request"); if(!sxi_hmac_sha1_final(hmac_ctx, chmac, &chmac_len)) quit_errmsg(500, "Crypto error authenticating the request"); if(!hmac_compare(chmac, rhmac, sizeof(rhmac))) { authed = AUTH_OK; } else { /* WARN("auth mismatch"); */ send_authreq(); return; } } else /* Otherwise set it as pending */ authed = AUTH_BODYCHECK; if(has_priv(PRIV_CLUSTER) && sx_hashfs_uses_secure_proto(hashfs) != is_https() && !sx_storage_is_bare(hashfs)) { /* programmed nodes: must obey cluster SSL mode * unprogrammed nodes: can use SSL instead of non-SSL, * it is the cluster's responsibility to initiate programming via SSL, * as the unprogrammed node would accept both * * */ WARN("hashfs use-ssl: %d, https: %d, is_bare: %d", sx_hashfs_uses_secure_proto(hashfs), is_https(), sx_storage_is_bare(hashfs)); quit_errmsg(403, sx_hashfs_uses_secure_proto(hashfs) ? "Cluster operations require SECURE mode" : "Cluster operations require INSECURE mode"); } if(!volume) cluster_ops(); else if(!path) volume_ops(); else file_ops(); if(authed == AUTH_BODYCHECKING) DEBUG("Bad request signature"); sxi_hmac_sha1_cleanup(&hmac_ctx); sxi_md_cleanup(&body_ctx); }
void handle_request(void) { const char *param; char *argp; unsigned int plen; msg_new_id(); verb = VERB_UNSUP; param = FCGX_GetParam("REQUEST_METHOD", envp); if(param) { plen = strlen(param); switch(plen) { case 3: if(!memcmp(param, "GET", 4)) verb = VERB_GET; else if(!memcmp(param, "PUT", 4)) verb = VERB_PUT; break; case 4: if(!memcmp(param, "HEAD", 5)) verb = VERB_HEAD; else if(!memcmp(param, "POST", 5)) verb = VERB_POST; break; case 6: if(!memcmp(param, "DELETE", 7)) verb = VERB_DELETE; break; case 7: if(!memcmp(param, "OPTIONS", 8)) { CGI_PUTS("Allow: GET,HEAD,OPTIONS,PUT,DELETE\r\nContent-Length: 0\r\n\r\n"); return; } break; } } if(verb == VERB_UNSUP) quit_errmsg(405, "Method Not Allowed"); if(content_len()<0 || (verb != VERB_PUT && content_len())) quit_errmsg(400, "Invalid Content-Length: must be positive and method must be PUT"); param = FCGX_GetParam("REQUEST_URI", envp); if(!param) quit_errmsg(400, "No URI provided"); plen = strlen(param); if(*param != '/') quit_errmsg(400, "URI must start with /"); if(plen > sizeof(reqbuf) - 1) quit_errmsg(414, "URL too long: request line must be <8k"); do { param++; plen--; } while(*param == '/'); memcpy(reqbuf, param, plen+1); argp = memchr(reqbuf, '?', plen); nargs = 0; if(argp) { unsigned int argslen = plen - (argp - reqbuf); plen = argp - reqbuf; do { *argp = '\0'; argp++; argslen--; } while(*argp == '?'); if(!argslen) argp = NULL; else { do { char *nextarg; if(nargs >= MAX_ARGS) quit_errmsg(414, "Too many parameters"); nextarg = memchr(argp, '&', argslen); if(nextarg) { do { *nextarg = '\0'; nextarg++; } while(*nextarg == '&'); } if(*argp) { if(!(args[nargs] = inplace_urldecode(argp, 0, 0, NULL))) quit_errmsg(400, "Invalid URL encoding"); if(utf8_validate_len(args[nargs]) < 0) quit_errmsg(400, "Parameters with invalid utf-8 encoding"); nargs++; } argslen -= nextarg - argp; argp = nextarg; } while (argp); } } while(plen && reqbuf[plen-1] == '/') { plen--; reqbuf[plen] = '\0'; } path = memchr(reqbuf, '/', plen); if(path) { do { *path = '\0'; path ++; } while(*path == '/'); if(!*path) path = NULL; } volume = *reqbuf ? reqbuf : NULL; int forbidden = 0; if((volume && !inplace_urldecode(volume, '/', 0, &forbidden)) || (path && !inplace_urldecode(path, '/', '/', &forbidden))) { if (forbidden) quit_errmsg(400, "Volume or path with forbidden %2f or %00"); else quit_errmsg(400, "Invalid URL encoding"); } int vlen = volume ? utf8_validate_len(volume) : 0; int flen = path ? utf8_validate_len(path) : 0; if (vlen < 0 || flen < 0) quit_errmsg(400, "URL with invalid utf-8 encoding"); if (is_reserved()) { /* No UTF8 used on reserved volumes, allow higher limit. * Otherwise we hit the 512 limit with batch requests already */ if (path && strlen(path) > SXLIMIT_MAX_FILENAME_LEN * 12) { msg_set_reason("Path too long: filename must be <%d characters (%ld)", SXLIMIT_MAX_FILENAME_LEN*12+ 1, strlen(path)); quit_errmsg(414, msg_get_reason()); } } else { if (flen > SXLIMIT_MAX_FILENAME_LEN) { msg_set_reason("Path too long: filename must be <%d UTF8 characters (%d)", SXLIMIT_MAX_FILENAME_LEN + 1, flen); quit_errmsg(414, msg_get_reason()); } } if (volume && strlen(volume) > SXLIMIT_MAX_VOLNAME_LEN) { msg_set_reason("Volume name too long: must be <= %d bytes", SXLIMIT_MAX_VOLNAME_LEN); quit_errmsg(414, msg_get_reason()); } if(!EVP_DigestInit(&body_ctx, EVP_sha1())) quit_errmsg(500, "Failed to initialize crypto engine"); HMAC_CTX_init(&hmac_ctx); authed = AUTH_NOTAUTH; role = PRIV_NONE; auth_begin(); if(has_priv(PRIV_CLUSTER) && sx_hashfs_uses_secure_proto(hashfs) != is_https() && !sx_storage_is_bare(hashfs)) { /* programmed nodes: must obey cluster SSL mode * unprogrammed nodes: can use SSL instead of non-SSL, * it is the cluster's responsibility to initiate programming via SSL, * as the unprogrammed node would accept both * * */ WARN("hashfs use-ssl: %d, https: %d, is_bare: %d", sx_hashfs_uses_secure_proto(hashfs), is_https(), sx_storage_is_bare(hashfs)); quit_errmsg(403, sx_hashfs_uses_secure_proto(hashfs) ? "Cluster operations require SECURE mode" : "Cluster operations require INSECURE mode"); } int dc = sx_hashfs_distcheck(hashfs); if(dc < 0) { CRIT("Failed to reload distribution"); /* MODHDIST: should die here */ } if(!volume) cluster_ops(); else if(!path) volume_ops(); else file_ops(); if(authed == AUTH_BODYCHECKING) WARN("FIXME: Security fail"); HMAC_CTX_cleanup(&hmac_ctx); EVP_MD_CTX_cleanup(&body_ctx); }
static void os_cmd_specs(sourceinfo_t *si, int parc, char *parv[]) { user_t *tu = NULL; operclass_t *cl = NULL; const char *targettype = parv[0]; const char *target = parv[1]; unsigned int i; int j, n; if (!has_any_privs(si)) { command_fail(si, fault_noprivs, _("You are not authorized to use %s."), si->service->nick); return; } if (targettype != NULL) { if (!has_priv(si, PRIV_VIEWPRIVS)) { command_fail(si, fault_noprivs, STR_NO_PRIVILEGE, PRIV_VIEWPRIVS); return; } if (target == NULL) target = "?"; if (!strcasecmp(targettype, "USER")) { tu = user_find_named(target); if (tu == NULL) { command_fail(si, fault_nosuch_target, _("\2%s\2 is not on IRC."), target); return; } if (!has_any_privs_user(tu)) { command_success_nodata(si, _("\2%s\2 is unprivileged."), tu->nick); return; } if (is_internal_client(tu)) { command_fail(si, fault_noprivs, _("\2%s\2 is an internal client."), tu->nick); return; } } else if (!strcasecmp(targettype, "OPERCLASS") || !strcasecmp(targettype, "CLASS")) { cl = operclass_find(target); if (cl == NULL) { command_fail(si, fault_nosuch_target, _("No such oper class \2%s\2."), target); return; } } else { command_fail(si, fault_badparams, _("Valid target types: USER, OPERCLASS.")); return; } } else tu = si->su; if (targettype == NULL) command_success_nodata(si, _("Privileges for \2%s\2:"), get_source_name(si)); else if (tu) command_success_nodata(si, _("Privileges for \2%s\2:"), tu->nick); else command_success_nodata(si, _("Privileges for oper class \2%s\2:"), cl->name); for (i = 0; i < ARRAY_SIZE(priv_categories); i++) { struct priv_category *cat = priv_categories[i]; command_success_nodata(si, "\2%s\2:", _(cat->name)); for (j = n = 0; cat->privs[j].priv != NULL; j++) { if (targettype == NULL ? has_priv(si, cat->privs[j].priv) : (tu ? has_priv_user(tu, cat->privs[j].priv) : has_priv_operclass(cl, cat->privs[j].priv))) { command_success_nodata(si, " %s (%s)", cat->privs[j].priv, _(cat->privs[j].desc)); ++n; } } if (!n) command_success_nodata(si, " %s", _("(no privileges held)")); } command_success_nodata(si, _("End of privileges")); if (targettype == NULL) logcommand(si, CMDLOG_ADMIN, "SPECS"); else if (tu) logcommand(si, CMDLOG_ADMIN, "SPECS:USER: \2%s!%s@%s\2", tu->nick, tu->user, tu->vhost); else logcommand(si, CMDLOG_ADMIN, "SPECS:OPERCLASS: \2%s\2", cl->name); }
static void ns_cmd_sendpass(sourceinfo_t *si, int parc, char *parv[]) { myuser_t *mu; char *name = parv[0]; char *newpass = NULL; char *key; metadata_t *md; enum specialoperation op = op_none; bool ismarked = false; char cmdtext[NICKLEN + 20]; hook_user_needforce_t needforce_hdata; if (!name) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "SENDPASS"); command_fail(si, fault_needmoreparams, _("Syntax: SENDPASS <account>")); return; } if (parc > 1) { if (!strcasecmp(parv[1], "FORCE")) op = op_force; else if (!strcasecmp(parv[1], "CLEAR")) op = op_clear; else { command_fail(si, fault_badparams, STR_INVALID_PARAMS, "SENDPASS"); command_fail(si, fault_badparams, _("Syntax: SENDPASS <account> [FORCE|CLEAR]")); return; } } if (!(mu = myuser_find_by_nick(name))) { command_fail(si, fault_nosuch_target, _("\2%s\2 is not registered."), name); return; } if (is_soper(mu) && !has_priv(si, PRIV_ADMIN)) { logcommand(si, CMDLOG_ADMIN, "failed SENDPASS \2%s\2 (is SOPER)", name); command_fail(si, fault_badparams, _("\2%s\2 belongs to a services operator; you need %s privilege to send the password."), name, PRIV_ADMIN); return; } if (mu->flags & MU_WAITAUTH) { command_fail(si, fault_badparams, _("\2%s\2 is not verified."), entity(mu)->name); return; } if ((md = metadata_find(mu, "private:mark:setter"))) { ismarked = true; if (op == op_none) { logcommand(si, CMDLOG_ADMIN, "failed SENDPASS \2%s\2 (marked by \2%s\2)", entity(mu)->name, md->value); command_fail(si, fault_badparams, _("This operation cannot be performed on %s, because the account has been marked by %s."), entity(mu)->name, md->value); if (has_priv(si, PRIV_MARK)) { snprintf(cmdtext, sizeof cmdtext, "SENDPASS %s FORCE", entity(mu)->name); command_fail(si, fault_badparams, _("Use %s to override this restriction."), cmdtext); } return; } else if (!has_priv(si, PRIV_MARK)) { logcommand(si, CMDLOG_ADMIN, "failed SENDPASS \2%s\2 (marked by \2%s\2)", entity(mu)->name, md->value); command_fail(si, fault_noprivs, STR_NO_PRIVILEGE, PRIV_MARK); return; } } needforce_hdata.si = si; needforce_hdata.mu = mu; needforce_hdata.allowed = 1; hook_call_user_needforce(&needforce_hdata); if (!needforce_hdata.allowed) { ismarked = true; if (op == op_none) { logcommand(si, CMDLOG_ADMIN, "failed SENDPASS \2%s\2 (marked)", entity(mu)->name); command_fail(si, fault_badparams, _("This operation cannot be performed on %s, because the account has been marked."), entity(mu)->name); if (has_priv(si, PRIV_MARK)) { snprintf(cmdtext, sizeof cmdtext, "SENDPASS %s FORCE", entity(mu)->name); command_fail(si, fault_badparams, _("Use %s to override this restriction."), cmdtext); } return; } else if (!has_priv(si, PRIV_MARK)) { logcommand(si, CMDLOG_ADMIN, "failed SENDPASS \2%s\2 (marked)", entity(mu)->name); command_fail(si, fault_noprivs, STR_NO_PRIVILEGE, PRIV_MARK); return; } } if (op == op_clear) { if (metadata_find(mu, "private:setpass:key")) { metadata_delete(mu, "private:setpass:key"); metadata_delete(mu, "private:sendpass:sender"); metadata_delete(mu, "private:sendpass:timestamp"); logcommand(si, CMDLOG_ADMIN, "SENDPASS:CLEAR: \2%s\2", entity(mu)->name); command_success_nodata(si, _("The password change key for \2%s\2 has been cleared."), entity(mu)->name); } else command_fail(si, fault_nochange, _("\2%s\2 did not have a password change key outstanding."), entity(mu)->name); return; } if (MOWGLI_LIST_LENGTH(&mu->logins) > 0) { command_fail(si, fault_noprivs, _("This operation cannot be performed on %s, because someone is logged in to it."), entity(mu)->name); return; } if (metadata_find(mu, "private:freeze:freezer")) { command_fail(si, fault_noprivs, _("%s has been frozen by the %s administration."), entity(mu)->name, me.netname); return; } if (command_find(si->service->commands, "SETPASS")) { if (metadata_find(mu, "private:setpass:key")) { command_fail(si, fault_alreadyexists, _("\2%s\2 already has a password change key outstanding."), entity(mu)->name); command_fail(si, fault_alreadyexists, _("Use SENDPASS %s CLEAR to clear it so that a new one can be sent."), entity(mu)->name); return; } if (ismarked) { wallops("%s sent the password for the \2MARKED\2 account %s.", get_oper_name(si), entity(mu)->name); if (md) command_success_nodata(si, _("Overriding MARK placed by %s on the account %s."), md->value, entity(mu)->name); else command_success_nodata(si, _("Overriding MARK on the account %s."), entity(mu)->name); } logcommand(si, CMDLOG_ADMIN, "SENDPASS: \2%s\2 (change key)", name); key = random_string(12); metadata_add(mu, "private:sendpass:sender", get_oper_name(si)); metadata_add(mu, "private:sendpass:timestamp", number_to_string(time(NULL))); if (!sendemail(si->su != NULL ? si->su : si->service->me, mu, EMAIL_SETPASS, mu->email, key)) { command_fail(si, fault_emailfail, _("Email send failed.")); free(key); return; } metadata_add(mu, "private:setpass:key", crypt_string(key, gen_salt())); free(key); command_success_nodata(si, _("The password change key for \2%s\2 has been sent to \2%s\2."), entity(mu)->name, mu->email); } else { if (ismarked) { wallops("%s sent the password for the \2MARKED\2 account %s.", get_oper_name(si), entity(mu)->name); if (md) command_success_nodata(si, _("Overriding MARK placed by %s on the account %s."), md->value, entity(mu)->name); else command_success_nodata(si, _("Overriding MARK on the account %s."), entity(mu)->name); } logcommand(si, CMDLOG_ADMIN, "SENDPASS: \2%s\2", name); newpass = random_string(12); metadata_add(mu, "private:sendpass:sender", get_oper_name(si)); metadata_add(mu, "private:sendpass:timestamp", number_to_string(time(NULL))); if (!sendemail(si->su != NULL ? si->su : si->service->me, mu, EMAIL_SENDPASS, mu->email, newpass)) { command_fail(si, fault_emailfail, _("Email send failed.")); free(newpass); return; } set_password(mu, newpass); free(newpass); command_success_nodata(si, _("The password for \2%s\2 has been sent to \2%s\2."), entity(mu)->name, mu->email); if (mu->flags & MU_NOPASSWORD) { mu->flags &= ~MU_NOPASSWORD; command_success_nodata(si, _("The \2%s\2 flag has been removed for account \2%s\2."), "NOPASSWORD", entity(mu)->name); } } }
static void gs_cmd_info(sourceinfo_t *si, int parc, char *parv[]) { mygroup_t *mg; struct tm tm; char buf[BUFSIZE], strfbuf[BUFSIZE]; metadata_t *md; if (!parv[0]) { command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "INFO"); command_fail(si, fault_needmoreparams, _("Syntax: INFO <!groupname>")); return; } if (!(mg = mygroup_find(parv[0]))) { command_fail(si, fault_alreadyexists, _("Group \2%s\2 does not exist."), parv[0]); return; } tm = *localtime(&mg->regtime); strftime(strfbuf, sizeof strfbuf, TIME_FORMAT, &tm); command_success_nodata(si, _("Information for \2%s\2:"), parv[0]); command_success_nodata(si, _("Registered : %s (%s ago)"), strfbuf, time_ago(mg->regtime)); if (config_options.show_entity_id || has_priv(si, PRIV_GROUP_AUSPEX)) command_success_nodata(si, _("Entity ID : %s"), entity(mg)->id); if (mg->flags & MG_PUBLIC || (si->smu != NULL && groupacs_sourceinfo_has_flag(mg, si, 0) && !groupacs_sourceinfo_has_flag(mg, si, GA_BAN)) || has_priv(si, PRIV_GROUP_AUSPEX)) command_success_nodata(si, _("Founder : %s"), mygroup_founder_names(mg)); if ((md = metadata_find(mg, "description"))) command_success_nodata(si, _("Description : %s"), md->value); if ((md = metadata_find(mg, "channel"))) command_success_nodata(si, _("Channel : %s"), md->value); if ((md = metadata_find(mg, "url"))) command_success_nodata(si, _("URL : %s"), md->value); if ((md = metadata_find(mg, "email"))) command_success_nodata(si, _("Email : %s"), md->value); *buf = '\0'; if (mg->flags & MG_REGNOLIMIT) mowgli_strlcat(buf, "REGNOLIMIT", BUFSIZE); if (mg->flags & MG_ACSNOLIMIT) { if (*buf) mowgli_strlcat(buf, " ", BUFSIZE); mowgli_strlcat(buf, "ACSNOLIMIT", BUFSIZE); } if (mg->flags & MG_OPEN) { if (*buf) mowgli_strlcat(buf, " ", BUFSIZE); mowgli_strlcat(buf, "OPEN", BUFSIZE); } if (mg->flags & MG_PUBLIC) { if (*buf) mowgli_strlcat(buf, " ", BUFSIZE); mowgli_strlcat(buf, "PUBLIC", BUFSIZE); } if (*buf) command_success_nodata(si, _("Flags : %s"), buf); command_success_nodata(si, _("\2*** End of Info ***\2")); logcommand(si, CMDLOG_GET, "INFO: \2%s\2", parv[0]); }
static void os_cmd_specs(char *origin) { user_t *u = user_find_named(origin), *tu = NULL; operclass_t *cl = NULL; char *targettype = strtok(NULL, " "); char *target = strtok(NULL, " "); char nprivs[BUFSIZE], cprivs[BUFSIZE], gprivs[BUFSIZE], oprivs[BUFSIZE]; int i; if (!has_any_privs(u)) { notice(opersvs.nick, origin, "You are not authorized to use %s.", opersvs.nick); return; } if (targettype != NULL) { if (!has_priv(u, PRIV_VIEWPRIVS)) { notice(opersvs.nick, origin, "You do not have %s privilege.", PRIV_VIEWPRIVS); return; } if (target == NULL) target = "?"; if (!strcasecmp(targettype, "USER")) { tu = user_find_named(target); if (tu == NULL) { notice(opersvs.nick, origin, "\2%s\2 is not on IRC.", target); return; } if (!has_any_privs(tu)) { notice(opersvs.nick, origin, "\2%s\2 is unprivileged.", tu->nick); return; } if (is_internal_client(tu)) { notice(opersvs.nick, origin, "\2%s\2 is an internal client.", tu->nick); return; } } else if (!strcasecmp(targettype, "OPERCLASS") || !strcasecmp(targettype, "CLASS")) { cl = operclass_find(target); if (cl == NULL) { notice(opersvs.nick, origin, "No such oper class \2%s\2.", target); return; } } else { notice(opersvs.nick, origin, "Valid target types: USER, OPERCLASS."); return; } } else tu = u; i = 0; *nprivs = *cprivs = *gprivs = *oprivs = '\0'; while (privnames[i].priv != NULL) { if (tu ? has_priv(tu, privnames[i].priv) : has_priv_operclass(cl, privnames[i].priv)) { if (privnames[i].npriv != NULL) { if (*nprivs) strcat(nprivs, ", "); strcat(nprivs, privnames[i].npriv); } if (privnames[i].cpriv != NULL) { if (*cprivs) strcat(cprivs, ", "); strcat(cprivs, privnames[i].cpriv); } if (privnames[i].gpriv != NULL) { if (*gprivs) strcat(gprivs, ", "); strcat(gprivs, privnames[i].gpriv); } if (privnames[i].opriv != NULL) { if (*oprivs) strcat(oprivs, ", "); strcat(oprivs, privnames[i].opriv); } } i++; } if (tu) notice(opersvs.nick, origin, "Privileges for \2%s\2:", tu->nick); else notice(opersvs.nick, origin, "Privileges for oper class \2%s\2:", cl->name); if (*nprivs) notice(opersvs.nick, origin, "\2Nicknames/accounts\2: %s", nprivs); if (*cprivs) notice(opersvs.nick, origin, "\2Channels\2: %s", cprivs); if (*gprivs) notice(opersvs.nick, origin, "\2General\2: %s", gprivs); if (*oprivs) notice(opersvs.nick, origin, "\2OperServ\2: %s", oprivs); notice(opersvs.nick, origin, "End of privileges"); if (tu) logcommand(opersvs.me, user_find_named(origin), CMDLOG_ADMIN, "SPECS USER %s!%s@%s", tu->nick, tu->user, tu->vhost); else logcommand(opersvs.me, user_find_named(origin), CMDLOG_ADMIN, "SPECS OPERCLASS %s", cl->name); }