Added all of the MH sources, including RCS files, in
[mmh] / docs / historical / mh-6.8.5 / support / pop / popd.c
1 /* popd.c - the POP server */
2 #ifndef lint
3 static char ident[] = "@(#)$Id: popd.c,v 1.16 1993/08/25 17:23:05 jromine Exp $";
4 #endif  /* lint */
5
6 /* Author:      Marshall T. Rose        <MRose@UDel>    (MTR)
7                 Department of Computer Science and Information Sciences
8                 University of Delaware
9                 Newark, DE  19716
10                 302/451-1951
11
12    Date:        Sun Oct 28 16:23:26 1984
13  */
14
15 #include <errno.h>
16 #include <signal.h>
17 #include <stdio.h>
18 #include "../h/strings.h"
19 #include "syslog.h"
20 #include <sys/types.h>
21 #include <sys/file.h>
22 #ifndef NOIOCTLH
23 #include <sys/ioctl.h>
24 #endif
25 #include <sys/socket.h>
26 #include <sys/time.h>
27 #ifdef  SIGTSTP
28 #include <sys/resource.h>
29 #include <sys/wait.h>
30 #endif
31 #include <netinet/in.h>
32 #include <netdb.h>
33 #include <arpa/inet.h>
34 #ifdef KPOP
35 #include <krb.h>
36
37 static Key_schedule schedule;
38 static KTEXT_ST ticket;
39 static AUTH_DAT kdata;
40 #endif
41 #ifdef  SYS5
42 #include <fcntl.h>
43 #endif
44
45
46 #ifdef  SYS5
47 #define u_short ushort
48 #endif
49
50 #define NOTOK   (-1)
51 #define OK      0
52
53 #define NULLCP  ((char *) 0)
54 #define NULLRP  ((struct rusage *) 0)
55
56 #define FAST                    /* fast start-up of BBoards */
57
58 /* \f */
59
60 extern int  errno;
61 #ifndef BSD44
62 extern int  sys_nerr;
63 extern char *sys_errlist[];
64 extern char *sys_siglist[];
65 #endif
66
67
68 int  debug = 0;
69 static int  nbits = ((sizeof (int)) * 8);
70 static int  options = 0;
71
72 #ifndef POPSERVICE
73 #define POPSERVICE      "pop"
74 #endif
75
76 char *myname = "popd";
77 char myhost[BUFSIZ];
78 static char *myprotocol = "tcp";
79 static char *myservice = POPSERVICE;
80
81 static struct sockaddr_in   in_socket;
82 static struct sockaddr_in  *isock = &in_socket;
83
84 #ifdef KPOP
85 static AUTH_DAT kdata;
86 #endif
87
88 static TYPESIG  chldser ();
89 void    padios (), padvise ();
90
91 static  server(), arginit(), envinit();
92 /* \f */
93
94 /* ARGSUSED */
95
96 main (argc, argv, envp)
97 int     argc;
98 char  **argv,
99       **envp;
100 {
101 #ifdef KPOP
102     int     i;
103 #else
104     int     fd,
105             sd;
106     int     on = 1;
107     struct servent *sp;
108     struct sockaddr_in  out_socket,
109                        *osock = &out_socket;
110 #endif
111
112 #ifdef KPOP
113     i = sizeof(in_socket);
114     if (getpeername(0, &in_socket, &i) < 0)
115       padios("getpeername", "bad status");
116 #else
117     if ((sp = getservbyname (myservice, myprotocol)) == NULL)
118         padios (NULLCP, "%s/%s: unknown service", myprotocol, myservice);
119     isock -> sin_family = AF_INET;
120     isock -> sin_port = sp -> s_port;
121     isock -> sin_addr.s_addr = INADDR_ANY;
122 #endif
123     arginit (argv);
124     envinit ();
125
126 #ifndef KPOP
127 #ifdef  RESTART
128     for (;;) {
129         char    reason[BUFSIZ];
130 #if defined(BSD42) && !defined(WAITINT)
131         union wait status;
132 #else
133         int status;
134 #endif
135
136         switch (fork ()) {
137             case NOTOK: 
138                 sleep (5);
139                 continue;
140
141             case OK: 
142                 break;
143
144             default: 
145                 sleep (60);
146                 (void) wait3 (&status, 0, NULLRP);
147                 if (WIFEXITED (status))
148                     (void) sprintf (reason, "exit=0%o", status.w_retcode);
149                 else
150                     if (WIFSIGNALED (status))
151                         (void) sprintf (reason, "signal=%s%s",
152                                 status.w_termsig < NSIG
153                                 ? sys_siglist[status.w_termsig] : "unknown",
154                                 status.w_coredump ? " (core dumped)" : NULL);
155                     else
156                         (void) strcpy (reason, "stopped(!!)");
157                 padvise (NULLCP, LOG_WARNING, "%s/%s server has terminated -- %s",
158                         sp -> s_proto, sp -> s_name, reason);
159                 continue;
160         }
161         break;
162     }
163
164     closelog ();
165 #ifndef BSD43
166     openlog (myname, LOG_PID);
167 #else   /* BSD43 */
168     openlog (myname, LOG_PID, LOG_DAEMON);
169 #endif  /* BSD43 */
170     padvise (NULLCP, LOG_INFO, "restart");
171 #endif  /* RESTART */
172
173 /* \f */
174
175     if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == NOTOK)
176         padios ("socket", "unable to create");
177 #ifndef BSD43
178     if (options & SO_DEBUG)
179         if (setsockopt (sd, SOL_SOCKET, SO_DEBUG, NULL, 0) == NOTOK)
180             padvise ("SO_DEBUG", LOG_WARNING, "unable to set socket option");
181     if (setsockopt (sd, SOL_SOCKET, SO_KEEPALIVE, NULL, 0) == NOTOK)
182         padvise ("SO_KEEPALIVE", LOG_WARNING, "unable to set socket option");
183 #else   /* BSD43 */
184     if (options & SO_DEBUG)
185         if (setsockopt (sd, SOL_SOCKET, SO_DEBUG, &on, sizeof on) == NOTOK)
186             padvise ("SO_DEBUG", LOG_WARNING, "unable to set socket option");
187     if (setsockopt (sd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof on) == NOTOK)
188         padvise ("SO_KEEPALIVE", LOG_WARNING, "unable to set socket option");
189 #endif  /* BSD43 */
190     if (bind (sd, (struct sockaddr *) isock, sizeof *isock) == NOTOK)
191         padios ("socket", "unable to bind");
192
193 #ifdef  SIGCHLD
194     (void) signal (SIGCHLD, chldser);
195 #endif  /* SIGCHLD */
196     (void) listen (sd, SOMAXCONN);
197 #endif /* KPOP */
198 #ifdef  FAST
199     popinit ();
200 #endif  /* FAST */
201 #ifndef KPOP
202     for (;;) {
203         int     i = sizeof *osock;
204
205         if ((fd = accept (sd, (struct sockaddr *) osock, &i)) == NOTOK) {
206             if (errno != EINTR)
207                 padvise ("socket", LOG_WARNING,
208                     "unable to accept connection on");
209             continue;
210         }
211 #endif
212 #ifdef  FAST
213         popassert ();
214 #endif  /* FAST */
215 #ifndef KPOP
216         switch (fork ()) {
217             case OK: 
218                 (void) close (sd);
219 #ifdef  SIGCHLD
220                 (void) signal (SIGCHLD, SIG_DFL);
221 #endif  /* SIGCHLD */
222                 server (fd, osock);
223                 _exit (0);
224
225             case NOTOK: 
226                 padvise ("socket", LOG_WARNING,
227                     "no forks, so rejecting connection on");
228             default: 
229                 (void) close (fd);
230         }
231     }
232 #else
233     server (0, isock);
234 #endif
235 }
236
237 /* \f */
238
239 static  server (fd, sin)
240 int     fd;
241 struct sockaddr_in *sin;
242 {
243     u_short port;
244     struct hostent *hp;
245     struct in_addr *addr;
246 #ifdef KPOP
247     int auth;
248     int sin_len;
249     struct sockaddr_in faddr;
250     char instance[INST_SZ];
251     char version[9];
252     char user[ANAME_SZ];
253 #endif
254
255     closelog ();
256 #ifndef BSD43
257     openlog (myname, LOG_PID);
258 #else   /* BSD43 */
259     openlog (myname, LOG_PID, LOG_DAEMON);
260 #endif  /* BSD43 */
261     port = ntohs (sin -> sin_port);
262     addr = &sin -> sin_addr;
263     hp = gethostbyaddr ((char *)addr, sizeof *addr, sin -> sin_family);
264     padvise (NULLCP, LOG_INFO, "servicing %s/%d",
265             hp ? hp -> h_name : inet_ntoa (*addr), port);
266     if (fd != 0)
267       {
268         (void) dup2 (fd, 0);
269         (void) close (fd);
270       }
271     (void) dup2 (0, 1);
272
273 #ifdef KPOP
274     sin_len = sizeof (struct sockaddr_in);
275     if (getpeername(0, &faddr, &sin_len) < 0) {
276       padvise("getpeername", LOG_INFO, "");
277       exit(1);
278     }
279     strcpy(instance, "*");
280     auth = krb_recvauth(0L, 0, &ticket, "pop", instance,
281                         &faddr, (struct sockaddr_in *)NULL,
282                         &kdata, "", schedule, version);
283     if (auth == KSUCCESS)
284       auth = krb_kntoln(&kdata, user);
285
286     if (auth != KSUCCESS) {
287       padvise(NULLCP, LOG_INFO, "bad kerberos data, not ok'ing");
288       kpop (0, 1, NULLCP, NULLCP, auth); /* respond(NOTOK, krb_err_txt[auth]); */
289     } else {
290       kpop (0, 1, user, (hp ? hp -> h_name : NULLCP), 0);
291     }
292 #else
293     pop (0, 1, sin -> sin_family == AF_INET && port < IPPORT_RESERVED && hp,
294             hp ? hp -> h_name : NULLCP);
295 #endif
296 }
297         
298 /* \f */
299
300 static  arginit (vec)
301 char    **vec;
302 {
303     int     port;
304     register char  *ap;
305     struct hostent *hp;
306
307     if (myname = rindex (*vec, '/'))
308         myname++;
309     if (myname == NULL || *myname == 0)
310         myname = *vec;
311
312     (void) gethostname (myhost, sizeof myhost);
313     if (hp = gethostbyname (myhost))
314         (void) strcpy (myhost, hp -> h_name);
315 #ifndef BSD42
316     nbits = _NFILE;
317 #else   /* BSD42 */
318     nbits = getdtablesize ();
319 #endif  /* BSD42 */
320
321     for (vec++; ap = *vec; vec++) {
322         if (*ap == '-')
323             switch (*++ap) {
324                 case 'd': 
325                     options |= SO_DEBUG;
326                     continue;
327
328                 case 'p': 
329                     if ((ap = *++vec) == NULL
330                             || *ap == '-'
331                             || (port = atoi (ap)) <= 0)
332                         padios (NULLCP, "usage: %s -p portno", myname);
333                     isock -> sin_port = htons ((u_short) port);
334                     continue;
335
336                 default: 
337                     padios (NULLCP, "-%s: unknown switch", ap);
338             }
339
340         padios (NULLCP, "usage: %s [switches]", myname);
341     }
342 }
343
344 /* \f */
345
346 static  envinit () {
347 #ifndef KPOP
348     int     i,
349             sd;
350
351     if (!(debug = isatty (2))) {
352         for (i = 0; i < 5; i++) {
353             switch (fork ()) {
354                 case NOTOK: 
355                     sleep (5);
356                     continue;
357
358                 case OK: 
359                     break;
360
361                 default: 
362                     _exit (0);
363             }
364             break;
365         }
366
367         (void) chdir ("/");
368
369         if ((sd = open ("/dev/null", O_RDWR)) == NOTOK)
370             padios ("/dev/null", "unable to read");
371         if (sd != 0)
372             (void) dup2 (sd, 0), (void) close (sd);
373         (void) dup2 (0, 1);
374         (void) dup2 (0, 2);
375
376         if ((sd = open ("/dev/tty", O_RDWR)) != NOTOK) {
377 #ifdef  TIOCNOTTY
378             (void) ioctl (sd, TIOCNOTTY, NULLCP);
379 #endif  /* TIOCNOTTY */
380             (void) close (sd);
381         }
382     }
383
384     for (sd = 3; sd < nbits; sd++)
385         (void) close (sd);
386 #endif /* KPOP */
387
388     (void) signal (SIGPIPE, SIG_IGN);
389
390 #ifndef BSD43
391     openlog (myname, LOG_PID);
392 #else   /* BSD43 */
393     openlog (myname, LOG_PID, LOG_DAEMON);
394 #endif  /* BSD43 */
395     padvise (NULLCP, LOG_INFO, "starting");
396     if (debug)
397         padvise (NULLCP, LOG_DEBUG, "options=0x%x port=%d",
398                 options, ntohs (isock -> sin_port));
399 }
400
401 /* \f */
402
403 #ifndef KPOP
404
405 /* ARGSUSED */
406
407 #ifdef  SIGCHLD
408
409 static TYPESIG chldser (sig, code, sc)
410 int     sig;
411 long    code;
412 struct sigcontext *sc;
413 {
414 #if defined(BSD42) && !defined(WAITINT)
415     union wait status;
416 #else
417     int status;
418 #endif
419
420     while (wait3 (&status, WNOHANG, NULLRP) > 0)
421         continue;
422 }
423
424 #endif /* SIGCHLD */
425 #endif /* KPOP */
426
427 /* \f */
428
429 /* VARARGS2 */
430
431 void    padios (what, fmt, a, b, c, d, e, f, g, h, i, j)
432 char   *what,
433        *fmt,
434        *a,
435        *b,
436        *c,
437        *d,
438        *e,
439        *f,
440        *g,
441        *h,
442        *i,
443        *j;
444 {
445     padvise (what, LOG_ERR, fmt, a, b, c, d, e, f, g, h, i, j);
446     _exit (1);
447 }
448
449 /* \f */
450
451 /* VARARGS3 */
452
453 void    padvise (what, code, fmt, a, b, c, d, e, f, g, h, i, j)
454 char   *what,
455        *fmt,
456        *a,
457        *b,
458        *c,
459        *d,
460        *e,
461        *f,
462        *g,
463        *h,
464        *i,
465        *j;
466 int     code;
467 {
468     int     eindex = errno;
469     char    buffer[BUFSIZ];
470
471     (void) sprintf (buffer, fmt, a, b, c, d, e, f, g, h, i, j);
472     if (what)
473         if (eindex > 0 && eindex < sys_nerr)
474             syslog (code, "%s %s: %s", buffer, what, sys_errlist[eindex]);
475         else
476             syslog (code, "%s %s: Error %d", buffer, what, eindex);
477     else
478         syslog (code, "%s", buffer);
479
480     if (debug) {
481         fprintf (stderr, "[%d] %s", code, buffer);
482         if (what)
483             (void) fputc (' ', stderr), perror (what);
484         else
485             (void) fputc ('\n', stderr);
486         (void) fflush (stderr);
487     }
488
489     errno = eindex;
490 }