X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fngircd%2Firc-login.c;h=03fea99ad4e8f79ceb3a426d073f75444817933e;hb=04e38f17ae671f84b93e06c6eefa9235dd71d6ce;hp=cd1899cef465b2941afe574708481892f9327242;hpb=cc336b75580d012c1caee58a252d1ad14b2cee23;p=ngircd-alex.git diff --git a/src/ngircd/irc-login.c b/src/ngircd/irc-login.c index cd1899ce..03fea99a 100644 --- a/src/ngircd/irc-login.c +++ b/src/ngircd/irc-login.c @@ -20,14 +20,17 @@ #include #include #include +#include +#include #include "ngircd.h" #include "conn-func.h" #include "conf.h" -#include "client.h" #include "channel.h" +#include "io.h" #include "log.h" #include "messages.h" +#include "pam.h" #include "parse.h" #include "irc.h" #include "irc-info.h" @@ -38,11 +41,17 @@ static bool Hello_User PARAMS(( CLIENT *Client )); +static bool Hello_User_PostAuth PARAMS(( CLIENT *Client )); static void Kill_Nick PARAMS(( char *Nick, char *Reason )); static void Introduce_Client PARAMS((CLIENT *To, CLIENT *Client, int Type)); +static void Reject_Client PARAMS((CLIENT *Client)); + static void cb_introduceClient PARAMS((CLIENT *Client, CLIENT *Prefix, void *i)); +#ifdef PAM +static void cb_Read_Auth_Result PARAMS((int r_fd, UNUSED short events)); +#endif /** * Handler for the IRC command "PASS". @@ -402,6 +411,7 @@ IRC_USER(CLIENT * Client, REQUEST * Req) #else Client_SetUser(Client, Req->argv[0], false); #endif + Client_SetOrigUser(Client, Req->argv[0]); /* "Real name" or user info text: Don't set it to the empty * string, the original ircd can't deal with such "real names" @@ -434,6 +444,7 @@ IRC_USER(CLIENT * Client, REQUEST * Req) Req->prefix); Client_SetUser(c, Req->argv[0], true); + Client_SetOrigUser(c, Req->argv[0]); Client_SetHostname(c, Req->argv[1]); Client_SetInfo(c, Req->argv[3]); @@ -576,6 +587,7 @@ IRC_WEBIRC(CLIENT *Client, REQUEST *Req) Client_Conn(Client), Req->argv[1], Req->argv[2], Req->argv[3]); Client_SetUser(Client, Req->argv[1], true); + Client_SetOrigUser(Client, Req->argv[1]); Client_SetHostname(Client, Req->argv[2]); return CONNECTED; } /* IRC_WEBIRC */ @@ -758,18 +770,116 @@ IRC_PONG(CLIENT *Client, REQUEST *Req) static bool Hello_User(CLIENT * Client) { +#ifdef PAM + int pipefd[2], result; + CONN_ID conn; + pid_t pid; + assert(Client != NULL); + conn = Client_Conn(Client); + + if (Conf_NoPAM) { + /* Don't do any PAM authentication at all, instead emulate + * the beahiour of the daemon compiled without PAM support: + * because there can't be any "server password", all + * passwords supplied are classified as "wrong". */ + if(Client_Password(Client)[0] == '\0') + return Hello_User_PostAuth(Client); + Reject_Client(Client); + return DISCONNECTED; + } - /* Check password ... */ + /* 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"); + result = PAM_Authenticate(Client); + write(pipefd[1], &result, sizeof(result)); + Log_Exit_Subprocess("Auth"); + exit(0); + } +#else + assert(Client != NULL); + + /* Check global server password ... */ if (strcmp(Client_Password(Client), Conf_ServerPwd) != 0) { /* Bad password! */ - Log(LOG_ERR, - "Client \"%s\" rejected (connection %d): Bad password!", - Client_Mask(Client), Client_Conn(Client)); - Conn_Close(Client_Conn(Client), NULL, "Bad password", true); + Reject_Client(Client); return DISCONNECTED; } + return Hello_User_PostAuth(Client); +#endif +} + + +#ifdef PAM + +/** + * Read result of the authenticatior sub-process from pipe + */ +static void +cb_Read_Auth_Result(int r_fd, UNUSED short events) +{ + CONN_ID conn; + CLIENT *client; + int result; + size_t len; + PROC_STAT *proc; + + LogDebug("Auth: Got callback on fd %d, events %d", r_fd, events); + conn = Conn_GetFromProc(r_fd); + if (conn == NONE) { + /* Ops, none found? Probably the connection has already + * been closed!? We'll ignore that ... */ + io_close(r_fd); + LogDebug("Auth: Got callback for unknown connection!?"); + return; + } + proc = Conn_GetProcStat(conn); + client = Conn_GetClient(conn); + + /* Read result from pipe */ + len = Proc_Read(proc, &result, sizeof(result)); + if (len == 0) + return; + + if (len != sizeof(result)) { + Log(LOG_CRIT, "Auth: Got malformed result!"); + Reject_Client(client); + return; + } + + if (result == true) { + Client_SetUser(client, Client_OrigUser(client), true); + (void)Hello_User_PostAuth(client); + } else + Reject_Client(client); +} +#endif + + +static void +Reject_Client(CLIENT *Client) +{ + Log(LOG_ERR, + "User \"%s\" rejected (connection %d): Access denied!", + Client_Mask(Client), Client_Conn(Client)); + Conn_Close(Client_Conn(Client), NULL, + "Access denied! Bad password?", true); +} + + +static bool +Hello_User_PostAuth(CLIENT *Client) +{ Introduce_Client(NULL, Client, CLIENT_USER); if (!IRC_WriteStrClient @@ -803,7 +913,7 @@ Hello_User(CLIENT * Client) IRC_SetPenalty(Client, 1); return CONNECTED; -} /* Hello_User */ +} static void