X-Git-Url: https://jfr.im/git/irc/evilnet/x3.git/blobdiff_plain/50c7ed1bffc915d89b4b8357ae39819155c445de..2fa83595ce1f9c3137e093e50590c5485817c54b:/src/nickserv.c diff --git a/src/nickserv.c b/src/nickserv.c index 0e8c858..1809e8c 100644 --- a/src/nickserv.c +++ b/src/nickserv.c @@ -88,6 +88,7 @@ #define KEY_PASSWD "passwd" #define KEY_NICKS "nicks" #define KEY_MASKS "masks" +#define KEY_SSLFPS "sslfps" #define KEY_IGNORES "ignores" #define KEY_OPSERV_LEVEL "opserv_level" #define KEY_FLAGS "flags" @@ -238,7 +239,7 @@ static const struct message_entry msgtab[] = { { "NSMSG_HANDLEINFO_REGGED", "Registered on: %s" }, { "NSMSG_HANDLEINFO_LASTSEEN", "Last seen: %s" }, { "NSMSG_HANDLEINFO_LASTSEEN_NOW", "Last seen: Right now!" }, - { "NSMSG_HANDLEINFO_KARMA", " Karma: %d" }, + { "NSMSG_HANDLEINFO_KARMA", "Karma: %d" }, { "NSMSG_HANDLEINFO_VACATION", "On vacation." }, { "NSMSG_HANDLEINFO_EMAIL_ADDR", "Email address: %s" }, { "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", "Cookie: There is currently an activation cookie issued for this account" }, @@ -257,6 +258,7 @@ static const struct message_entry msgtab[] = { { "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", "Last quit hostmask: Unknown" }, { "NSMSG_HANDLEINFO_NICKS", "Nickname(s): %s" }, { "NSMSG_HANDLEINFO_MASKS", "Hostmask(s): %s" }, + { "NSMSG_HANDLEINFO_SSLFPS", "SSL Fingerprints(s): %s" }, { "NSMSG_HANDLEINFO_IGNORES", "Ignore(s): %s" }, { "NSMSG_HANDLEINFO_CHANNELS", "Channel(s): %s" }, { "NSMSG_HANDLEINFO_CURRENT", "Current nickname(s): %s" }, @@ -286,9 +288,13 @@ static const struct message_entry msgtab[] = { { "NSMSG_ADDMASK_SUCCESS", "Hostmask %s added." }, { "NSMSG_ADDIGNORE_ALREADY", "$b%s$b is already an ignored hostmask in your account." }, { "NSMSG_ADDIGNORE_SUCCESS", "Hostmask %s added." }, + { "NSMSG_ADDSSLFP_ALREADY", "$b%s$b is already an SSL fingerprint in your account." }, + { "NSMSG_ADDSSLFP_SUCCESS", "SSL fingerprint %s added." }, { "NSMSG_DELMASK_NOTLAST", "You may not delete your last hostmask." }, { "NSMSG_DELMASK_SUCCESS", "Hostmask %s deleted." }, { "NSMSG_DELMASK_NOT_FOUND", "Unable to find mask to be deleted." }, + { "NSMSG_DELSSLFP_SUCCESS", "SSL fingerprint %s deleted." }, + { "NSMSG_DELSSLFP_NOT_FOUND", "Unable to find SSL fingerprint to be deleted." }, { "NSMSG_OPSERV_LEVEL_BAD", "You may not promote another oper above your level." }, { "NSMSG_USE_CMD_PASS", "Please use the PASS command to change your password." }, { "NSMSG_UNKNOWN_NICK", "I know nothing about nick $b%s$b." }, @@ -504,21 +510,25 @@ delete_nick(struct nick_info *ni) } static unreg_func_t *unreg_func_list; +static void **unreg_func_list_extra; static unsigned int unreg_func_size = 0, unreg_func_used = 0; void -reg_unreg_func(unreg_func_t func) +reg_unreg_func(unreg_func_t func, void *extra) { if (unreg_func_used == unreg_func_size) { if (unreg_func_size) { unreg_func_size <<= 1; unreg_func_list = realloc(unreg_func_list, unreg_func_size*sizeof(unreg_func_t)); + unreg_func_list_extra = realloc(unreg_func_list_extra, unreg_func_size*sizeof(void*)); } else { unreg_func_size = 8; unreg_func_list = malloc(unreg_func_size*sizeof(unreg_func_t)); + unreg_func_list_extra = malloc(unreg_func_size*sizeof(void*)); } } - unreg_func_list[unreg_func_used++] = func; + unreg_func_list[unreg_func_used] = func; + unreg_func_list_extra[unreg_func_used++] = extra; } static void @@ -536,6 +546,7 @@ free_handle_info(void *vhi) struct handle_info *hi = vhi; free_string_list(hi->masks); + free_string_list(hi->sslfps); free_string_list(hi->ignores); assert(!hi->users); @@ -581,7 +592,7 @@ nickserv_unregister_handle(struct handle_info *hi, struct userNode *notify, stru } #endif for (n=0; nusers) { if (nickserv_conf.sync_log) { uNode = GetUserH(hi->users->nick); @@ -827,6 +838,25 @@ valid_user_for(struct userNode *user, struct handle_info *hi) return 0; } +static int +valid_user_sslfp(struct userNode *user, struct handle_info *hi) +{ + unsigned int ii; + + if (!hi->sslfps->used) + return 0; + if (!(user->sslfp)) + return 0; + + /* If any SSL fingerprint matches, allow it. */ + for (ii=0; iisslfps->used; ii++) + if (!irccasecmp(user->sslfp, hi->sslfps->list[ii])) + return 1; + + /* No valid SSL fingerprint found. */ + return 0; +} + static int is_secure_password(const char *handle, const char *pass, struct userNode *user) { @@ -870,21 +900,25 @@ is_secure_password(const char *handle, const char *pass, struct userNode *user) } static auth_func_t *auth_func_list; +static void **auth_func_list_extra; static unsigned int auth_func_size = 0, auth_func_used = 0; void -reg_auth_func(auth_func_t func) +reg_auth_func(auth_func_t func, void *extra) { if (auth_func_used == auth_func_size) { if (auth_func_size) { auth_func_size <<= 1; auth_func_list = realloc(auth_func_list, auth_func_size*sizeof(auth_func_t)); + auth_func_list_extra = realloc(auth_func_list_extra, auth_func_size*sizeof(void*)); } else { auth_func_size = 8; auth_func_list = malloc(auth_func_size*sizeof(auth_func_t)); + auth_func_list_extra = malloc(auth_func_size*sizeof(void*)); } } - auth_func_list[auth_func_used++] = func; + auth_func_list[auth_func_used] = func; + auth_func_list_extra[auth_func_used++] = extra; } static handle_rename_func_t *rf_list; @@ -964,7 +998,7 @@ void send_func_list(struct userNode *user) old_info = user->handle_info; for (n=0; nnick)) { for (n=0; ndead) return; } @@ -1104,7 +1138,7 @@ nickserv_register(struct userNode *user, struct userNode *settee, const char *ha #ifdef WITH_LDAP if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) { int rc; - rc = ldap_do_add(handle, crypted, NULL); + rc = ldap_do_add(handle, (no_auth ? NULL : crypted), NULL); if(LDAP_SUCCESS != rc && LDAP_ALREADY_EXISTS != rc ) { if(user) send_message(user, nickserv, "NSMSG_LDAP_FAIL", ldap_err2string(rc)); @@ -1114,6 +1148,7 @@ nickserv_register(struct userNode *user, struct userNode *settee, const char *ha #endif hi = register_handle(handle, crypted, 0); hi->masks = alloc_string_list(1); + hi->sslfps = alloc_string_list(1); hi->ignores = alloc_string_list(1); hi->users = NULL; hi->language = lang_C; @@ -1498,11 +1533,8 @@ static NICKSERV_FUNC(cmd_oregister) if (nickserv_conf.email_required) { NICKSERV_MIN_PARMS(3); email = argv[3]; - if (argc >= 4) {/* take: "acct pass email mask nick" or "acct pass email mask" or "acct pass email nick" */ - if (argc < 4) { - mask = NULL; - settee = NULL; - } else if (strchr(argv[4], '@')) + if (argc > 4) {/* take: "acct pass email mask nick" or "acct pass email mask" or "acct pass email nick" */ + if (strchr(argv[4], '@')) mask = argv[4]; else nick = argv[4]; @@ -1512,11 +1544,8 @@ static NICKSERV_FUNC(cmd_oregister) } } else { - if (argc >= 4) {/* take: "account pass mask nick" or "account pass mask" or "account pass nick" */ - if (argc < 4) { - mask = NULL; - settee = NULL; - } else if (strchr(argv[3], '@')) + if (argc > 3) {/* take: "account pass mask nick" or "account pass mask" or "account pass nick" */ + if (strchr(argv[3], '@')) mask = argv[3]; else nick = argv[3]; @@ -1803,6 +1832,26 @@ static NICKSERV_FUNC(cmd_handleinfo) reply("NSMSG_HANDLEINFO_MASKS", nsmsg_none); } + if (hi->sslfps->used) { + for (i=0; i < hi->sslfps->used; i++) { + herelen = strlen(hi->sslfps->list[i]); + if (pos + herelen + 1 > ArrayLength(buff)) { + i--; + goto print_sslfp_buff; + } + memcpy(buff+pos, hi->sslfps->list[i], herelen); + pos += herelen; buff[pos++] = ' '; + if (i+1 == hi->sslfps->used) { + print_sslfp_buff: + buff[pos-1] = 0; + reply("NSMSG_HANDLEINFO_SSLFPS", buff); + pos = 0; + } + } + } else { + reply("NSMSG_HANDLEINFO_SSLFPS", nsmsg_none); + } + if (hi->ignores->used) { for (i=0; i < hi->ignores->used; i++) { herelen = strlen(hi->ignores->list[i]); @@ -2271,10 +2320,10 @@ static NICKSERV_FUNC(cmd_auth) return 1; } #ifdef WITH_LDAP - if( ( nickserv_conf.ldap_enable && ldap_result == LDAP_INVALID_CREDENTIALS ) || - ( (!nickserv_conf.ldap_enable) && (!checkpass(passwd, hi->passwd)) ) ) { + if(( ( nickserv_conf.ldap_enable && ldap_result == LDAP_INVALID_CREDENTIALS ) || + ( (!nickserv_conf.ldap_enable) && (!checkpass(passwd, hi->passwd)) ) ) && !valid_user_sslfp(user, hi)) { #else - if (!checkpass(passwd, hi->passwd)) { + if (!checkpass(passwd, hi->passwd) && !valid_user_sslfp(user, hi)) { #endif unsigned int n; send_message_type(4, user, cmd->parent->bot, @@ -2520,39 +2569,26 @@ static NICKSERV_FUNC(cmd_odelcookie) switch (hi->cookie->type) { case ACTIVATION: safestrncpy(hi->passwd, hi->cookie->data, sizeof(hi->passwd)); - if (nickserv_conf.sync_log) - SyncLog("ACCOUNTACC %s", hi->handle); - break; - case PASSWORD_CHANGE: - safestrncpy(hi->passwd, hi->cookie->data, sizeof(hi->passwd)); - if (nickserv_conf.sync_log) - SyncLog("PASSCHANGE %s %s", hi->handle, hi->passwd); - break; - case EMAIL_CHANGE: - if (!hi->email_addr && nickserv_conf.sync_log) { - if (nickserv_conf.sync_log) - SyncLog("REGISTER %s %s %s %s", hi->handle, hi->passwd, hi->cookie->data, user->info); - } #ifdef WITH_LDAP if(nickserv_conf.ldap_enable && nickserv_conf.ldap_admin_dn) { int rc; - if((rc = ldap_do_modify(hi->handle, NULL, hi->cookie->data)) != LDAP_SUCCESS) { - /* Falied to update email in ldap, but still + if((rc = ldap_do_modify(hi->handle, hi->cookie->data, NULL)) != LDAP_SUCCESS) { + /* Falied to update password in ldap, but still * updated it here.. what should we do? */ - reply("NSMSG_LDAP_FAIL_SEND_EMAIL", ldap_err2string(rc)); - } else { - nickserv_set_email_addr(hi, hi->cookie->data); + reply("NSMSG_LDAP_FAIL", ldap_err2string(rc)); + return 0; } } - else { - nickserv_set_email_addr(hi, hi->cookie->data); - } -#else - nickserv_set_email_addr(hi, hi->cookie->data); #endif if (nickserv_conf.sync_log) - SyncLog("EMAILCHANGE %s %s", hi->handle, hi->cookie->data); + SyncLog("ACCOUNTACC %s", hi->handle); break; + case PASSWORD_CHANGE: + break; + case EMAIL_CHANGE: + break; + case ALLOWAUTH: + break; default: reply("NSMSG_BAD_COOKIE_TYPE", hi->cookie->type); log_module(NS_LOG, LOG_ERROR, "Bad cookie type %d for account %s.", hi->cookie->type, hi->handle); @@ -2903,6 +2939,80 @@ static NICKSERV_FUNC(cmd_odelmask) return nickserv_delmask(cmd, user, hi, argv[2], 1); } +static int +nickserv_addsslfp(struct userNode *user, struct handle_info *hi, const char *sslfp) +{ + unsigned int i; + char *new_sslfp = strdup(sslfp); + for (i=0; isslfps->used; i++) { + if (!irccasecmp(new_sslfp, hi->sslfps->list[i])) { + send_message(user, nickserv, "NSMSG_ADDSSLFP_ALREADY", new_sslfp); + free(new_sslfp); + return 0; + } + } + string_list_append(hi->sslfps, new_sslfp); + send_message(user, nickserv, "NSMSG_ADDSSLFP_SUCCESS", new_sslfp); + return 1; +} + +static NICKSERV_FUNC(cmd_addsslfp) +{ + NICKSERV_MIN_PARMS((user->sslfp ? 1 : 2)); + if ((argc < 2) && (user->sslfp)) { + int res = nickserv_addsslfp(user, user->handle_info, user->sslfp); + return res; + } else { + return nickserv_addsslfp(user, user->handle_info, argv[1]); + } +} + +static NICKSERV_FUNC(cmd_oaddsslfp) +{ + struct handle_info *hi; + + NICKSERV_MIN_PARMS(3); + if (!(hi = get_victim_oper(user, argv[1]))) + return 0; + return nickserv_addsslfp(user, hi, argv[2]); +} + +static int +nickserv_delsslfp(struct svccmd *cmd, struct userNode *user, struct handle_info *hi, const char *del_sslfp) +{ + unsigned int i; + for (i=0; isslfps->used; i++) { + if (!irccasecmp(del_sslfp, hi->sslfps->list[i])) { + char *old_sslfp = hi->sslfps->list[i]; + hi->sslfps->list[i] = hi->sslfps->list[--hi->sslfps->used]; + reply("NSMSG_DELSSLFP_SUCCESS", old_sslfp); + free(old_sslfp); + return 1; + } + } + reply("NSMSG_DELSSLFP_NOT_FOUND"); + return 0; +} + +static NICKSERV_FUNC(cmd_delsslfp) +{ + NICKSERV_MIN_PARMS((user->sslfp ? 1 : 2)); + if ((argc < 2) && (user->sslfp)) { + return nickserv_delsslfp(cmd, user, user->handle_info, user->sslfp); + } else { + return nickserv_delsslfp(cmd, user, user->handle_info, argv[1]); + } +} + +static NICKSERV_FUNC(cmd_odelsslfp) +{ + struct handle_info *hi; + NICKSERV_MIN_PARMS(3); + if (!(hi = get_victim_oper(user, argv[1]))) + return 0; + return nickserv_delsslfp(cmd, user, hi, argv[2]); +} + int nickserv_modify_handle_flags(struct userNode *user, struct userNode *bot, const char *str, unsigned long *padded, unsigned long *premoved) { unsigned int nn, add = 1, pos; @@ -3382,7 +3492,7 @@ oper_try_set_access(struct userNode *user, struct userNode *bot, struct handle_i } if(nickserv_conf.ldap_enable && *(nickserv_conf.ldap_field_oslevel) && *(nickserv_conf.ldap_admin_dn)) { int rc; - if((rc = ldap_do_oslevel(target->handle, new_level)) != LDAP_SUCCESS) { + if((rc = ldap_do_oslevel(target->handle, new_level, target->opserv_level)) != LDAP_SUCCESS) { send_message(user, bot, "NSMSG_LDAP_FAIL", ldap_err2string(rc)); return 0; } @@ -3893,6 +4003,8 @@ nickserv_saxdb_write(struct saxdb_context *ctx) { saxdb_write_sint(ctx, KEY_KARMA, hi->karma); if (hi->masks->used) saxdb_write_string_list(ctx, KEY_MASKS, hi->masks); + if (hi->sslfps->used) + saxdb_write_string_list(ctx, KEY_SSLFPS, hi->sslfps); if (hi->ignores->used) saxdb_write_string_list(ctx, KEY_IGNORES, hi->ignores); if (hi->maxlogins) @@ -4505,7 +4617,7 @@ static void nickserv_db_read_handle(char *handle, dict_t obj) { const char *str; - struct string_list *masks, *slist, *ignores; + struct string_list *masks, *sslfps, *slist, *ignores; struct handle_info *hi; struct userNode *authed_users; struct userData *channel_list; @@ -4545,6 +4657,8 @@ nickserv_db_read_handle(char *handle, dict_t obj) hi->channels = channel_list; masks = database_get_data(obj, KEY_MASKS, RECDB_STRING_LIST); hi->masks = masks ? string_list_copy(masks) : alloc_string_list(1); + sslfps = database_get_data(obj, KEY_SSLFPS, RECDB_STRING_LIST); + hi->sslfps = sslfps ? string_list_copy(sslfps) : alloc_string_list(1); ignores = database_get_data(obj, KEY_IGNORES, RECDB_STRING_LIST); hi->ignores = ignores ? string_list_copy(ignores) : alloc_string_list(1); str = database_get_data(obj, KEY_MAXLOGINS, RECDB_QSTRING); @@ -5169,7 +5283,7 @@ nickserv_define_func(const char *name, modcmd_func_t func, int min_level, int mu } static void -nickserv_db_cleanup(void) +nickserv_db_cleanup(UNUSED_ARG(void* extra)) { unreg_del_user_func(nickserv_remove_user, NULL); userList_clean(&curr_helpers); @@ -5182,7 +5296,9 @@ nickserv_db_cleanup(void) dict_delete(nickserv_id_dict); dict_delete(nickserv_conf.weak_password_dict); free(auth_func_list); + free(auth_func_list_extra); free(unreg_func_list); + free(unreg_func_list_extra); free(rf_list); free(rf_list_extra); free(allowauth_func_list); @@ -5197,7 +5313,7 @@ nickserv_db_cleanup(void) regfree(&nickserv_conf.valid_nick_regex); } -void handle_loc_auth_oper(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle)) { +void handle_loc_auth_oper(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle), UNUSED_ARG(void *extra)) { if (!*nickserv_conf.auto_oper || !user->handle_info) return; @@ -5224,7 +5340,7 @@ init_nickserv(const char *nick) reg_nick_change_func(handle_nick_change, NULL); reg_del_user_func(nickserv_remove_user, NULL); reg_account_func(handle_account); - reg_auth_func(handle_loc_auth_oper); + reg_auth_func(handle_loc_auth_oper, NULL); /* set up handle_inverse_flags */ memset(handle_inverse_flags, 0, sizeof(handle_inverse_flags)); @@ -5255,6 +5371,10 @@ init_nickserv(const char *nick) nickserv_define_func("OADDMASK", cmd_oaddmask, 0, 1, 0); nickserv_define_func("DELMASK", cmd_delmask, -1, 1, 0); nickserv_define_func("ODELMASK", cmd_odelmask, 0, 1, 0); + nickserv_define_func("ADDSSLFP", cmd_addsslfp, -1, 1, 0); + nickserv_define_func("OADDSSLFP", cmd_oaddsslfp, 0, 1, 0); + nickserv_define_func("DELSSLFP", cmd_delsslfp, -1, 1, 0); + nickserv_define_func("ODELSSLFP", cmd_odelsslfp, 0, 1, 0); nickserv_define_func("PASS", cmd_pass, -1, 1, 0); nickserv_define_func("SET", cmd_set, -1, 1, 0); nickserv_define_func("OSET", cmd_oset, 0, 1, 0); @@ -5338,7 +5458,7 @@ init_nickserv(const char *nick) nickserv_service = service_register(nickserv); } saxdb_register("NickServ", nickserv_saxdb_read, nickserv_saxdb_write); - reg_exit_func(nickserv_db_cleanup); + reg_exit_func(nickserv_db_cleanup, NULL); if(nickserv_conf.handle_expire_frequency) timeq_add(now + nickserv_conf.handle_expire_frequency, expire_handles, NULL);