示例#1
0
文件: tac_plus.c 项目: Babar/tac_plus
static int
init(void)
{
    if (initialised)
	cfg_clean_config();

    report(LOG_NOTICE, "Reading config");

    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);
	tac_exit(1);
    }

    if (session.acctfile == NULL && !(session.flags & SESS_FLAG_ACCTSYSL))
	session.acctfile = tac_strdup(TACPLUS_ACCTFILE);

    initialised++;
    reinitialize = 0;
    report(LOG_NOTICE, "Version %s Initialized %d", version, initialised);

    return 0;
}
示例#2
0
文件: tac_plus.c 项目: Babar/tac_plus
static RETSIGTYPE
die(int signum)
{
    report(LOG_NOTICE, "Received signal %d, shutting down", signum);
    if (childpid > 0)
	unlink(pidfilebuf);
    tac_exit(0);
}
示例#3
0
文件: utils.c 项目: Babar/tac_plus
char *
tac_strdup(char *p)
{
    if (p != NULL) {
      char *n = strdup(p);

      if (n == NULL) {
        report(LOG_ERR, "strdup allocation failure");
        tac_exit(1);
      }
      return(n);
    }
    report(LOG_ERR, "tac_strdup passed char* is NULL");
    return(NULL);
}
示例#4
0
文件: parse.c 项目: rfdrake/tac_plus
static void
declare(char *name, int value)
{
    KEYWORD *n;
    KEYWORD *k = (KEYWORD *)tac_malloc(sizeof(KEYWORD));

    k->word = tac_strdup(name);
    k->value = value;

    n = hash_add_entry(wordtable, (void *) k);

    if (n) {
	report(LOG_ERR, "Attempt to multiply define keyword %s", name);
	tac_exit(1);
    }
}
示例#5
0
文件: utils.c 项目: Babar/tac_plus
char *
tac_realloc(char *ptr, int size)
{
    char *p;

    if (ptr == NULL) {
	/* realloc(0, size) is not portable */
	p = tac_malloc(size);
    } else {
	p = (char *)realloc(ptr, size);
    }

    if (p == NULL) {
	report(LOG_ERR, "realloc %d failure", size);
	tac_exit(1);
    }
    return(p);
}
示例#6
0
文件: utils.c 项目: Babar/tac_plus
char *
tac_malloc(int size)
{
    char *p;

    /* some mallocs don't like requests for zero length */
    if (size == 0) {
	size++;
    }

    p = (char *)malloc(size);

    if (p == NULL) {
	report(LOG_ERR, "malloc %d failure: %s", size, strerror(errno));
	tac_exit(1);
    }
    return(p);
}
示例#7
0
文件: tac_plus.c 项目: Babar/tac_plus
/*
 * We will eventually be called from inetd or via the rc scripts directly
 * Parse arguments and act appropiately.
 */
int
main(int argc, char **argv)
{
    extern char *optarg;
    FILE *fp;
    int	c, *s, ns;
    struct pollfd *pfds;

#if PROFILE
    moncontrol(0);
#endif

    if ((progname = strrchr(*argv, '/')) != NULL) {
	progname++;
    } else
	progname = *argv;

    /* initialise global session data */
    memset(&session, 0, sizeof(session));
    session.peer = tac_strdup("unknown");


    if (argc <= 1) {
	usage();
	tac_exit(1);
    }

    while ((c = getopt(argc, argv, "B:C:d:hiPp:tGgvSsLw:u:")) != EOF)
	switch (c) {
	case 'B':		/* bind() address*/
	    bind_address = optarg;
	    break;
	case 'L':		/* lookup peer names via DNS */
	    lookup_peer = 1;
	    break;
	case 's':		/* don't respond to sendpass */
	    sendauth_only = 1;
	    break;
	case 'v':		/* print version and exit */
	    vers();
	    tac_exit(1);
	case 't':
	    console = 1;	/* log to console too */
	    break;
	case 'P':		/* Parse config file only */
	    parse_only = 1;
	    break;
	case 'G':		/* foreground */
	    opt_G = 1;
	    break;
	case 'g':		/* single threaded */
	    single = 1;
	    break;
	case 'p':		/* port */
	    port = atoi(optarg);
	    portstr = optarg;
	    break;
	case 'd':		/* debug */
	    debug |= atoi(optarg);
	    break;
	case 'C':		/* config file name */
	    session.cfgfile = tac_strdup(optarg);
	    break;
	case 'h':		/* usage */
	    usage();
	    tac_exit(0);
	case 'i':		/* inetd mode */
	    standalone = 0;
	    break;
	case 'S':		/* enable single-connection */
	    opt_S = 1;
	    break;
#ifdef MAXSESS
	case 'w':		/* wholog file */
	    wholog = tac_strdup(optarg);
	    break;
#endif
	case 'u':
	    wtmpfile = tac_strdup(optarg);
	    break;

	default:
	    fprintf(stderr, "%s: bad switch %c\n", progname, c);
	    usage();
	    tac_exit(1);
	}

    parser_init();

    /* read the configuration/etc */
    init();
#if defined(REAPCHILD) && defined(REAPSIGIGN)
    client_count_init();
#endif
    open_logfile();

    signal(SIGUSR1, handler);
    signal(SIGHUP, handler);
    signal(SIGUSR2, dump_clients_handler);
    signal(SIGTERM, die);
    signal(SIGPIPE, SIG_IGN);

    if (parse_only)
	tac_exit(0);

    if (debug)
	report(LOG_DEBUG, "tac_plus server %s starting", version);

    if (!standalone) {
	/* running under inetd */
	char host[NI_MAXHOST];
	int on;
#ifdef IPV6
	struct sockaddr_in6 name;
#else
  struct sockaddr_in name;
#endif
	socklen_t name_len;

	name_len = sizeof(name);
	session.flags |= SESS_NO_SINGLECONN;

	session.sock = 0;
#ifdef IPV6
	if (getpeername(session.sock, (struct sockaddr6 *)&name, &name_len)) {
	    report(LOG_ERR, "getpeername failure %s", strerror(errno));
#else
	if (getpeername(session.sock, (struct sockaddr *)&name, &name_len)) {
	    report(LOG_ERR, "getpeername failure %s", strerror(errno));
#endif
	} else {
	    if (lookup_peer)
		on = 0;
	    else
		on = NI_NUMERICHOST;
#ifdef IPV6
	    if (getnameinfo((struct sockaddr6 *)&name, name_len, host, 128,
			    NULL, 0, on)) {
#else
	    if (getnameinfo((struct sockaddr *)&name, name_len, host, 128,
			    NULL, 0, on)) {
#endif
		strncpy(host, "unknown", NI_MAXHOST - 1);
		host[NI_MAXHOST - 1] = '\0';
	    }
	    if (session.peer) free(session.peer);
	    session.peer = tac_strdup(host);

	    if (session.peerip) free(session.peerip);
#ifdef IPV6
	    session.peerip = tac_strdup((char *)inet_ntop(name.sin6_family,
					&name.sin6_addr, host, name_len));
#else
	    session.peerip = tac_strdup((char *)inet_ntop(name.sin_family,
					&name.sin_addr, host, name_len));
#endif
	    if (debug & DEBUG_AUTHEN_FLAG)
		report(LOG_INFO, "session.peerip is %s", session.peerip);
	}
#ifdef FIONBIO
	on = 1;
	if (ioctl(session.sock, FIONBIO, &on) < 0) {
	    report(LOG_ERR, "ioctl(FIONBIO) %s", strerror(errno));
	    tac_exit(1);
	}
#endif
	start_session();
	tac_exit(0);
 }

    if (single) {
	session.flags |= SESS_NO_SINGLECONN;
    } else {
	/*
	 * Running standalone; background ourselves and release controlling
	 * tty, unless -G option was specified to keep the parent in the
	 * foreground.
	 */
#ifdef SIGTTOU
	signal(SIGTTOU, SIG_IGN);
#endif
#ifdef SIGTTIN
	signal(SIGTTIN, SIG_IGN);
#endif
#ifdef SIGTSTP
	signal(SIGTSTP, SIG_IGN);
#endif
	if (!opt_S)
	    session.flags |= SESS_NO_SINGLECONN;

	if (!opt_G) {
	    if ((childpid = fork()) < 0)
		report(LOG_ERR, "Can't fork first child");
	    else if (childpid > 0)
		exit(0);		/* parent */

	    if (debug)
		report(LOG_DEBUG, "Backgrounded");

#if SETPGRP_VOID
	    if (setpgrp() == -1)
#else
	    if (setpgrp(0, getpid()) == -1)
#endif /* SETPGRP_VOID */
		report(LOG_ERR, "Can't change process group: %s",
		       strerror(errno));

	    /* XXX What does "REAPCHILD" have to do with TIOCNOTTY? */
#ifndef REAPCHILD
	    c = open("/dev/tty", O_RDWR);
	    if (c >= 0) {
		ioctl(c, TIOCNOTTY, (char *)0);
		(void) close(c);
	    }
#else /* REAPCHILD */
	    if ((childpid = fork()) < 0)
		report(LOG_ERR, "Can't fork second child");
	    else if (childpid > 0)
		exit(0);

	    if (debug & DEBUG_FORK_FLAG)
		report(LOG_DEBUG, "Forked grandchild");

#endif /* REAPCHILD */

	    /* some systems require this */
	    closelog();

	    for (c = getdtablesize(); c >= 0; c--)
		(void)close(c);

	    /*
	     * make sure we can still log to syslog now that we have closed
	     * everything
	     */
	    open_logfile();
	}
    }
#if REAPCHILD
#if REAPSIGIGN
    signal(SIGCHLD, reapchild);
#else
    signal(SIGCHLD, SIG_IGN);
#endif
#endif

    ostream = NULL;
    /* chdir("/"); */
    umask(022);
    errno = 0;

    get_socket(&s, &ns);

#ifndef SOMAXCONN
#define SOMAXCONN 5
#endif

    for (c = 0; c < ns; c++) {
	if (listen(s[c], SOMAXCONN) < 0) {
	    console = 1;
	report(LOG_ERR, "listen: %s", strerror(errno));
	tac_exit(1);
    }
    }

    if (port == TAC_PLUS_PORT) {
	if (bind_address == NULL) {
	    strncpy(pidfilebuf, TACPLUS_PIDFILE, PIDSZ);
	    if (pidfilebuf[PIDSZ - 1] != '\0')
		c = PIDSZ;
	    else
		c = PIDSZ - 1;
	} else
	    c = snprintf(pidfilebuf, PIDSZ, "%s.%s", TACPLUS_PIDFILE,
			 bind_address);
    } else {
	if (bind_address == NULL)
	    c = snprintf(pidfilebuf, PIDSZ, "%s.%d", TACPLUS_PIDFILE, port);
	else
	    c = snprintf(pidfilebuf, PIDSZ, "%s.%s.%d", TACPLUS_PIDFILE,
			 bind_address, port);
    }
    if (c >= PIDSZ) {
	pidfilebuf[PIDSZ - 1] = '\0';
	report(LOG_ERR, "pid filename truncated: %s", pidfilebuf);
	childpid = 0;
    } else {
	/* write process id to pidfile */
	if ((fp = fopen(pidfilebuf, "w")) != NULL) {
	    fprintf(fp, "%d\n", (int)getpid());
	    fclose(fp);
	    /*
	     * After forking to disassociate; make sure we know we're the
	     * mother so that we remove our pid file upon exit in die().
	     */
	    childpid = 1;
	} else {
	    report(LOG_ERR, "Cannot write pid to %s %s", pidfilebuf,
		   strerror(errno));
	    childpid = 0;
	}
    }
#ifdef TACPLUS_GROUPID
    if (setgid(TACPLUS_GROUPID))
	report(LOG_ERR, "Cannot set group id to %d %s",
	       TACPLUS_GROUPID, strerror(errno));
#endif

#ifdef TACPLUS_USERID
    if (setuid(TACPLUS_USERID))
	report(LOG_ERR, "Cannot set user id to %d %s",
	       TACPLUS_USERID, strerror(errno));
#endif

#ifdef MAXSESS
    maxsess_loginit();
#endif /* MAXSESS */

    report(LOG_DEBUG, "uid=%d euid=%d gid=%d egid=%d s=%d",
	   getuid(), geteuid(), getgid(), getegid(), s);

    pfds = malloc(sizeof(struct pollfd) * ns);
    if (pfds == NULL) {
	report(LOG_ERR, "malloc failure: %s", strerror(errno));
	tac_exit(1);
    }
    for (c = 0; c < ns; c++) {
	pfds[c].fd = s[c];
	pfds[c].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
    }

    for (;;) {
#if HAVE_PID_T
	pid_t pid;
#else
	int pid;
#endif
	char host[NI_MAXHOST];
#ifdef IPV6
	struct sockaddr_in6 from;
#else
	struct sockaddr_in from;
#endif
	socklen_t from_len;
	int newsockfd, status;
	int flags;
  int procs_for_client;

#if defined(REAPCHILD) && defined(REAPSIGIGN)
  if (reap_children)
    reapchildren();
#endif

	if (reinitialize)
	    init();

  if (dump_client_table) {
    report(LOG_ALERT, "Dumping Client Tables");
    dump_client_tables();
    dump_client_table = 0;
  }

	status = poll(pfds, ns, cfg_get_accepttimeout() * 1000);
	if (status == 0)
	    continue;
	if (status == -1)
	    if (errno == EINTR)
		continue;

	from_len = sizeof(from);
	memset((char *)&from, 0, from_len);
	for (c = 0; c < ns; c++) {
	    if (pfds[c].revents & POLLIN)
  #ifdef IPV6
		newsockfd = accept(s[c], (struct sockaddr6 *)&from, &from_len);
  #else
		newsockfd = accept(s[c], (struct sockaddr *)&from, &from_len);
  #endif
	    else if (pfds[c].revents & (POLLERR | POLLHUP | POLLNVAL)) {
		report(LOG_ERR, "exception on listen FD %d", s[c]);
		tac_exit(1);
	    }
	}

	if (newsockfd < 0) {
	    if (errno == EINTR)
		continue;

	    report(LOG_ERR, "accept: %s", strerror(errno));
	    continue;
	}

	if (lookup_peer)
	    flags = 0;
	else
	    flags = NI_NUMERICHOST;
#ifdef IPV6
	if (getnameinfo((struct sockaddr_in6 *)&from, from_len, host, 128, NULL, 0,
			flags)) {
#else
	if (getnameinfo((struct sockaddr_in *)&from, from_len, host, 128, NULL, 0,
			flags)) {
#endif
	    strncpy(host, "unknown", NI_MAXHOST - 1);
	    host[NI_MAXHOST - 1] = '\0';
	}

	if (session.peer) free(session.peer);
	session.peer = tac_strdup(host);

	if (session.peerip) free(session.peerip);
#ifdef IPV6
	session.peerip = tac_strdup((char *)inet_ntop(from.sin6_family,
          &from.sin6_addr, host, INET6_ADDRSTRLEN));
#else
	session.peerip = tac_strdup((char *)inet_ntop(from.sin_family,
          &from.sin_addr, host, INET_ADDRSTRLEN));
#endif
	if (debug & DEBUG_PACKET_FLAG)
	    report(LOG_DEBUG, "session request from %s sock=%d",
		   session.peer, newsockfd);

	if (!single) {
#if defined(REAPCHILD) && defined(REAPSIGIGN)
      /* first we check the tocal process count to see if we are at the limit */
      if (total_child_count >= cfg_get_maxprocs()) {
        report(LOG_ALERT, "refused connection from %s [%s] at global max procs [%d]",
          session.peer, session.peerip, total_child_count);
        shutdown(newsockfd, 2);
        close(newsockfd);
        continue;
      }
      /* no we check the process count per client */
      procs_for_client = get_client_count(session.peerip);
      report(LOG_ALERT, "connection [%d] from %s [%s]", procs_for_client + 1, session.peer, session.peerip);
      if (procs_for_client >= cfg_get_maxprocsperclt()) {
        report(LOG_ALERT, "refused connection from %s [%s] at client max procs [%d]",
          session.peer, session.peerip, procs_for_client);
        shutdown(newsockfd, 2);
        close(newsockfd);
        continue;
      }
#endif
	    pid = fork();
	    if (pid < 0) {
		    report(LOG_ERR, "fork error");
		    tac_exit(1);
	    }
	} else {
	    pid = 0;
	}
	if (pid == 0) {
	  /* child */
	  if (!single) {
            if (ns > 1) {
              for (c = 0; c < ns; c++) {
                close(s[c]);
              }
            }
          }
	  session.sock = newsockfd;
#ifdef LIBWRAP
	  if (! hosts_ctl(progname,session.peer,session.peerip,progname)) {
		  report(LOG_ALERT, "refused connection from %s [%s]",
		       session.peer, session.peerip);
      shutdown(session.sock, 2);
      close(session.sock);
      if (!single) {
          tac_exit(0);
      } else {
          close(session.sock);
          continue;
      }
    }
    if (debug)
      report(LOG_DEBUG, "connect from %s [%s]", session.peer, session.peerip);
#endif
#if PROFILE
	    moncontrol(1);
#endif

	    start_session();
	    shutdown(session.sock, 2);
	    close(session.sock);
	    if (!single)
		    tac_exit(0);
	} else {
	    /* parent */
#if defined(REAPCHILD) && defined(REAPSIGIGN)
      total_child_count++;
      procs_for_client = increment_client_count_for_proc(pid, session.peerip);
      snprintf(msgbuf, MSGBUFSZ, "forked %lu for %s, procs %d, procs for client %d",
            (long)pid, session.peerip, total_child_count, procs_for_client);
		    report(LOG_DEBUG, msgbuf);
#endif
	    close(newsockfd);
	}
    }
}
示例#8
0
文件: tac_plus.c 项目: Babar/tac_plus
/*
 * Return a socket bound to an appropriate port number/address. Exits
 * the program on failure.
 */
static int
get_socket(int **sa, int *nsa)
{
    char	host[NI_MAXHOST], serv[NI_MAXHOST];
    struct addrinfo hint, *res, *rp;
    u_long inaddr;
    int		ecode,
		flag,
		kalive = 1,
		s;

    memset(&hint, 0, sizeof(struct addrinfo));
    hint.ai_family = AF_UNSPEC;
    hint.ai_socktype = SOCK_STREAM;
    hint.ai_protocol = IPPROTO_TCP;
    hint.ai_flags = AI_PASSIVE;
#ifdef AI_ADDRCONFIG
    hint.ai_flags |= AI_ADDRCONFIG;
#endif
    if (bind_address)
	ecode = getaddrinfo(bind_address, portstr, &hint, &res);
    else
	ecode = getaddrinfo(NULL, portstr, &hint, &res);
    if (ecode != 0) {
	report(LOG_ERR, "getaddrinfo: %s\n", gai_strerror(ecode));
	    tac_exit(1);
	}

    *sa = NULL;
    *nsa = 0;
    for (rp = res; rp != NULL; rp = rp->ai_next) {
	s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
	if (s == -1)
	    continue;

	if (1 || debug & DEBUG_PACKET_FLAG)
	    report(LOG_DEBUG, "socket FD %d AF %d", s, rp->ai_family);
	flag = 1;
	if (rp->ai_family == AF_INET6)
	    setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag));
#ifdef SO_REUSEADDR
	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&flag,
		       sizeof(flag)) < 0)
	perror("setsockopt - SO_REUSEADDR");
#endif
    if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *)&kalive,
		   sizeof(kalive)) < 0)
	    perror("setsockopt - SO_KEEPALIVE");
	flag = 0;
	if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *)&flag,
		       sizeof(flag)) < 0)
	    perror("setsockopt - SO_NODELAY");

	if (bind(s, rp->ai_addr, rp->ai_addrlen) < 0) {
	    console = 1;
	    ecode = errno;
	    if (lookup_peer)
		flag = 0;
	    else
		flag = NI_NUMERICHOST | NI_NUMERICSERV;
	    if (getnameinfo(rp->ai_addr, rp->ai_addrlen, host, NI_MAXHOST,
			    serv, NI_MAXHOST, flag)) {
		strncpy(host, "unknown", NI_MAXHOST - 1);
		host[NI_MAXHOST - 1] = '\0';
		strncpy(serv, "unknown", NI_MAXHOST - 1);
		serv[NI_MAXHOST - 1] = '\0';
	    }
	    report(LOG_ERR, "get_socket: bind %s:%s %s", host, serv,
		   strerror(ecode));
	    console = 0;
	    close(s);
	    s = -1;
	    continue;
	}
	if (*sa == NULL)
	    *sa = malloc(sizeof(int) * ++(*nsa));
	else
	    *sa = realloc(*sa, sizeof(int) * ++(*nsa));
	if (*sa == NULL) {
	    report(LOG_ERR, "malloc failure: %s", strerror(errno));
	tac_exit(1);
    }
	(*sa)[*nsa - 1] = s;
    }
    freeaddrinfo(res);

    if (*nsa < 1) {
	console = 1;
	report(LOG_ERR, "get_socket: could not bind a listening socket");
	tac_exit(1);
    }
    return(0);
}