Example #1
0
char *gen_salt(void)
{
	char *ht = gen_pw(6);

	strlcpy(saltbuf, "$1$", BUFSIZE);
	strlcat(saltbuf, ht, BUFSIZE);
	strlcat(saltbuf, "$", BUFSIZE);

	free(ht);

	return saltbuf;
}
Example #2
0
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];

	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(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;
		}
	}

	if (op == op_clear)
	{
		if (metadata_find(mu, "private:setpass:key"))
		{
			metadata_delete(mu, "private:setpass:key");
			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_success_nodata(si, _("%s has been frozen by the %s administration."), entity(mu)->name, me.netname);
		return;
	}

	/* alternative, safer method? */
	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;
		}
		key = gen_pw(12);
		if (sendemail(si->su != NULL ? si->su : si->service->me, EMAIL_SETPASS, mu, key))
		{
			metadata_add(mu, "private:setpass:key", crypt_string(key, gen_salt()));
			logcommand(si, CMDLOG_ADMIN, "SENDPASS: \2%s\2 (change key)", name);
			command_success_nodata(si, _("The password change key for \2%s\2 has been sent to \2%s\2."), entity(mu)->name, mu->email);
			if (ismarked)
			{
				wallops("%s sent the password for the \2MARKED\2 account %s.", get_oper_name(si), entity(mu)->name);
				command_success_nodata(si, _("Overriding MARK placed by %s on the account %s."), md->value, entity(mu)->name);
			}
		}
		else
			command_fail(si, fault_emailfail, _("Email send failed."));
		free(key);
		return;
	}

	/* this is not without controversy... :) */
	if (mu->flags & MU_CRYPTPASS)
	{
		command_success_nodata(si, _("The password for the account \2%s\2 is encrypted; a new password will be assigned and sent."), name);
		newpass = gen_pw(12);
		set_password(mu, newpass);
	}

	if (sendemail(si->su != NULL ? si->su : si->service->me, EMAIL_SENDPASS, mu, (newpass == NULL) ? mu->pass : newpass))
	{
		logcommand(si, CMDLOG_ADMIN, "SENDPASS: \2%s\2", name);
		command_success_nodata(si, _("The password for \2%s\2 has been sent to \2%s\2."), entity(mu)->name, mu->email);
		if (ismarked)
		{
			wallops("%s sent the password for the \2MARKED\2 account %s.", get_oper_name(si), entity(mu)->name);
			command_success_nodata(si, _("Overriding MARK placed by %s on the account %s."), md->value, entity(mu)->name);
		}
	}
	else
		command_fail(si, fault_emailfail, _("Email send failed."));

	if (newpass != NULL)
		free(newpass);

	return;
}
Example #3
0
static void ns_cmd_register(sourceinfo_t *si, int parc, char *parv[])
{
    myuser_t *mu;
    mynick_t *mn = NULL;
    mowgli_node_t *n;
    char *account;
    char *pass;
    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 (!crypto_module_loaded && 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);
        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 ((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->nick);
        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;
    }

    /* make sure they're within limits */
    if (me.maxusers > 0)
    {
        tcnt = 0;
        myentity_foreach_t(ENT_USER, register_foreach_cb, email);

        if (tcnt >= me.maxusers)
        {
            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 = gen_pw(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, EMAIL_REGISTER, mu, 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);
    }
}