* 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;
#endif
int pid;
+ signal(SIGCHLD, reapchild);
+
for (;;) {
pid = wait3(&status, WNOHANG, 0);
if (pid <= 0)
}
#endif /* REAPCHILD */
+static void die TAC_ARGS((int signum));
+
static void
die(signum)
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);
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;
return (s);
}
+static void open_logfile TAC_ARGS((void));
+
static void
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
*
* Parse arguments and act appropiately.
*/
+int main TAC_ARGS((int argc, char **argv));
+
+int
main(argc, argv)
int argc;
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");
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);
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);
}
#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)
#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);
report(LOG_ERR, "Can't fork second child");
else if (childpid > 0)
exit(0);
-
+
if (debug & DEBUG_FORK_FLAG)
report(LOG_DEBUG, "Forked grandchild");
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 */
/* 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
#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) {
}
#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);
*
*/
-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;
}
}
+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
#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
#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
#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");
#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