unsigned char thread_create(int sock, struct sockaddr_in* remote) { int ret; pthread_mutex_lock(&user_lock); int i = get_threadd(); if (i < 0) { pthread_mutex_unlock(&user_lock); return 1; } ret = cli_auth(sock, &threads[i]); if (!ret) { close(sock); pthread_mutex_unlock(&user_lock); return 0; } threads[i].used = 1; threads[i].sock = sock; threads[i].sig = 0; memcpy(&threads[i].client, (char*)remote, sizeof(struct sockaddr)); if (pthread_create(&threads[i].thread, 0, func_msg, (void*)&threads[i]) < 0) { mgr_kill(threads[i].user); threads[i].used = 0; pthread_mutex_unlock(&user_lock); return 2; } pthread_mutex_unlock(&user_lock); return 0; }
/** Handle a PASS message from an unregistered connection. * * \a parv[1..\a parc-1] is a possibly broken-up password. Since some * clients do not prefix the password with ':', this functions stitches * the elements back together before using it. * * See @ref m_functions for discussion of the arguments. * @param[in] cptr Client that sent us the message. * @param[in] sptr Original source of message. * @param[in] parc Number of arguments. * @param[in] parv Argument vector. */ int mr_pass(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char password[BUFSIZE]; int arg, len; assert(0 != cptr); assert(cptr == sptr); assert(!IsRegistered(sptr)); /* Some clients (brokenly) send "PASS x y" rather than "PASS :x y" * when the user enters "x y" as the password. Unsplit arguments to * work around this. */ for (arg = 1, len = 0; arg < parc; ++arg) { ircd_strncpy(password + len, parv[arg], sizeof(password) - len); len += strlen(parv[arg]); password[len++] = ' '; } if (len > 0) --len; password[len] = '\0'; if (EmptyString(password)) return need_more_params(cptr, "PASS"); #if defined(DDB) if (IsUserPort(cptr)) { /* * PASS :server_pass[:ddb_pass] * PASS :ddb_pass */ char *ddb_pwd; ddb_pwd = strchr(password, ':'); if (ddb_pwd) *ddb_pwd++ = '\0'; else ddb_pwd = password; ircd_strncpy(cli_ddb_passwd(cptr), ddb_pwd, DDBPWDLEN); } #endif ircd_strncpy(cli_passwd(cptr), password, PASSWDLEN); return cli_auth(cptr) ? auth_set_password(cli_auth(cptr), password) : 0; }
/* * mr_pong - registration message handler * * parv[0] = sender prefix * parv[1] = pong response echo * NOTE: cptr is always unregistered here */ int mr_pong(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { assert(0 != cptr); assert(cptr == sptr); assert(!IsRegistered(sptr)); ClearPingSent(cptr); return (parc > 1) ? auth_set_pong(cli_auth(sptr), strtoul(parv[parc - 1], NULL, 10)) : 0; }
/** Release a Client. * In addition to the cleanup done by dealloc_client(), this will free * any pending auth request, free the connection for local clients, * and delete the processing timer for the client. * @param[in] cptr Client to free. */ void free_client(struct Client* cptr) { if (!cptr) return; /* * forget to remove the client from the hash table? */ assert(cli_verify(cptr)); assert(cli_hnext(cptr) == cptr); /* or from linked list? */ assert(cli_next(cptr) == 0); assert(cli_prev(cptr) == 0); Debug((DEBUG_LIST, "Freeing client %s [%p], connection %p", cli_name(cptr), cptr, cli_connect(cptr))); if (cli_auth(cptr)) destroy_auth_request(cli_auth(cptr), 0); /* Make sure we didn't magically get re-added to the list */ assert(cli_next(cptr) == 0); assert(cli_prev(cptr) == 0); if (cli_from(cptr) == cptr) { /* in other words, we're local */ cli_from(cptr) = 0; /* timer must be marked as not active */ if (!cli_freeflag(cptr) && !t_active(&(cli_proc(cptr)))) dealloc_connection(cli_connect(cptr)); /* connection not open anymore */ else { if (-1 < cli_fd(cptr) && cli_freeflag(cptr) & FREEFLAG_SOCKET) socket_del(&(cli_socket(cptr))); /* queue a socket delete */ if (cli_freeflag(cptr) & FREEFLAG_TIMER) timer_del(&(cli_proc(cptr))); /* queue a timer delete */ } } cli_connect(cptr) = 0; dealloc_client(cptr); /* actually destroy the client */ }
static void auth_kill_client(struct AuthRequest* auth) { assert(0 != auth); unlink_auth_request(auth, (IsDoingAuth(auth)) ? &AuthPollList : &AuthIncompleteList); if (IsDNSPending(auth)) delete_resolver_queries(auth); IPcheck_disconnect(auth->client); Count_unknowndisconnects(UserStats); cli_auth(auth->client) = 0; free_client(auth->client); free_auth_request(auth); }
/* * release_auth_client - release auth client from auth system * this adds the client into the local client lists so it can be read by * the main io processing loop */ static void release_auth_client(struct Client* client) { assert(0 != client); cli_auth(client) = 0; cli_lasttime(client) = cli_since(client) = CurrentTime; if (cli_fd(client) > HighestFd) HighestFd = cli_fd(client); LocalClientArray[cli_fd(client)] = client; add_client_to_list(client); socket_events(&(cli_socket(client)), SOCK_ACTION_SET | SOCK_EVENT_READABLE); Debug((DEBUG_INFO, "Auth: release_auth_client %s@%s[%s]", cli_username(client), cli_sockhost(client), cli_sock_ip(client))); }
/* * make_auth_request - allocate a new auth request */ static struct AuthRequest* make_auth_request(struct Client* client) { struct AuthRequest* auth = (struct AuthRequest*) MyMalloc(sizeof(struct AuthRequest)); assert(0 != auth); memset(auth, 0, sizeof(struct AuthRequest)); auth->flags = AM_TIMEOUT; auth->fd = -1; auth->client = client; cli_auth(client) = auth; timer_add(timer_init(&auth->timeout), auth_timeout_callback, (void*) auth, TT_RELATIVE, feature_int(FEAT_AUTH_TIMEOUT)); return auth; }
/* * read_auth_reply - read the reply (if any) from the ident server * we connected to. * We only give it one shot, if the reply isn't good the first time * fail the authentication entirely. --Bleep */ void read_auth_reply(struct AuthRequest* auth) { char* username = 0; unsigned int len; /* * rfc1453 sez we MUST accept 512 bytes */ char buf[BUFSIZE + 1]; assert(0 != auth); assert(0 != auth->client); assert(auth == cli_auth(auth->client)); if (IO_SUCCESS == os_recv_nonb(auth->fd, buf, BUFSIZE, &len)) { buf[len] = '\0'; Debug((DEBUG_LIST, "Auth %p [%p] reply: %s", auth, &auth->socket, buf)); username = check_ident_reply(buf); Debug((DEBUG_LIST, "Username: %s", username)); } close(auth->fd); auth->fd = -1; Debug((DEBUG_LIST, "Deleting auth [%p] socket %p", auth, &auth->socket)); socket_del(&auth->socket); ClearAuth(auth); if (!EmptyString(username)) { ircd_strncpy(cli_username(auth->client), username, USERLEN); /* * Not needed, struct is zeroed by memset * auth->client->username[USERLEN] = '\0'; */ SetGotId(auth->client); ++ServerStats->is_asuc; if (IsUserPort(auth->client)) sendheader(auth->client, REPORT_FIN_ID); } else { ++ServerStats->is_abad; } unlink_auth_request(auth, &AuthPollList); if (IsDNSPending(auth)) link_auth_request(auth, &AuthIncompleteList); else { release_auth_client(auth->client); free_auth_request(auth); } }
/* * mr_pass - registration message handler */ int mr_pass(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { char password[BUFSIZE]; int arg, len, i = 0, emptypass = 0; char* locargv[3] = {NULL, NULL, NULL}; char *tmp = NULL; assert(0 != cptr); assert(cptr == sptr); assert(!IsRegistered(sptr)); /* Some clients (brokenly) send "PASS x y" rather than "PASS :x y" * when the user enters "x y" as the password. Unsplit arguments to * work around this. */ for (arg = 1, len = 0; arg < parc; ++arg) { ircd_strncpy(password + len, parv[arg], sizeof(password) - len); len += strlen(parv[arg]); password[len++] = ' '; } if (len > 0) --len; password[len] = '\0'; if (feature_bool(FEAT_LOGIN_ON_CONNECT) && feature_bool(FEAT_EXTENDED_ACCOUNTS) && !cli_loc(cptr) && (password[0] != '\0')) { emptypass = 1; tmp = password; if (*tmp == '/') { *tmp = '\0'; tmp++; } else { tmp = strstr(tmp, " /"); if (tmp != NULL) { *tmp = '\0'; tmp += 2; } } while ((tmp != NULL) && *tmp && (i<3)) { locargv[i++] = tmp; tmp = strstr(tmp, "/"); if (tmp != NULL) { *tmp = '\0'; tmp++; } } if ((i>1) && !EmptyString(locargv[i-2]) && !EmptyString(locargv[i-1])) { cli_loc(cptr) = (struct LOCInfo *)MyMalloc(sizeof(struct LOCInfo)); memset(cli_loc(cptr), 0, sizeof(struct LOCInfo)); cli_loc(cptr)->cookie = 0; ircd_strncpy(cli_loc(cptr)->password, locargv[--i], ACCPASSWDLEN); ircd_strncpy(cli_loc(cptr)->account, locargv[--i], ACCOUNTLEN); if ((i>0) && !EmptyString(locargv[i-1])) ircd_strncpy(cli_loc(cptr)->service, locargv[--i], NICKLEN); else ircd_strncpy(cli_loc(cptr)->service, feature_str(FEAT_LOC_DEFAULT_SERVICE), NICKLEN); } } if ((password[0] == '\0') && !(cli_loc(cptr)) && !emptypass) return need_more_params(cptr, "PASS"); if (cli_loc(cptr) && (password[0] == '\0') && !emptypass) { if (cli_auth(cptr)) auth_end_loc(cli_auth(cptr)); MyFree(cli_loc(cptr)); } if (cli_passwd(cptr)[0] == '\0') ircd_strncpy(cli_passwd(cptr), password, PASSWDLEN); return cli_auth(cptr) ? auth_set_password(cli_auth(cptr), password) : 0; }