]> arthur.barton.de Git - ngircd-alex.git/blobdiff - src/ngircd/irc-login.c
Add Doxygen @file documentation to each source and header file
[ngircd-alex.git] / src / ngircd / irc-login.c
index 5a52d3cb68a9955079e75d4053f50ca61841ef19..b310d8b84614e7a37737825518125d9eb78ca705 100644 (file)
@@ -7,26 +7,33 @@
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
- *
- * Login and logout
  */
 
 
 #include "portab.h"
 
+/**
+ * @file
+ * Login and logout
+ */
+
 #include "imp.h"
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <strings.h>
+#include <signal.h>
+#include <unistd.h>
 
 #include "ngircd.h"
 #include "conn-func.h"
 #include "conf.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".
@@ -133,16 +146,17 @@ IRC_PASS( CLIENT *Client, REQUEST *Req )
                if (type && strcmp(type, PROTOIRCPLUS) == 0) {
                        /* The peer seems to be a server which supports the
                         * IRC+ protocol (see doc/Protocol.txt). */
-                       serverver = ptr + 1;
-                       flags = strchr(serverver, ':');
+                       serverver = ptr ? ptr + 1 : "?";
+                       flags = strchr(ptr ? serverver : impl, ':');
                        if (flags) {
                                *flags = '\0';
                                flags++;
                        } else
                                flags = "";
                        Log(LOG_INFO,
-                           "Peer announces itself as %s-%s using protocol %d.%d/IRC+ (flags: \"%s\").",
-                           impl, serverver, protohigh, protolow, flags);
+                           "Peer on conenction %d announces itself as %s-%s using protocol %d.%d/IRC+ (flags: \"%s\").",
+                           Client_Conn(Client), impl, serverver,
+                           protohigh, protolow, flags);
                } else {
                        /* The peer seems to be a server supporting the
                         * "original" IRC protocol (RFC 2813). */
@@ -151,8 +165,9 @@ IRC_PASS( CLIENT *Client, REQUEST *Req )
                        else
                                flags = "";
                        Log(LOG_INFO,
-                           "Peer announces itself as \"%s\" using protocol %d.%d (flags: \"%s\").",
-                           impl, protohigh, protolow, flags);
+                           "Peer on connection %d announces itself as \"%s\" using protocol %d.%d (flags: \"%s\").",
+                           Client_Conn(Client), impl,
+                           protohigh, protolow, flags);
                }
                Client_SetFlags(Client, flags);
        }
@@ -401,6 +416,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"
@@ -433,6 +449,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]);
 
@@ -575,6 +592,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 */
@@ -757,18 +775,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;
+       }
+
+       /* 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 password ... */
+       /* 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
@@ -802,7 +918,7 @@ Hello_User(CLIENT * Client)
        IRC_SetPenalty(Client, 1);
 
        return CONNECTED;
-} /* Hello_User */
+}
 
 
 static void