]> arthur.barton.de Git - ngircd-alex.git/blobdiff - src/ngircd/irc-login.c
config: deprecate NoXX-Options
[ngircd-alex.git] / src / ngircd / irc-login.c
index c8b44dbc1653723d0a32cddd4f63300c8e906a60..381dd201b675c9a8ca6985380c23b90361c64b33 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <strings.h>
+#include <signal.h>
+#include <unistd.h>
 
 #include "ngircd.h"
-#include "resolve.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"
 
 
 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".
@@ -403,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"
@@ -435,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]);
 
@@ -577,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 */
@@ -759,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_PAM) {
+               /* 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
@@ -804,7 +913,7 @@ Hello_User(CLIENT * Client)
        IRC_SetPenalty(Client, 1);
 
        return CONNECTED;
-} /* Hello_User */
+}
 
 
 static void
@@ -840,10 +949,16 @@ Introduce_Client(CLIENT *From, CLIENT *Client, int Type)
                         Client_Modes(Client), Client_ID(From),
                         Client_ID(Client_Introducer(Client)),
                         Client_Hops(Client), Client_Hops(Client) > 1 ? "s": "");
-       } else
+       } else {
                Log(LOG_NOTICE, "%s \"%s\" registered (connection %d).",
                    Client_TypeText(Client), Client_Mask(Client),
                    Client_Conn(Client));
+               Log_ServerNotice('c', "Client connecting: %s (%s@%s) [%s] - %s",
+                                Client_ID(Client), Client_User(Client),
+                                Client_Hostname(Client),
+                                Conn_IPA(Client_Conn(Client)),
+                                Client_TypeText(Client));
+       }
 
        /* Inform other servers */
        IRC_WriteStrServersPrefixFlag_CB(From,