4 * TACACS_PLUS daemon suitable for using on Un*x systems.
6 * October 1994, Lol Grant
8 * Copyright (c) 1994-1998 by Cisco systems, Inc.
9 * Permission to use, copy, modify, and distribute this software for
10 * any purpose and without fee is hereby granted, provided that this
11 * copyright and permission notice appear on all copies of the
12 * software and supporting documentation, the name of Cisco Systems,
13 * Inc. not be used in advertising or publicity pertaining to
14 * distribution of the program without specific prior permission, and
15 * notice be given in supporting documentation that modification,
16 * copying and distribution is by permission of Cisco Systems, Inc.
18 * Cisco Systems, Inc. makes no representations about the suitability
19 * of this software for any purpose. THIS SOFTWARE IS PROVIDED ``AS
20 * IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
21 * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
22 * FITNESS FOR A PARTICULAR PURPOSE.
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #include <sys/types.h>
38 #ifdef HAVE_SYS_TIME_H
47 #ifdef HAVE_SYS_SYSLOG_H
48 #include <sys/syslog.h>
53 #ifdef HAVE_SYS_IOCTL_H
54 #include <sys/ioctl.h>
74 static void version TAC_ARGS((void));
75 static void start_session TAC_ARGS((void));
82 #define TAC_PLUS_PORT 49
86 static int standalone = 1; /* running standalone (1) or under inetd (0) */
87 static int initialised = 0; /* data structures have been allocated */
88 int sendauth_only = 0; /* don't respond to sendpass requests */
89 int debug = 0; /* debugging flags */
90 static int port = 0; /* port we're listening on */
91 int console = 0; /* write all syslog messages to console */
92 int parse_only = 0; /* exit after verbose parsing */
93 int single = 0; /* single thread (for debugging) */
95 struct session session; /* session data */
97 static char pidfilebuf[75]; /* holds current name of the pidfile */
101 static RETSIGTYPE reapchild TAC_ARGS((int signo));
114 signal(SIGCHLD, reapchild);
117 pid = wait3(&status, WNOHANG, 0);
120 if (debug & DEBUG_FORK_FLAG)
121 report(LOG_DEBUG, "%d reaped", pid);
124 #endif /* REAPCHILD */
126 static void die TAC_ARGS((int signum));
132 report(LOG_INFO, "Received signal %d, shutting down", signum);
137 static void init TAC_ARGS((void));
145 report(LOG_INFO, "Reading config");
147 session.acctfile = tac_strdup("/var/log/acctfile");
149 if (!session.cfgfile) {
150 report(LOG_ERR, "no config file specified");
154 /* read the config file */
155 if (cfg_read_config(session.cfgfile)) {
156 report(LOG_ERR, "Parsing %s", session.cfgfile);
157 fprintf(stderr,"Config file not found!!\n");
163 report(LOG_INFO, "Version %s%s Initialized %d", VERSION, VERSION_TAIL, initialised);
167 /* 'handler()' will be called during initialization to setup signal handler,
168 * keep it in mind when modifying it!
171 static int handler_occured = 0;
173 static RETSIGTYPE handler TAC_ARGS((int signum));
179 /* never execute any non-trivial (=system-call) commands here
180 * as it may immediately abort the whole 'handler()' (SYSV signal).
181 * We hope that SA_RESTART is NOT set for our signals
184 /* It is never wrong to reinstall 'handler' just to be safe */
185 signal(SIGUSR1, handler);
186 signal(SIGHUP , handler);
188 /* DON'T interrupt! */
189 #ifdef HAVE_SIGINTERRUPT
190 siginterrupt(SIGUSR1, 0 /* flag */);
191 siginterrupt(SIGHUP , 0 /* flag */);
195 static void check_handler_occured TAC_ARGS((void));
198 check_handler_occured()
201 if (!handler_occured)
205 report(LOG_INFO, "Signal detected, reloading configuration");
210 * Return a socket bound to an appropriate port number/address. Exits
211 * the program on failure */
213 static int get_socket TAC_ARGS((void));
219 struct sockaddr_in sin;
223 bzero((char *) &sin, sizeof(sin));
226 sin.sin_port = htons(port);
228 sp = getservbyname("tacacs", "tcp");
230 sin.sin_port = sp->s_port;
232 report(LOG_ERR, "Cannot find socket port");
237 sin.sin_family = AF_INET;
238 sin.sin_addr.s_addr = htonl(INADDR_ANY);
240 s = socket(AF_INET, SOCK_STREAM, 0);
244 report(LOG_ERR, "get_socket: socket: %s", sys_errlist[errno]);
248 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on,
250 perror("setsockopt - SO_REUSEADDR");
251 #endif /* SO_REUSEADDR */
253 if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
255 report(LOG_ERR, "get_socket: bind %d %s",
263 static void open_logfile TAC_ARGS((void));
269 openlog("tac_plus", LOG_PID, LOG_LOCAL6);
271 openlog("tac_plus", LOG_PID);
273 setlogmask(LOG_UPTO(LOG_DEBUG));
276 static void prep_session_peer TAC_ARGS((const struct sockaddr_in *from));
279 prep_session_peer(from)
280 const struct sockaddr_in *from;
284 if (session.peer_addr && session.peer_addr != session.peer)
285 free(session.peer_addr);
289 session.peer_addr = tac_strdup( (char *) inet_ntoa(from->sin_addr) );
291 hp = gethostbyaddr((char *) &from->sin_addr.s_addr, sizeof(from->sin_addr.s_addr), AF_INET);
294 session.peer = tac_strdup(hp->h_name);
296 session.peer = session.peer_addr;
302 * We will eventually be called from inetd or via the rc scripts directly
303 * Parse arguments and act appropiately.
306 int main TAC_ARGS((int argc, char **argv));
320 debug = 0; /* no debugging */
321 standalone = 1; /* standalone */
322 single = 0; /* single threaded */
324 /* initialise global session data */
325 bzero(&session, sizeof(session));
326 session.peer = tac_strdup("unknown");
331 port = TAC_PLUS_PORT;
334 #ifdef MAINTAINER_MODE
335 session.cfgfile = "/etc/tacacs/tac_plus.cfg";
339 fprintf(stderr, "Usage: tac_plus -C <configuration file>\n");
340 fprintf(stderr, "\t[ -t ] [ -P ] [ -g ] [ -p <port> ]\n");
341 fprintf(stderr, "\t[ -d <debug level> ] [ -i ] [ -v ] [ -s ]\n");
342 fprintf(stderr, "\t[ -l logfile ]");
344 fprintf(stderr, " [ -w whologfile ]");
346 fprintf(stderr, "\n");
350 while ((c = getopt(argc, argv, "td:C:ip:PgvsLl:w:u:")) != EOF)
352 case 'L': /* lookup peer names via DNS */
355 case 's': /* don't respond to sendpass */
358 case 'v': /* print version and exit */
362 console++; /* log to console too */
364 case 'P': /* Parse config file only */
367 case 'g': /* single threaded */
373 case 'd': /* debug */
374 debug = atoi(optarg);
376 case 'C': /* config file name */
377 session.cfgfile = tac_strdup(optarg);
379 case 'i': /* stand-alone */
382 case 'l': /* logfile */
383 logfile = tac_strdup(optarg);
386 case 'w': /* wholog file */
387 wholog = tac_strdup(optarg);
391 wtmpfile = tac_strdup(optarg);
395 fprintf(stderr, "%s: bad switch %c\n", argv[0], c);
399 if (geteuid() != 0) {
400 fprintf(stderr, "Warning, not running as uid 0\n");
401 fprintf(stderr, "Tac_plus is usually run as root\n");
408 handler(-1 /* signum */); /* connect to the signals */
409 handler_occured = 0; /* post-fix cludge */
411 signal(SIGTERM, die);
412 signal(SIGPIPE, SIG_IGN);
418 report(LOG_DEBUG, "tac_plus server %s%s starting", VERSION, VERSION_TAIL);
421 /* running under inetd */
422 struct sockaddr_in name;
428 name_len = sizeof(name);
430 if (getpeername(session.sock, (struct sockaddr *) &name, &name_len)) {
431 report(LOG_ERR, "getpeername failure %s", sys_errlist[errno]);
432 prep_session_peer(NULL);
434 prep_session_peer(&name);
438 if (ioctl(session.sock, FIONBIO, &fionbio_on) < 0) {
439 report(LOG_ERR, "ioctl(FIONBIO) %s", sys_errlist[errno]);
448 /* Running standalone. Background ourselves, let go of controlling tty */
451 signal(SIGTTOU, SIG_IGN);
454 signal(SIGTTIN, SIG_IGN);
457 signal(SIGTSTP, SIG_IGN);
460 signal(SIGHUP, SIG_IGN);
462 if ((childpid = fork()) < 0)
463 report(LOG_ERR, "Can't fork first child");
464 else if (childpid > 0)
465 exit(0); /* parent */
468 report(LOG_DEBUG, "Backgrounded");
474 #else /* SETPGRP_VOID */
475 if (setpgrp(0, getpid()) == -1)
476 #endif /* SETPGRP_VOID */
477 report(LOG_ERR, "Can't change process group");
480 c = open("/dev/tty", O_RDWR);
482 ioctl(c, TIOCNOTTY, (char *) 0);
486 signal(SIGCHLD, reapchild);
488 #else /* REAPCHILD */
492 #else /* SETPGRP_VOID */
493 if (setpgrp(0, getpid()) == 1)
494 #endif /* SETPGRP_VOID */
495 report(LOG_ERR, "Can't change process group");
497 signal(SIGHUP, SIG_IGN);
499 if ((childpid = fork()) < 0)
500 report(LOG_ERR, "Can't fork second child");
501 else if (childpid > 0)
504 if (debug & DEBUG_FORK_FLAG)
505 report(LOG_DEBUG, "Forked grandchild");
507 signal(SIGCHLD, SIG_IGN);
509 #endif /* REAPCHILD */
511 closelog(); /* some systems require this */
513 for (c = 0; c < getdtablesize(); c++)
516 /* make sure we can still log to syslog now we've closed everything */
519 } /* ! single threaded */
530 #define SOMAXCONN 128
534 #endif /* SOMAXCONN */
536 if (listen(s, SOMAXCONN) < 0) {
538 report(LOG_ERR, "listen: %s", sys_errlist[errno]);
542 if (port == TAC_PLUS_PORT) {
543 strcpy(pidfilebuf, TACPLUS_PIDFILE);
545 sprintf(pidfilebuf, "%s.%d", TACPLUS_PIDFILE, port);
548 /* write process id to pidfile */
549 if ((fp = fopen(pidfilebuf, "w")) != NULL) {
550 fprintf(fp, "%d\n", (int) getpid());
553 report(LOG_ERR, "Cannot write pid to %s %s",
554 pidfilebuf, sys_errlist[errno]);
556 #ifdef TACPLUS_GROUPID
557 if (setgid(TACPLUS_GROUPID))
558 report(LOG_ERR, "Cannot set group id to %d %s",
559 TACPLUS_GROUPID, sys_errlist[errno]);
562 #ifdef TACPLUS_USERID
563 if (setuid(TACPLUS_USERID))
564 report(LOG_ERR, "Cannot set user id to %d %s",
565 TACPLUS_USERID, sys_errlist[errno]);
572 report(LOG_DEBUG, "uid=%d euid=%d gid=%d egid=%d s=%d",
573 (int) getuid(), (int) geteuid(), (int) getgid(), (int) getegid(), s);
577 struct sockaddr_in from;
581 check_handler_occured();
583 bzero((char *) &from, sizeof(from));
584 from_len = sizeof(from);
586 /* PERMIT interrupt of accept()! */
587 #ifdef HAVE_SIGINTERRUPT
588 siginterrupt(SIGUSR1, 1 /* flag */);
589 siginterrupt(SIGHUP , 1 /* flag */);
593 newsockfd = accept(s, (struct sockaddr *) &from, &from_len);
595 /* DON'T interrupt! */
596 #ifdef HAVE_SIGINTERRUPT
597 siginterrupt(SIGUSR1, 0 /* flag */);
598 siginterrupt(SIGHUP , 0 /* flag */);
601 check_handler_occured();
604 /* sometimes we may get even 'errno==0' when 'handler()' signal occured */
605 if (errno == EINTR || errno == 0)
608 report(LOG_ERR, "accept: %s", sys_errlist[errno]);
611 prep_session_peer(&from);
613 if (debug & DEBUG_PACKET_FLAG)
614 report(LOG_DEBUG, "session request from %s sock=%d",
615 session.peer, newsockfd);
621 report(LOG_ERR, "fork error");
632 session.sock = newsockfd;
634 shutdown(session.sock, 2);
639 if (debug & DEBUG_FORK_FLAG)
640 report(LOG_DEBUG, "forked %d", pid);
653 #endif /* GETDTABLESIZE */
655 static int bad_version_check TAC_ARGS((u_char *pak));
657 /* Make sure version number is kosher. Return 0 if it is */
659 bad_version_check(pak)
662 HDR *hdr = (HDR *) pak;
665 case TAC_PLUS_AUTHEN:
667 * Let authen routines take care of more sophisticated version
668 * checking as its now a bit involved.
672 case TAC_PLUS_AUTHOR:
674 if (hdr->version != TAC_PLUS_VER_0) {
675 send_error_reply(hdr->type, "Illegal packet version");
686 * Determine the packet type, read the rest of the packet data,
687 * decrypt it and call the appropriate service routine.
691 static void start_session TAC_ARGS((void));
703 /* Now we are starting our new 'request' cycle */
704 cfg_request_scan_begin();
711 if (debug & DEBUG_PACKET_FLAG) {
712 report(LOG_DEBUG, "validation request from %s", session.peer);
717 session.session_id = ntohl(hdr->session_id);
719 /* Do some version checking */
720 if (bad_version_check(pak)) {
726 case TAC_PLUS_AUTHEN:
731 case TAC_PLUS_AUTHOR:
741 /* Note: can't send error reply if type is unknown */
742 report(LOG_ERR, "Illegal type %d in received packet", hdr->type);
748 static void version TAC_ARGS((void));
753 fprintf(stdout, "tac_plus version %s%s\n", VERSION, VERSION_TAIL);
755 fprintf(stdout,"AIX\n");
758 fprintf(stdout,"ARAP_DES\n");
761 fprintf(stdout,"BSDI\n");
763 #ifdef CONST_SYSERRLIST
764 fprintf(stdout,"CONST_SYSERRLIST\n");
767 fprintf(stdout,"DEBUG\n");
770 fprintf(stdout,"DES_DEBUG\n");
773 fprintf(stdout,"FIONBIO\n");
776 fprintf(stdout,"FREEBSD\n");
779 fprintf(stdout,"GETDTABLESIZE\n");
782 fprintf(stdout,"HPUX\n");
785 fprintf(stdout,"LINUX\n");
788 fprintf(stdout,"LOG_LOCAL6\n");
791 fprintf(stdout,"MAXSESS\n");
794 fprintf(stdout,"MIPS\n");
797 fprintf(stdout,"NEED_BZERO\n");
800 fprintf(stdout,"NETBSD\n");
803 fprintf(stdout,"REAPCHILD\n");
805 #ifdef SHADOW_PASSWORDS
806 fprintf(stdout,"SHADOW_PASSWORDS\n");
809 fprintf(stdout,"SIGTSTP\n");
812 fprintf(stdout,"SIGTTIN\n");
815 fprintf(stdout,"SIGTTOU\n");
818 fprintf(stdout,"SKEY\n");
821 fprintf(stdout,"SOLARIS\n");
824 fprintf(stdout,"SO_REUSEADDR\n");
827 fprintf(stdout,"HAVE_STRCSPN\n");
830 fprintf(stdout,"SYSV\n");
832 #ifdef TACPLUS_GROUPID
833 fprintf(stdout,"TACPLUS_GROUPID\n");
836 fprintf(stdout,"TAC_PLUS_PORT\n");
838 #ifdef TACPLUS_USERID
839 fprintf(stdout,"TACPLUS_USERID\n");
842 fprintf(stdout,"UNIONWAIT\n");
845 fprintf(stdout,"_BSD1\n");
848 fprintf(stdout,"_BSD_INCLUDES\n");
851 fprintf(stdout,"__STDC__\n");