/** * Handler for the "CAP LIST" command. * * @param Client The client from which this command has been received. * @param Arg Command argument or NULL. * @returns CONNECTED or DISCONNECTED. */ bool Handle_CAP_LIST(CLIENT *Client, UNUSED char *Arg) { assert(Client != NULL); return IRC_WriteStrClient(Client, "CAP %s LIST :%s", Client_ID(Client), Get_CAP_String(Client_Cap(Client))); }
/** * Handler for the "CAP CLEAR" command. * * @param Client The client from which this command has been received. * @returns CONNECTED or DISCONNECTED. */ bool Handle_CAP_CLEAR(CLIENT *Client) { int cap_old; assert(Client != NULL); cap_old = Client_Cap(Client); if (cap_old & CLIENT_CAP_MULTI_PREFIX) Client_CapDel(Client, CLIENT_CAP_MULTI_PREFIX); return IRC_WriteStrClient(Client, "CAP %s ACK :%s", Client_ID(Client), Get_CAP_String(cap_old)); }
/** * Handler for the "CAP REQ" command. * * @param Client The client from which this command has been received. * @param Arg Command argument. * @returns CONNECTED or DISCONNECTED. */ bool Handle_CAP_REQ(CLIENT *Client, char *Arg) { int new_cap; assert(Client != NULL); assert(Arg != NULL); Set_CAP_Negotiation(Client); new_cap = Parse_CAP(Client_Cap(Client), Arg); if (new_cap < 0) return IRC_WriteStrClient(Client, "CAP %s NAK :%s", Client_ID(Client), Arg); Client_CapSet(Client, new_cap); return IRC_WriteStrClient(Client, "CAP %s ACK :%s", Client_ID(Client), Arg); }
/** * Initiate client login. * * This function is called after the daemon received the required NICK and * USER commands of a new client. If the daemon is compiled with support for * PAM, the authentication sub-processs is forked; otherwise the global server * password is checked. * * @param Client The client logging in. * @returns CONNECTED or DISCONNECTED. */ GLOBAL bool Login_User(CLIENT * Client) { #ifdef PAM int pipefd[2], result; pid_t pid; #endif CONN_ID conn; assert(Client != NULL); conn = Client_Conn(Client); #ifndef STRICT_RFC if (Conf_AuthPing) { /* Did we receive the "auth PONG" already? */ if (Conn_GetAuthPing(conn)) { Client_SetType(Client, CLIENT_WAITAUTHPING); LogDebug("Connection %d: Waiting for AUTH PONG ...", conn); return CONNECTED; } } #endif /* Still waiting for "CAP END" command? */ if (Client_Cap(Client) & CLIENT_CAP_PENDING) { Client_SetType(Client, CLIENT_WAITCAPEND); LogDebug("Connection %d: Waiting for CAP END ...", conn); return CONNECTED; } #ifdef PAM if (!Conf_PAM) { /* Don't do any PAM authentication at all if PAM is not * enabled, instead emulate the behavior of the daemon * compiled without PAM support. */ if (strcmp(Conn_Password(conn), Conf_ServerPwd) == 0) return Login_User_PostAuth(Client); Client_Reject(Client, "Bad server password", false); return DISCONNECTED; } if (Conf_PAMIsOptional && strcmp(Conn_Password(conn), "") == 0) { /* Clients are not required to send a password and to be PAM- * authenticated at all. If not, they won't become "identified" * and keep the "~" in their supplied user name. * Therefore it is sensible to either set Conf_PAMisOptional or * to enable IDENT lookups -- not both. */ return Login_User_PostAuth(Client); } if (Conf_PAM) { /* Fork child process for PAM authentication; and make sure that the * process timeout is set higher than the login timeout! */ pid = Proc_Fork(Conn_GetProcStat(conn), pipefd, cb_Read_Auth_Result, Conf_PongTimeout + 1); if (pid > 0) { LogDebug("Authenticator for connection %d created (PID %d).", conn, pid); return CONNECTED; } else { /* Sub process */ Log_Init_Subprocess("Auth"); Conn_CloseAllSockets(NONE); result = PAM_Authenticate(Client); if (write(pipefd[1], &result, sizeof(result)) != sizeof(result)) Log_Subprocess(LOG_ERR, "Failed to pipe result to parent!"); Log_Exit_Subprocess("Auth"); exit(0); } } else return CONNECTED; #else /* Check global server password ... */ if (strcmp(Conn_Password(conn), Conf_ServerPwd) != 0) { /* Bad password! */ Client_Reject(Client, "Bad server password", false); return DISCONNECTED; } return Login_User_PostAuth(Client); #endif }