int main (int argc, char **argv) { int status; int i; /* configure interface */ for (i = 0 ; i < (sizeof(ifinfo)/sizeof(struct ifinfo)) ; i++) { struct ifinfo *ifn = &ifinfo[i]; ipaddr_t broadcast; apply_netmask_broadcast(broadcast,(char *)&ifn->ip, (char *)&ifn->netmask); printf(" Name: %s ",ifn->interface); printf("Ip Address: %s ",pripaddr((char *)&ifn->ip)); printf("Netmask: %s ",pripaddr((char *)&ifn->netmask)); printf("Broadcast: %s\n",pripaddr(broadcast)); status = ifconfig(ifn->interface,ifn->flags, (char *)&ifn->ip, (char *)&ifn->netmask,broadcast); printf("ifconfig %s => %d\n",ifn->interface,status); if (status != 0) { printf("ifconfig failed\n"); } } /* add default route */ status = route_add(ROUTE_INET, ((ipaddr_t){0,0,0,0}), ((ipaddr_t){0,0,0,0}), mygateway); printf("route add default %s ==> %d\n",pripaddr(mygateway),status); /* start arp daemon, necessary to be started before mounting nfs server * so that the server can resolve our ip address, and we can resolve his. */ { extern void arpd_main (void); if (fork () == 0) { arpd_main (); } } /* mount the nfs root */ { extern int nfs_mount_root(); printf("MOUNTING ROOT: "); status = nfs_mount_root(nfs_server_ip,nfs_server_path); printf("DONE\n"); if (status != 0) { printf("failed (errno: %d)\n",errno); printf("check machine \"%s\" /etc/exports file, and make sure that you\n" "either have -alldirs or the exact directory there\n" "you have restarted mountd after making changes\n" "and that you have the proper permission\n",nfs_server_ip); printf("fix the problem and try again\n"); } } /* configuring lo0: configure loopback interface and route * ip packets from our machineip to our machineip via loopback * interface */ { ipaddr_t lo0mask = {255,255,255,255}; if_show(); status = ifconfig("lo0",IF_UP|IF_LOOPBACK, IPADDR_LOOPBACK, lo0mask, IPADDR_BROADCAST); printf("ifconfig lo0 => %d\n",status); for (i = 0 ; i < (sizeof(ifinfo)/sizeof(struct ifinfo)) ; i++) { struct ifinfo *ifn = &ifinfo[i]; status = route_add(ROUTE_INET, ifn->ip,IPADDR_BROADCAST, IPADDR_LOOPBACK); printf("route %s localhost ==> %d\n",pripaddr(ifn->ip),status); } } /* set the hostname */ { struct hostent *h; if ((h = gethostbyaddr(ifinfo[0].ip,4,AF_INET)) != NULL) { printf("My hostname is: %s\n",h->h_name); sethostname(h->h_name,strlen(h->h_name)); setdomainname(DOMAIN,strlen(DOMAIN)); } else { printf("gethostbyaddr %s %d %d failed\n",pripaddr(ifinfo[0].ip),4,AF_INET); } } /* if there is an rc.local files execute it. this is crucial because * otherwise the machine will simple have mounted a file system and stopped */ #ifdef RCLOCAL { struct stat sb; if (stat(RCLOCAL,&sb) == 0) { int status; sys_cputs("Spawning "); sys_cputs(RCLOCAL); sys_cputs("\n"); status = system(RCLOCAL); /* child */ kprintf("%d system(%s) returned %d %d\n",getpid(),RCLOCAL,status,errno); } } #endif /* RCLOCAL */ /* setup reaper */ #if 1 signal(SIGCHLD,reapchild); for(;;) sleep(100); #endif /* the first process now sleeps forever. It can't die, since it holds * references to important resources (like some memory pages) */ #if 0 reapchildren(); #else UAREA.u_status = U_SLEEP; yield(-1); #endif kprintf("FIRST PROCESS SHOULD NEVER PRINT THIS ==> TROUBLE\n"); assert(0); return 0; }
/* * 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); } } }