Initial "gts1" commit.
[tac_plus.git] / main.c
diff --git a/main.c b/main.c
index cf0ffd8..3878c01 100644 (file)
--- a/main.c
+++ b/main.c
@@ -14,7 +14,7 @@
  * distribution of the program without specific prior permission, and
  * notice be given in supporting documentation that modification,
  * copying and distribution is by permission of Cisco Systems, Inc.
-
+ *
  * Cisco Systems, Inc. makes no representations about the suitability
  * of this software for any purpose.  THIS SOFTWARE IS PROVIDED ``AS
  * IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
  * FITNESS FOR A PARTICULAR PURPOSE.
 */
 
+
 #include "tac_plus.h"
-#include "sys/wait.h"
-#include "signal.h"
+
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <netdb.h>
+#include <errno.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+#endif
+#ifdef HAVE_SYS_SYSLOG_H
+#include <sys/syslog.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#include "main.h"
+#include "report.h"
+#include "utils.h"
+#include "cfgfile.h"
+#include "packet.h"
+#include "dump.h"
+#include "author.h"
+#include "acct.h"
+#include "authen.h"
+#include "do_acct.h"
+#include "parse.h"
+
+#ifdef MAXSESS
+#include "maxsess.h"
+#endif
+
+
+static void version TAC_ARGS((void));
+static void start_session TAC_ARGS((void));
+
+
+/* Configurable:
+ */
+
+#ifndef TAC_PLUS_PORT
+#define        TAC_PLUS_PORT                   49
+#endif
+
 
 static int standalone  = 1; /* running standalone (1) or under inetd (0) */
 static int initialised = 0; /* data structures have been allocated */
 int sendauth_only      = 0; /* don't respond to sendpass requests */
 int debug              = 0; /* debugging flags */
-int port               = 0; /* port we're listening on */
+static int port        = 0; /* port we're listening on */
 int console            = 0; /* write all syslog messages to console */
 int parse_only         = 0; /* exit after verbose parsing */
 int single             = 0; /* single thread (for debugging) */
-int wtmpfd            = 0; /* for wtmp file logging */
-char *wtmpfile         = NULL;
-
-struct timeval started_at;
 
 struct session session;     /* session data */
 
 static char pidfilebuf[75]; /* holds current name of the pidfile */
 
-void start_session();
 
 #ifndef REAPCHILD
-static
-#ifdef VOIDSIG
-void 
-#else
-int
-#endif /* VOIDSIG */
-reapchild()
+static RETSIGTYPE reapchild TAC_ARGS((int signo));
+
+static RETSIGTYPE
+reapchild(signo)
+int signo;
 {
 #ifdef UNIONWAIT
     union wait status;
@@ -61,6 +111,8 @@ reapchild()
 #endif
     int pid;
 
+    signal(SIGCHLD, reapchild);
+
     for (;;) {
        pid = wait3(&status, WNOHANG, 0);
        if (pid <= 0)
@@ -71,6 +123,8 @@ reapchild()
 }
 #endif /* REAPCHILD */
 
+static void die TAC_ARGS((int signum));
+
 static void
 die(signum)
 int signum;
@@ -80,21 +134,23 @@ int signum;
     tac_exit(0);
 }
 
+static void init TAC_ARGS((void));
+
 static void
 init()
 {
     if (initialised)
-       cfg_clean_config();    
+       cfg_clean_config();
 
     report(LOG_INFO, "Reading config");
 
     session.acctfile = tac_strdup("/var/log/acctfile");
-    
+
     if (!session.cfgfile) {
        report(LOG_ERR, "no config file specified");
        tac_exit(1);
     }
-    
+
     /* read the config file */
     if (cfg_read_config(session.cfgfile)) {
        report(LOG_ERR, "Parsing %s", session.cfgfile);
@@ -104,26 +160,59 @@ init()
 
     initialised++;
 
-    report(LOG_INFO, "Version %s Initialized %d", VERSION, initialised);
+    report(LOG_INFO, "Version %s%s Initialized %d", VERSION, VERSION_TAIL, initialised);
 
 }
 
-static void
+/* 'handler()' will be called during initialization to setup signal handler,
+ * keep it in mind when modifying it!
+ */
+
+static int handler_occured = 0;
+
+static RETSIGTYPE handler TAC_ARGS((int signum));
+
+static RETSIGTYPE
 handler(signum)
 int signum;
 {
-    report(LOG_INFO, "Received signal %d", signum);
-    init();
-#ifdef REARMSIGNAL
+    /* never execute any non-trivial (=system-call) commands here
+     * as it may immediately abort the whole 'handler()' (SYSV signal).
+     * We hope that SA_RESTART is NOT set for our signals
+     */
+    handler_occured = 1;
+    /* It is never wrong to reinstall 'handler' just to be safe */
     signal(SIGUSR1, handler);
-    signal(SIGHUP, handler);
-#endif REARMSIGNAL
+    signal(SIGHUP , handler);
+
+    /* DON'T interrupt! */
+#ifdef HAVE_SIGINTERRUPT
+    siginterrupt(SIGUSR1, 0 /* flag */);
+    siginterrupt(SIGHUP , 0 /* flag */);
+#endif
+}
+
+static void check_handler_occured TAC_ARGS((void));
+
+static RETSIGTYPE
+check_handler_occured()
+{
+
+    if (!handler_occured)
+       return;
+
+    handler_occured = 0;
+    report(LOG_INFO, "Signal detected, reloading configuration");
+    init();
 }
 
 /*
  * Return a socket bound to an appropriate port number/address. Exits
  * the program on failure */
 
+static int get_socket TAC_ARGS((void));
+
+static int
 get_socket()
 {
     int s;
@@ -171,6 +260,8 @@ get_socket()
     return (s);
 }
 
+static void open_logfile TAC_ARGS((void));
+
 static void
 open_logfile()
 {
@@ -182,6 +273,29 @@ open_logfile()
     setlogmask(LOG_UPTO(LOG_DEBUG));
 }
 
+static void prep_session_peer TAC_ARGS((const struct sockaddr_in *from));
+
+static void
+prep_session_peer(from)
+const struct sockaddr_in *from;
+{
+    struct hostent *hp;
+
+    if (session.peer_addr && session.peer_addr != session.peer)
+       free(session.peer_addr);
+    if (session.peer)
+       free(session.peer);
+
+    session.peer_addr = tac_strdup( (char *) inet_ntoa(from->sin_addr) );
+
+    hp = gethostbyaddr((char *) &from->sin_addr.s_addr, sizeof(from->sin_addr.s_addr), AF_INET);
+
+    if (hp)
+       session.peer = tac_strdup(hp->h_name);
+    else
+       session.peer = session.peer_addr;
+}
+
 /*
  * main
  *
@@ -189,6 +303,9 @@ open_logfile()
  * Parse arguments and act appropiately.
  */
 
+int main TAC_ARGS((int argc, char **argv));
+
+int
 main(argc, argv)
 int argc;
 char **argv;
@@ -214,6 +331,10 @@ char **argv;
     port = TAC_PLUS_PORT;
 #endif
 
+#ifdef MAINTAINER_MODE
+    session.cfgfile = "/etc/tacacs/tac_plus.cfg";
+#endif
+
     if (argc <= 1) {
        fprintf(stderr, "Usage: tac_plus -C <configuration file>\n");
        fprintf(stderr, "\t[ -t ] [ -P ] [ -g ] [ -p <port> ]\n");
@@ -284,8 +405,9 @@ char **argv;
 
     init();
 
-    signal(SIGUSR1, handler);
-    signal(SIGHUP, handler);
+    handler(-1 /* signum */);          /* connect to the signals */
+    handler_occured = 0;               /* post-fix cludge */
+
     signal(SIGTERM, die);
     signal(SIGPIPE, SIG_IGN);
 
@@ -293,31 +415,27 @@ char **argv;
        tac_exit(0);
 
     if (debug)
-       report(LOG_DEBUG, "tac_plus server %s starting", VERSION);
+       report(LOG_DEBUG, "tac_plus server %s%s starting", VERSION, VERSION_TAIL);
 
     if (!standalone) {
        /* running under inetd */
        struct sockaddr_in name;
-       int name_len;
-       int on = 1;
+       socklen_t name_len;
+#ifdef FIONBIO
+       int fionbio_on = 1;
+#endif
 
        name_len = sizeof(name);
 
-       session.sock = 0;
        if (getpeername(session.sock, (struct sockaddr *) &name, &name_len)) {
            report(LOG_ERR, "getpeername failure %s", sys_errlist[errno]);
-       } else {
-           struct hostent *hp;
-           hp = gethostbyaddr((char *) &name.sin_addr.s_addr,
-                              sizeof(name.sin_addr.s_addr), AF_INET);
-           if (session.peer) {
-               free(session.peer);
-           }
-           session.peer = tac_strdup(hp ? hp->h_name : 
-                                 (char *) inet_ntoa(name.sin_addr));
-       }
+           prep_session_peer(NULL);
+       } else
+           prep_session_peer(&name);
+
+       session.sock = 0;
 #ifdef FIONBIO
-       if (ioctl(session.sock, FIONBIO, &on) < 0) {
+       if (ioctl(session.sock, FIONBIO, &fionbio_on) < 0) {
            report(LOG_ERR, "ioctl(FIONBIO) %s", sys_errlist[errno]);
            tac_exit(1);
        }
@@ -338,9 +456,9 @@ char **argv;
 #ifdef SIGTSTP
        signal(SIGTSTP, SIG_IGN);
 #endif
-       
+
        signal(SIGHUP, SIG_IGN);
-    
+
        if ((childpid = fork()) < 0)
            report(LOG_ERR, "Can't fork first child");
        else if (childpid > 0)
@@ -351,23 +469,29 @@ char **argv;
 
 #ifndef REAPCHILD
 
-#ifdef LINUX
+#ifdef SETPGRP_VOID
        if (setpgrp() == -1)
-#else /* LINUX */
+#else /* SETPGRP_VOID */
        if (setpgrp(0, getpid()) == -1)
-#endif /* LINUX */
+#endif /* SETPGRP_VOID */
            report(LOG_ERR, "Can't change process group");
-       
+
+#ifdef TIOCNOTTY
        c = open("/dev/tty", O_RDWR);
        if (c >= 0) {
            ioctl(c, TIOCNOTTY, (char *) 0);
            (void) close(c);
        }
+#endif
        signal(SIGCHLD, reapchild);
 
 #else /* REAPCHILD */
 
+#ifdef SETPGRP_VOID
        if (setpgrp() == 1)
+#else /* SETPGRP_VOID */
+       if (setpgrp(0, getpid()) == 1)
+#endif /* SETPGRP_VOID */
            report(LOG_ERR, "Can't change process group");
 
        signal(SIGHUP, SIG_IGN);
@@ -376,7 +500,7 @@ char **argv;
            report(LOG_ERR, "Can't fork second child");
        else if (childpid > 0)
            exit(0);
-    
+
        if (debug & DEBUG_FORK_FLAG)
            report(LOG_DEBUG, "Forked grandchild");
 
@@ -393,18 +517,18 @@ char **argv;
        open_logfile();
 
     } /* ! single threaded */
-    
+
     ostream = NULL;
     /* chdir("/"); */
     umask(0);
     errno = 0;
 
     s = get_socket();
-   
+
 #ifndef SOMAXCONN
 #ifdef LINUX
 #define SOMAXCONN 128
-#else 
+#else
 #define SOMAXCONN 5
 #endif /* LINUX */
 #endif /* SOMAXCONN */
@@ -423,21 +547,21 @@ char **argv;
 
     /* write process id to pidfile */
     if ((fp = fopen(pidfilebuf, "w")) != NULL) {
-       fprintf(fp, "%d\n", getpid());
+       fprintf(fp, "%d\n", (int) getpid());
        fclose(fp);
-    } else 
-       report(LOG_ERR, "Cannot write pid to %s %s", 
+    } else
+       report(LOG_ERR, "Cannot write pid to %s %s",
               pidfilebuf, sys_errlist[errno]);
 
 #ifdef TACPLUS_GROUPID
     if (setgid(TACPLUS_GROUPID))
-       report(LOG_ERR, "Cannot set group id to %d %s", 
+       report(LOG_ERR, "Cannot set group id to %d %s",
               TACPLUS_GROUPID, sys_errlist[errno]);
 #endif
 
 #ifdef TACPLUS_USERID
-    if (setuid(TACPLUS_USERID)) 
-       report(LOG_ERR, "Cannot set user id to %d %s", 
+    if (setuid(TACPLUS_USERID))
+       report(LOG_ERR, "Cannot set user id to %d %s",
               TACPLUS_USERID, sys_errlist[errno]);
 #endif
 
@@ -446,41 +570,48 @@ char **argv;
 #endif /* MAXSESS */
 
     report(LOG_DEBUG, "uid=%d euid=%d gid=%d egid=%d s=%d",
-          getuid(), geteuid(), getgid(), getegid(), s);
+          (int) getuid(), (int) geteuid(), (int) getgid(), (int) getegid(), s);
 
     for (;;) {
        int pid;
        struct sockaddr_in from;
-       int from_len;
+       socklen_t from_len;
        int newsockfd;
-       struct hostent *hp = NULL;
+
+       check_handler_occured();
 
        bzero((char *) &from, sizeof(from));
        from_len = sizeof(from);
 
+       /* PERMIT interrupt of accept()! */
+#ifdef HAVE_SIGINTERRUPT
+       siginterrupt(SIGUSR1, 1 /* flag */);
+       siginterrupt(SIGHUP , 1 /* flag */);
+#endif
+
+       errno = 0;
        newsockfd = accept(s, (struct sockaddr *) &from, &from_len);
 
+       /* DON'T interrupt! */
+#ifdef HAVE_SIGINTERRUPT
+       siginterrupt(SIGUSR1, 0 /* flag */);
+       siginterrupt(SIGHUP , 0 /* flag */);
+#endif
+
+       check_handler_occured();
+
        if (newsockfd < 0) {
-           if (errno == EINTR)
+           /* sometimes we may get even 'errno==0' when 'handler()' signal occured */
+           if (errno == EINTR || errno == 0)
                continue;
 
            report(LOG_ERR, "accept: %s", sys_errlist[errno]);
            continue;
        }
-
-       if (lookup_peer) {
-           hp = gethostbyaddr((char *) &from.sin_addr.s_addr,
-                              sizeof(from.sin_addr.s_addr), AF_INET);
-       }
-
-       if (session.peer) {
-           free(session.peer);
-       }
-       session.peer = tac_strdup(hp ? hp->h_name : 
-                                 (char *) inet_ntoa(from.sin_addr));
+       prep_session_peer(&from);
 
        if (debug & DEBUG_PACKET_FLAG)
-           report(LOG_DEBUG, "session request from %s sock=%d", 
+           report(LOG_DEBUG, "session request from %s sock=%d",
                   session.peer, newsockfd);
 
        if (!single) {
@@ -514,25 +645,27 @@ char **argv;
 }
 
 #ifdef GETDTABLESIZE
-int 
+int
 getdtablesize()
 {
     return(_NFILE);
 }
 #endif /* GETDTABLESIZE */
 
+static int bad_version_check TAC_ARGS((u_char *pak));
+
 /* Make sure version number is kosher. Return 0 if it is */
-int
+static int
 bad_version_check(pak)
 u_char *pak;
 {
     HDR *hdr = (HDR *) pak;
-    
+
     switch (hdr->type) {
     case TAC_PLUS_AUTHEN:
-       /* 
+       /*
         * Let authen routines take care of more sophisticated version
-        * checking as its now a bit involved. 
+        * checking as its now a bit involved.
         */
        return(0);
 
@@ -555,12 +688,13 @@ u_char *pak;
  *
  */
 
-void
+static void start_session TAC_ARGS((void));
+
+static void
 start_session()
 {
-    u_char *pak, *read_packet();
+    u_char *pak;
     HDR *hdr;
-    void authen();
 
     session.seq_no = 0;
     session.aborted = 0;
@@ -608,9 +742,12 @@ start_session()
     }
 }
 
+static void version TAC_ARGS((void));
+
+static void
 version()
 {
-    fprintf(stdout, "tac_plus version %s\n", VERSION);
+    fprintf(stdout, "tac_plus version %s%s\n", VERSION, VERSION_TAIL);
 #ifdef AIX
     fprintf(stdout,"AIX\n");
 #endif
@@ -644,9 +781,6 @@ version()
 #ifdef LINUX
     fprintf(stdout,"LINUX\n");
 #endif
-#ifdef LITTLE_ENDIAN
-    fprintf(stdout,"LITTLE_ENDIAN\n");
-#endif
 #ifdef LOG_LOCAL6
     fprintf(stdout,"LOG_LOCAL6\n");
 #endif
@@ -662,15 +796,9 @@ version()
 #ifdef NETBSD
     fprintf(stdout,"NETBSD\n");
 #endif
-#ifdef NO_PWAGE
-    fprintf(stdout,"NO_PWAGE\n");
-#endif
 #ifdef REAPCHILD
     fprintf(stdout,"REAPCHILD\n");
 #endif
-#ifdef REARMSIGNAL
-    fprintf(stdout,"REARMSIGNAL\n");
-#endif
 #ifdef SHADOW_PASSWORDS
     fprintf(stdout,"SHADOW_PASSWORDS\n");
 #endif
@@ -692,14 +820,8 @@ version()
 #ifdef SO_REUSEADDR
     fprintf(stdout,"SO_REUSEADDR\n");
 #endif
-#ifdef STDLIB_MALLOC
-    fprintf(stdout,"STDLIB_MALLOC\n");
-#endif
-#ifdef STRCSPN
-    fprintf(stdout,"STRCSPN\n");
-#endif
-#ifdef SYSLOG_IN_SYS
-    fprintf(stdout,"SYSLOG_IN_SYS\n");
+#ifdef HAVE_STRCSPN
+    fprintf(stdout,"HAVE_STRCSPN\n");
 #endif
 #ifdef SYSV
     fprintf(stdout,"SYSV\n");
@@ -713,15 +835,9 @@ version()
 #ifdef TACPLUS_USERID
     fprintf(stdout,"TACPLUS_USERID\n");
 #endif
-#ifdef TRACE
-    fprintf(stdout,"TRACE\n");
-#endif
 #ifdef UNIONWAIT
     fprintf(stdout,"UNIONWAIT\n");
 #endif
-#ifdef VOIDSIG
-    fprintf(stdout,"VOIDSIG\n");
-#endif
 #ifdef _BSD1
     fprintf(stdout,"_BSD1\n");
 #endif