home *** CD-ROM | disk | FTP | other *** search
- #ifndef lint
- static char *sccsid = "@(#)$Header: serve.c,v 1.37 91/01/10 17:19:52 sob Exp $";
- #endif
-
- /*
- * Main server routine
- */
-
- #include "common.h"
- #include <signal.h>
- #ifdef USG
- #include <sys/times.h>
- #else
- #include <sys/time.h>
- #endif
-
- #ifdef LOG
- # ifndef USG
- # include <sys/resource.h>
- # endif not USG
- #endif
-
- #ifdef TIMERS_DONT_WORK
- #include "timer.h"
- #endif
-
- extern int ahbs(), group(), help(), ihave();
- extern int list(), newgroups(), newnews(), nextlast(), post();
- extern int slave(), stat(), xhdr(), xthread();
-
- extern int errno;
-
- #ifdef AUTH
- extern int doauth();
- #endif AUTH
-
- static struct cmdent {
- char *cmd_name;
- int authreq; /* 0=none,1=userpass */
- int (*cmd_fctn)();
- } cmdtbl[] = {
- #ifdef AUTH
- "authcap", 0, doauth,
- "authinfo", 0, doauth,
- "authsys", 0, doauth,
- #endif AUTH
- "article", 0, ahbs,
- "body", 0, ahbs,
- "group", 0, group,
- "head", 0, ahbs,
- "help", 0, help,
- "ihave", 1, ihave,
- "last", 0, nextlast,
- "list", 0, list,
- "newgroups", 0, newgroups,
- "newnews", 0, newnews,
- "next", 0, nextlast,
- "post", 1, post,
- "slave", 0, slave,
- "stat", 0, ahbs,
- #ifdef XHDR
- "xhdr", 0, xhdr,
- #endif XHDR
- #ifdef XTHREAD
- "xthread", 0, xthread,
- #endif
- };
- #define NUMCMDS (sizeof(cmdtbl) / sizeof(struct cmdent))
-
- #ifdef TIMEOUT
- static void timeout();
- #endif
- #ifdef LOGINCHECK
- static void logincheck();
- static int firstlogincheck;
- #endif
- #ifdef BATCHED_INPUT
- static void batchcheck();
- #endif
-
- #ifdef TIMERS_DONT_WORK
- static struct timer timers[] = {
- #ifdef TIMEOUT
- { timeout, 1, TIMEOUT, 0 },
- #endif
- #ifdef LOGINCHECK
- { logincheck, 0, LOGINCHECK, 0 },
- #endif
- #ifdef BATCHCHECK
- { batchcheck, 1, BATCHCHECK, 0 },
- #endif
- };
- #define NTIMERS_DONT_WORK (sizeof(timers) / sizeof(struct timer))
- #endif
-
- static char *stats_init();
- #ifdef LOG
- static void stats_finish();
- #endif
-
- #ifdef AUTH
- extern int Needauth;
- extern char User[];
- #endif AUTH
-
- /*
- * serve -- given a connection on stdin/stdout, serve
- * a client, executing commands until the client
- * says goodbye.
- *
- * Parameters: None.
- *
- * Returns: Exits.
- *
- * Side effects: Talks to client, does a lot of
- * stuff.
- */
-
- serve()
- {
- char line[NNTP_STRLEN];
- char host[MAXHOSTNAMELEN];
- char gdbuf[MAXBUFLEN];
- char **argp;
- char *timeptr, *cp;
- int argnum, i;
- #ifdef POSTER
- struct passwd *pp;
- #endif
- #ifdef LOG
- grps_acsd = arts_acsd = 0;
- #endif
-
- /* Not all systems pass fd's 1 and 2 from inetd */
-
- (void) close(1);
- (void) close(2);
- (void) dup(0);
- (void) dup(0);
-
- /* If we're ALONE, then we've already opened syslog */
-
- #ifndef ALONE
- # ifdef SYSLOG
- # ifdef BSD_42
- openlog("nntpd", LOG_PID);
- # else
- openlog("nntpd", LOG_PID, SYSLOG);
- # endif
- # endif
- #endif
-
- timeptr = stats_init();
-
- #ifdef ALONE
- #ifndef USG
- (void) signal(SIGCHLD, SIG_IGN);
- #endif not USG
- #endif
-
- /* Ignore SIGPIPE, since we'll see closed connections with read */
-
- (void) signal(SIGPIPE, SIG_IGN);
-
- /* Get permissions and see if we can talk to this client */
- #ifdef AUTH
- Needauth = 1;
- strcpy(User,"");
- #endif AUTH
- host_access(&canread, &canpost, &canxfer, gdbuf);
-
- if (gethostname(host, sizeof(host)) < 0)
- (void) strcpy(host, "Amnesiac");
-
- #ifdef SETPROCTITLE
- setproctitle("%s", hostname);
- #endif
-
- if (!canread && !canxfer) {
- printf("%d %s NNTP server can't talk to you. Goodbye.\r\n",
- ERR_ACCESS, host);
- (void) fflush(stdout);
- (void) fclose(stdout);
- #ifdef SYSLOG
- syslog(LOG_INFO, "%s refused connection", hostname);
- #endif
- exit(1);
- }
-
- #ifdef LOGINCHECK
- firstlogincheck = 1;
- logincheck();
- firstlogincheck = 0;
- #endif
-
- if ( !canpost && !canread && !space(MINFREE)) {
- printf("%d %s NNTP server out of space. Try later.\r\n",
- ERR_GOODBYE, host);
- (void) fflush(stdout);
- #ifdef SYSLOG
- syslog(LOG_INFO, "%s no space", hostname);
- #endif
- exit(1);
- }
-
- /* If we can talk, proceed with initialization */
-
- ngpermcount = get_nglist(&ngpermlist, gdbuf);
-
- #ifdef POSTER
- pp = getpwnam(POSTER);
- if (pp != NULL) {
- uid_poster = pp->pw_uid;
- gid_poster = pp->pw_gid;
- home_poster = pp->pw_dir;
- } else
- #endif
- uid_poster = gid_poster = 0;
-
- #ifndef FASTFORK
- num_groups = 0;
- num_groups = read_groups(); /* Read in the active file */
- #else
- signal(SIGALRM, SIG_IGN); /* Children don't deal with */
- /* these things */
- #endif
- /*
- * num_groups may be zero if expire is running and the active
- * file is locked. (Under System V with lockf, for example.)
- * Or, something may be really screwed up....
- */
- if (num_groups == 0){ /* can't get a group list */
- printf("%d %s NNTP server unavailable. Try later.\r\n",
- ERR_FAULT, host);
- (void) fflush(stdout);
- #ifdef SYSLOG
- syslog(LOG_INFO, "%s no groups", hostname);
- #endif
- exit(1);
- }
-
- art_fp = NULL;
- argp = (char **) NULL; /* for first time */
-
- if ((cp = index(timeptr, '\n')) != NULL)
- *cp = '\0';
- else
- timeptr = "Unknown date";
- #ifdef AUTH
- printf("%d %s NNTP[auth] server version %s ready at %s (%s).\r\n",
- #else
- printf("%d %s NNTP server version %s ready at %s (%s).\r\n",
- #endif
- canpost ? OK_CANPOST : OK_NOPOST,
- host, nntp_version,
- timeptr,
- canpost ? "posting ok" : "no posting");
- (void) fflush(stdout);
-
- /*
- * Now get commands one at a time and execute the
- * appropriate routine to deal with them.
- */
- #ifdef TIMERS_DONT_WORK
- timer_init(timers, NTIMERS_DONT_WORK);
- #endif
- for (;;) {
- #ifdef TIMERS_DONT_WORK
- /* Don't try to read input unless there is some */
- if (!timer_sleep(timers, NTIMERS_DONT_WORK))
- continue;
- #endif
- if (fgets(line, sizeof(line), stdin) == NULL)
- break;
- /* Strip trailing CR-LF */
- cp = line + strlen(line) - 1;
- while (cp >= line && (*cp == '\n' || *cp == '\r'))
- *cp-- = '\0';
- #ifdef DEBUG
- if (debug)
- syslog(LOG_DEBUG, "<- \"%s\"", line);
- #endif
-
- /* Null command */
- if ((argnum = parsit(line, &argp)) == 0)
- continue;
-
- /* a motion to adjourn is always in order */
- if (!strcasecmp(argp[0], "quit"))
- break;
-
- for (i = 0; i < NUMCMDS; ++i)
- if (!strcasecmp(cmdtbl[i].cmd_name, argp[0]))
- break;
-
- if (i < NUMCMDS) {
- #ifdef SETPROCTITLE
- setproctitle("%s %s", hostname, argp[0]);
- #endif
- #ifdef AUTH
- /* authentication required? */
- if (cmdtbl[i].authreq == 1 && Needauth)
- {
- printf("%d Authentication required for command\r\n", ERR_NOAUTH);
- (void) fflush(stdout);
- continue;
- }
- #endif AUTH
- (*cmdtbl[i].cmd_fctn)(argnum, argp);
- } else {
- #ifdef SYSLOG
- syslog(LOG_INFO, "%s unrecognized %s", hostname, line);
- #endif
- printf("%d Command unrecognized.\r\n", ERR_COMMAND);
- (void) fflush(stdout);
- }
- }
-
- printf("%d %s closing connection. Goodbye.\r\n", OK_GOODBYE, host);
-
- (void) fflush(stdout);
-
- #ifdef BATCHED_INPUT
- batchcheck();
- #endif
-
- #ifdef SYSLOG
- if (ferror(stdout))
- syslog(LOG_ERR, "%s disconnect: %m", hostname);
- #ifdef LOG
- stats_finish();
- #endif
- #endif
-
- #ifdef PROFILE
- profile();
- #endif
- exit(0);
- }
-
- #ifdef TIMEOUT
- /*
- * Called after TIMEOUT seconds of idle time to shut things down.
- * XXX stats are not reported when this occurs
- */
- static void
- timeout()
- {
-
- printf("%d Timeout after %d seconds, closing connection.\r\n",
- ERR_FAULT, TIMEOUT);
- #ifdef SYSLOG
- syslog(LOG_NOTICE, "%s timeout", hostname);
- #endif
- (void) fflush(stdout);
- #ifdef BATCHED_INPUT
- batchcheck();
- #endif
- #ifdef LOG
- stats_finish();
- #endif
- #ifdef PROFILE
- profile();
- #endif
- exit(1);
- }
- #endif
-
- #ifdef LOGINCHECK
- /*
- * Called ever LOGINCHECK seconds to see if logins have been disabled.
- * If so, shut down.
- * XXX stats are not reported when this occurs
- */
- static void
- logincheck()
- {
- char host[MAXHOSTNAMELEN];
-
- if (access(NOLOGIN, F_OK) < 0)
- return;
- if (gethostname(host, sizeof(host)) < 0)
- (void) strcpy(host, "Amnesiac");
- printf("%d Logins are disabled on NNTP server %s. Try again later.\r\n",
- ERR_ACCESS, host);
- (void) fflush(stdout);
- #ifdef SYSLOG
- syslog(LOG_INFO, "%s logins disabled%s",
- hostname, firstlogincheck ? "" : " (kicked out)");
- #endif
- #ifdef BATCHED_INPUT
- batchcheck();
- #endif
- #ifdef LOG
- stats_finish();
- #endif
- #ifdef PROFILE
- profile();
- #endif
- exit(1);
- }
- #endif
-
- #ifdef BATCHED_INPUT
- /*
- * Called after BATCHCHECK seconds of idle time and at the end
- * of a session to see if a batch needs to be launched.
- */
- static void
- batchcheck()
- {
- char errbuf[2 * NNTP_STRLEN];
-
- enqpartbatch(CONT_XFER, ERR_XFERFAIL, errbuf);
- }
- #endif
-
- /*
- * Stats stuff
- */
- static double Tstart, Tfinish;
- static double user, sys;
- #ifdef USG
- static time_t start, finish;
- #else /* not USG */
- static struct timeval start, finish;
- #endif /* not USG */
-
- static char *
- stats_init()
- {
- extern char *ctime();
-
- #ifdef USG
- (void) time(&start);
- Tstart = (double) start;
- return(ctime(&start));
- #else /* not USG */
- (void) gettimeofday(&start, (struct timezone *)NULL);
- Tstart = (double) start.tv_sec + ((double)start.tv_usec)/1000000.0;
- return(ctime(&start.tv_sec));
- #endif /* not USG */
- }
-
- #ifdef LOG
- static void
- stats_finish()
- {
- char buf[NNTP_STRLEN];
- # ifdef USG
- struct tms cpu;
- # else /* not USG */
- struct rusage me, kids;
- # endif /* not USG */
-
- #ifdef USG
- (void) time(&finish);
- Tfinish = (double) finish;
-
- #ifndef HZ
- #define HZ 60.0 /* typical system clock ticks - param.h */
- #endif /* not HZ */
-
- (void) times(&cpu);
- user = (double)(cpu.tms_utime + cpu.tms_cutime) / HZ;
- sys = (double)(cpu.tms_stime + cpu.tms_cstime) / HZ;
- #else /* not USG */
- (void) gettimeofday(&finish, (struct timezone *)NULL);
- Tfinish = (double) finish.tv_sec + ((double)finish.tv_usec)/1000000.0;
-
- (void) getrusage(RUSAGE_SELF, &me);
- (void) getrusage(RUSAGE_CHILDREN, &kids);
-
- user = (double) me.ru_utime.tv_sec + me.ru_utime.tv_usec/1000000.0 +
- kids.ru_utime.tv_sec + kids.ru_utime.tv_usec/1000000.0;
- sys = (double) me.ru_stime.tv_sec + me.ru_stime.tv_usec/1000000.0 +
- kids.ru_stime.tv_sec + kids.ru_stime.tv_usec/1000000.0;
- #endif /* not USG */
- if (grps_acsd)
- syslog(LOG_INFO, "%s exit %d articles %d groups",
- hostname, arts_acsd, grps_acsd);
- if (nn_told)
- syslog(LOG_INFO, "%s newnews_stats told %d took %d",
- hostname, nn_told, nn_took);
- if (ih_accepted || ih_rejected || ih_failed)
- syslog(LOG_INFO,
- "%s ihave_stats accepted %d rejected %d failed %d",
- hostname,
- ih_accepted,
- ih_rejected,
- ih_failed);
- (void) sprintf(buf, "user %.3f system %.3f elapsed %.3f",
- user, sys, Tfinish - Tstart);
- syslog(LOG_INFO, "%s times %s", hostname, buf);
- }
- #endif LOG
-