X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Fs_auth.c;h=b3e993af3137b147814043082d07d2626e9daec6;hb=c2ad630afaab5353b2656f6cd5d591f8a2488692;hp=d70ab971072a56b83e953760cd3ce28c24f02dba;hpb=a36ad5e29241b0c89379947b13887cb6930ef3e0;p=ircu2.10.12-pk.git diff --git a/ircd/s_auth.c b/ircd/s_auth.c index d70ab97..b3e993a 100644 --- a/ircd/s_auth.c +++ b/ircd/s_auth.c @@ -52,6 +52,7 @@ #include "list.h" #include "msg.h" /* for MAXPARA */ #include "numeric.h" +#include "numnicks.h" #include "querycmds.h" #include "random.h" #include "res.h" @@ -83,6 +84,7 @@ enum AuthRequestFlag { AR_IAUTH_HURRY, /**< we told iauth to hurry up */ AR_IAUTH_USERNAME, /**< iauth sent a username (preferred or forced) */ AR_IAUTH_FUSERNAME, /**< iauth sent a forced username */ + AR_IAUTH_SOFT_DONE, /**< iauth has no objection to client */ AR_PASSWORD_CHECKED, /**< client password already checked */ AR_NUM_FLAGS }; @@ -211,6 +213,31 @@ static int preregister_user(struct Client *cptr); typedef int (*iauth_cmd_handler)(struct IAuth *iauth, struct Client *cli, int parc, char **params); +/** Copies a username, cleaning it in the process. + * + * @param[out] dest Destination buffer for user name. + * @param[in] src Source buffer for user name. Must be distinct from + * \a dest. + */ +void clean_username(char *dest, const char *src) +{ + int rlen = USERLEN; + char ch; + + /* First character can be ~, later characters cannot. */ + if (!IsCntrl(*src)) + { + ch = *src++; + *dest++ = IsUserChar(ch) ? ch : '_'; + rlen--; + } + while (rlen-- && !IsCntrl(ch = *src++)) + { + *dest++ = (IsUserChar(ch) && (ch != '~')) ? ch : '_'; + } + *dest = '\0'; +} + /** Set username for user associated with \a auth. * @param[in] auth Client authorization request to work on. * @return Zero if client is kept, CPTR_KILLED if client rejected. @@ -221,11 +248,9 @@ static int auth_set_username(struct AuthRequest *auth) struct User *user = cli_user(sptr); char *d; char *s; - int rlen = USERLEN; int killreason; short upper = 0; short lower = 0; - short pos = 0; short leadcaps = 0; short other = 0; short digits = 0; @@ -233,32 +258,27 @@ static int auth_set_username(struct AuthRequest *auth) char ch; char last; - if (FlagHas(&auth->flags, AR_IAUTH_USERNAME)) + if (FlagHas(&auth->flags, AR_IAUTH_FUSERNAME)) { - ircd_strncpy(cli_user(sptr)->username, cli_username(sptr), USERLEN); + ircd_strncpy(user->username, cli_username(sptr), USERLEN); } - else + else if (IsIdented(sptr)) { - /* Copy username from source to destination. Since they may be the - * same, and we may prefix with a '~', use a buffer character (ch) - * to hold the next character to copy. - */ - s = IsIdented(sptr) ? cli_username(sptr) : user->username; - last = *s++; - d = user->username; - if (HasFlag(sptr, FLAG_DOID) && !IsIdented(sptr)) - { - *d++ = '~'; - --rlen; - } - while (last && !IsCntrl(last) && rlen--) + clean_username(user->username, cli_username(sptr)); + } + else if (HasFlag(sptr, FLAG_DOID)) + { + /* Prepend ~ to user->username. */ + s = user->username; + s[USERLEN] = '\0'; + for (last = '~'; (ch = *s) != '\0'; ) { - ch = *s++; - *d++ = IsUserChar(last) ? last : '_'; - last = (ch != '~') ? ch : '_'; + *s++ = last; + last = ch; } - *d = 0; - } + *s++ = last; + *s = '\0'; + } /* else cleaned version of client-provided name is in place */ /* If username is empty or just ~, reject. */ if ((user->username[0] == '\0') @@ -281,7 +301,7 @@ static int auth_set_username(struct AuthRequest *auth) s = d = user->username + (user->username[0] == '~'); for (last = '\0'; (ch = *d++) != '\0'; - pos++, last = ch) + last = ch) { if (IsLower(ch)) { @@ -291,13 +311,13 @@ static int auth_set_username(struct AuthRequest *auth) { upper++; /* Accept caps as leading if we haven't seen lower case or digits yet. */ - if ((leadcaps || pos == 0) && !lower && !digits) + if ((leadcaps || last == '\0') && !lower && !digits) leadcaps++; } else if (IsDigit(ch)) { digits++; - if (pos == 0 || !IsDigit(last)) + if (!IsDigit(last)) { digitgroups++; /* If more than two groups of digits, reject. */ @@ -309,7 +329,7 @@ static int auth_set_username(struct AuthRequest *auth) { other++; /* If -_. exist at start, consecutively, or more than twice, reject. */ - if (pos == 0 || last == '-' || last == '_' || last == '.' || other > 2) + if (last == '\0' || last == '-' || last == '_' || last == '.' || other > 2) goto badid; } else /* All other punctuation is rejected. */ @@ -527,7 +547,7 @@ static int preregister_user(struct Client *cptr) /* Can this ever happen? */ case ACR_BAD_SOCKET: ++ServerStats->is_ref; - IPcheck_connect_fail(cptr); + IPcheck_connect_fail(cptr, 0); return exit_client(cptr, cptr, &me, "Unknown error -- Try again"); } return 0; @@ -677,6 +697,8 @@ static void read_auth_reply(struct AuthRequest* auth) if (IsUserPort(auth->client)) sendheader(auth->client, REPORT_FAIL_ID); ++ServerStats->is_abad; + if (IAuthHas(iauth, IAUTH_UNDERNET)) + sendto_iauth(auth->client, "u"); } else { if (IsUserPort(auth->client)) sendheader(auth->client, REPORT_FIN_ID); @@ -790,7 +812,8 @@ int auth_ping_timeout(struct Client *cptr) /* Check for iauth timeout. */ if (FlagHas(&auth->flags, AR_IAUTH_PENDING)) { - if (IAuthHas(iauth, IAUTH_REQUIRED)) { + if (IAuthHas(iauth, IAUTH_REQUIRED) + && !FlagHas(&auth->flags, AR_IAUTH_SOFT_DONE)) { sendheader(cptr, REPORT_FAIL_IAUTH); return exit_client_msg(cptr, cptr, &me, "Authorization Timeout"); } @@ -1019,12 +1042,6 @@ void start_auth(struct Client* client) } auth->port = remote.port; - /* Try to start DNS lookup. */ - start_dns_query(auth); - - /* Try to start ident lookup. */ - start_auth_query(auth); - /* Set required client inputs for users. */ if (IsUserPort(client)) { cli_user(client) = make_user(client); @@ -1036,6 +1053,12 @@ void start_auth(struct Client* client) start_iauth_query(auth); } + /* Try to start DNS lookup. */ + start_dns_query(auth); + + /* Try to start ident lookup. */ + start_auth_query(auth); + /* Add client to GlobalClientList. */ add_client_to_list(client); @@ -1084,10 +1107,10 @@ int auth_set_user(struct AuthRequest *auth, const char *username, const char *ho FlagClr(&auth->flags, AR_NEEDS_USER); cptr = auth->client; ircd_strncpy(cli_info(cptr), userinfo, REALLEN); - ircd_strncpy(cli_user(cptr)->username, username, USERLEN); + clean_username(cli_user(cptr)->username, username); ircd_strncpy(cli_user(cptr)->host, cli_sockhost(cptr), HOSTLEN); if (IAuthHas(iauth, IAUTH_UNDERNET)) - sendto_iauth(cptr, "U %s %s %s :%s", username, hostname, servername, userinfo); + sendto_iauth(cptr, "U %s %s %s :%s", cli_user(cptr)->username, hostname, servername, userinfo); else if (IAuthHas(iauth, IAUTH_ADDLINFO)) sendto_iauth(cptr, "U %s", username); return check_auth_finished(auth); @@ -1140,6 +1163,17 @@ void auth_send_exit(struct Client *cptr) sendto_iauth(cptr, "D"); } +/** Forward an XREPLY on to iauth. + * @param[in] sptr Source of the XREPLY. + * @param[in] routing Routing information for the original XQUERY. + * @param[in] reply Contents of the reply. + */ +void auth_send_xreply(struct Client *sptr, const char *routing, + const char *reply) +{ + sendto_iauth(NULL, "X %#C %s :%s", sptr, routing, reply); +} + /** Mark that a user has started capabilities negotiation. * This blocks authorization until auth_cap_done() is called. * @param[in] auth Authorization request for client. @@ -1359,19 +1393,19 @@ static void iauth_disconnect(struct IAuth *iauth) if (iauth == NULL) return; - /* Close main socket. */ - if (s_fd(i_socket(iauth)) != -1) { - close(s_fd(i_socket(iauth))); - socket_del(i_socket(iauth)); - s_fd(i_socket(iauth)) = -1; - } - /* Close error socket. */ if (s_fd(i_stderr(iauth)) != -1) { close(s_fd(i_stderr(iauth))); socket_del(i_stderr(iauth)); s_fd(i_stderr(iauth)) = -1; } + + /* Close main socket. */ + if (s_fd(i_socket(iauth)) != -1) { + close(s_fd(i_socket(iauth))); + socket_del(i_socket(iauth)); + s_fd(i_socket(iauth)) = -1; + } } /** Close all %IAuth connections marked as closing. */ @@ -1814,7 +1848,7 @@ static int iauth_cmd_ip_address(struct IAuth *iauth, struct Client *cli, memcpy(&auth->original, &cli_ip(cli), sizeof(auth->original)); /* Undo original IP connection in IPcheck. */ - IPcheck_connect_fail(cli); + IPcheck_connect_fail(cli, 1); ClearIPChecked(cli); /* Update the IP and charge them as a remote connect. */ @@ -1868,6 +1902,22 @@ static struct ConfItem *auth_find_class_conf(const char *class_name) return aconf; } +/** Tentatively accept a client in IAuth. + * @param[in] iauth Active IAuth session. + * @param[in] cli Client referenced by command. + * @param[in] parc Number of parameters. + * @param[in] params Optional class name for client. + * @return Negative (CPTR_KILLED) if the connection is refused, one otherwise. + */ +static int iauth_cmd_soft_done(struct IAuth *iauth, struct Client *cli, + int parc, char **params) +{ + /* Clear iauth pending flag. */ + assert(cli_auth(cli) != NULL); + FlagSet(&cli_auth(cli)->flags, AR_IAUTH_SOFT_DONE); + return 1; +} + /** Accept a client in IAuth. * @param[in] iauth Active IAuth session. * @param[in] cli Client referenced by command. @@ -1941,8 +1991,10 @@ static int iauth_cmd_done_account(struct IAuth *iauth, struct Client *cli, } /* If account has a creation timestamp, use it. */ assert(cli_user(cli) != NULL); - if (params[0][len] == ':') + if (params[0][len] == ':') { cli_user(cli)->acc_create = strtoul(params[0] + len + 1, NULL, 10); + params[0][len] = '\0'; + } /* Copy account name to User structure. */ ircd_strncpy(cli_user(cli)->account, params[0], ACCOUNTLEN); @@ -2004,6 +2056,55 @@ static int iauth_cmd_challenge(struct IAuth *iauth, struct Client *cli, return 0; } +/** Send an extension query to a specified remote server. + * @param[in] iauth Active IAuth session. + * @param[in] cli Client referenced by command. + * @param[in] parc Number of parameters (3). + * @param[in] params Remote server, routing information, and query. + * @return Zero. + */ +static int iauth_cmd_xquery(struct IAuth *iauth, struct Client *cli, + int parc, char **params) +{ + char *serv; + const char *routing; + const char *query; + struct Client *acptr; + + /* Process parameters */ + if (EmptyString(params[0])) { + sendto_iauth(cli, "E Missing :Missing server parameter"); + return 0; + } else + serv = params[0]; + + if (EmptyString(params[1])) { + sendto_iauth(cli, "E Missing :Missing routing parameter"); + return 0; + } else + routing = params[1]; + + if (EmptyString(params[2])) { + sendto_iauth(cli, "E Missing :Missing query parameter"); + return 0; + } else + query = params[2]; + + /* Try to find the specified server */ + if (!(acptr = find_match_server(serv))) { + sendto_iauth(cli, "x %s %s :Server not online", serv, routing); + return 0; + } + + /* If it's to us, do nothing; otherwise, forward the query */ + if (!IsMe(acptr)) + /* The "iauth:" prefix helps ircu route the reply to iauth */ + sendcmdto_one(&me, CMD_XQUERY, acptr, "%C iauth:%s :%s", acptr, routing, + query); + + return 0; +} + /** Parse a \a message from \a iauth. * @param[in] iauth Active IAuth session. * @param[in] message Message to be parsed. @@ -2028,6 +2129,7 @@ static void iauth_parse(struct IAuth *iauth, char *message) case 'A': handler = iauth_cmd_config; has_cli = 0; break; case 's': handler = iauth_cmd_newstats; has_cli = 0; break; case 'S': handler = iauth_cmd_stats; has_cli = 0; break; + case 'X': handler = iauth_cmd_xquery; has_cli = 0; break; case 'o': handler = iauth_cmd_username_forced; has_cli = 1; break; case 'U': handler = iauth_cmd_username_good; has_cli = 1; break; case 'u': handler = iauth_cmd_username_bad; has_cli = 1; break; @@ -2035,6 +2137,7 @@ static void iauth_parse(struct IAuth *iauth, char *message) case 'I': handler = iauth_cmd_ip_address; has_cli = 1; break; case 'M': handler = iauth_cmd_usermode; has_cli = 1; break; case 'C': handler = iauth_cmd_challenge; has_cli = 1; break; + case 'd': handler = iauth_cmd_soft_done; has_cli = 1; break; case 'D': handler = iauth_cmd_done_client; has_cli = 1; break; case 'R': handler = iauth_cmd_done_account; has_cli = 1; break; case 'k': /* The 'k' command indicates the user should be booted @@ -2165,8 +2268,7 @@ static void iauth_sock_callback(struct Event *ev) switch (ev_type(ev)) { case ET_DESTROY: - /* Hm, what happened here? */ - if (!IAuthHas(iauth, IAUTH_CLOSING)) + if (!IAuthHas(iauth, IAUTH_CLOSING) && !s_active(i_stderr(iauth))) iauth_do_spawn(iauth, 1); break; case ET_READ: @@ -2239,7 +2341,8 @@ static void iauth_stderr_callback(struct Event *ev) switch (ev_type(ev)) { case ET_DESTROY: - /* We do not restart iauth here: the stdout handler does that for us. */ + if (!IAuthHas(iauth, IAUTH_CLOSING) && !s_active(i_socket(iauth))) + iauth_do_spawn(iauth, 1); break; case ET_READ: iauth_read_stderr(iauth);