1: # include <whoami.h> 2: # include <sys/types.h> 3: # include <errno.h> 4: # include "sendmail.h" 5: 6: # if pdp11 7: # define wait3(a,b,c) wait2(a,b) 8: # endif pdp11 9: 10: #ifndef DAEMON 11: SCCSID(@(#)4.1a_daemon.c 3.35+ 12/5/82 (w/o daemon mode)); 12: #else 13: 14: # include <sys/socket.h> 15: # include <netinet/in.h> 16: # include <wait.h> 17: 18: # include <netdb.h> 19: 20: SCCSID(@(#)4.1a_daemon.c 3.35+ 12/5/82 (with daemon mode)); 21: 22: /* 23: ** DAEMON.C -- routines to use when running as a daemon. 24: ** 25: ** 4.1a BSD version -- this version is not well supported. 26: ** 27: ** This entire file is highly dependent on the 4.1a BSD 28: ** interprocess communication primitives. No attempt has 29: ** been made to make this file portable to Version 7, 30: ** Version 6, MPX files, etc. If you should try such a 31: ** thing yourself, I recommend chucking the entire file 32: ** and starting from scratch. Basic semantics are: 33: ** 34: ** getrequests() 35: ** Opens a port and initiates a connection. 36: ** Returns in a child. Must set InChannel and 37: ** OutChannel appropriately. 38: ** makeconnection(host, port, outfile, infile) 39: ** Make a connection to the named host on the given 40: ** port. Set *outfile and *infile to the files 41: ** appropriate for communication. Returns zero on 42: ** success, else an exit status describing the 43: ** error. 44: ** 45: ** The semantics of both of these should be clean. 46: */ 47: /* 48: ** GETREQUESTS -- open mail IPC port and get requests. 49: ** 50: ** Parameters: 51: ** none. 52: ** 53: ** Returns: 54: ** none. 55: ** 56: ** Side Effects: 57: ** Waits until some interesting activity occurs. When 58: ** it does, a child is created to process it, and the 59: ** parent waits for completion. Return from this 60: ** routine is always in the child. 61: */ 62: 63: getrequests() 64: { 65: union wait status; 66: 67: for (;;) 68: { 69: register int pid; 70: register int port; 71: 72: /* 73: ** Wait for a connection. 74: */ 75: 76: while ((port = getconnection()) < 0) 77: { 78: # ifdef LOG 79: if (LogLevel > 0) 80: syslog(LOG_SALERT, "cannot get connection"); 81: # endif LOG 82: finis(); 83: } 84: 85: /* 86: ** Create a subprocess to process the mail. 87: */ 88: 89: # ifdef DEBUG 90: if (tTd(15, 2)) 91: printf("getrequests: forking (port = %d)\n", port); 92: # endif DEBUG 93: 94: pid = fork(); 95: if (pid < 0) 96: { 97: syserr("daemon: cannot fork"); 98: sleep(10); 99: (void) close(port); 100: continue; 101: } 102: 103: if (pid == 0) 104: { 105: /* 106: ** CHILD -- return to caller. 107: ** Verify calling user id if possible here. 108: */ 109: 110: InChannel = fdopen(port, "r"); 111: OutChannel = fdopen(port, "w"); 112: # ifdef DEBUG 113: if (tTd(15, 2)) 114: printf("getreq: returning\n"); 115: # endif DEBUG 116: # ifdef LOG 117: if (LogLevel > 11) 118: syslog(LOG_DEBUG, "connected, pid=%d", getpid()); 119: # endif LOG 120: return; 121: } 122: 123: /* 124: ** PARENT -- wait for child to terminate. 125: ** Perhaps we should allow concurrent processing? 126: */ 127: 128: # ifdef DEBUG 129: if (tTd(15, 2)) 130: { 131: sleep(2); 132: printf("getreq: parent waiting\n"); 133: } 134: # endif DEBUG 135: 136: /* close the port so that others will hang (for a while) */ 137: (void) close(port); 138: 139: /* pick up old zombies; implement load limiting */ 140: while (wait3(&status, WNOHANG, 0) > 0) 141: continue; 142: } 143: } 144: /* 145: ** GETCONNECTION -- make a connection with the outside world 146: ** 147: ** This routine is horribly contorted to try to get around a bunch 148: ** of 4.1a IPC bugs. There appears to be nothing we can do to make 149: ** it "right" -- the code to interrupt accepts just doesn't work 150: ** right. However, this is an attempt to minimize the probablity 151: ** of problems. 152: ** 153: ** Parameters: 154: ** none. 155: ** 156: ** Returns: 157: ** The port for mail traffic. 158: ** 159: ** Side Effects: 160: ** Waits for a connection. 161: */ 162: 163: #define IPPORT_PLAYPORT 3055 /* random number */ 164: 165: struct sockaddr_in SendmailAddress = { AF_INET, IPPORT_SMTP }; 166: int DaemonSocket; 167: 168: getconnection() 169: { 170: int s; 171: #ifdef NVMUNIX 172: int t; 173: #endif NVMUNIX 174: struct sockaddr otherend; 175: 176: /* 177: ** Set up the address for the mailer. 178: */ 179: 180: SendmailAddress.sin_addr.s_addr = 0; 181: SendmailAddress.sin_port = IPPORT_SMTP; 182: # ifdef DEBUG 183: if (tTd(15, 15)) 184: SendmailAddress.sin_port = IPPORT_PLAYPORT; 185: # endif DEBUG 186: SendmailAddress.sin_port = htons(SendmailAddress.sin_port); 187: 188: /* 189: ** Try to actually open the connection. 190: */ 191: 192: # ifdef DEBUG 193: if (tTd(15, 1)) 194: printf("getconnection\n"); 195: # endif DEBUG 196: 197: for (;; sleep(15)) 198: { 199: int i; 200: 201: /* get a socket for the SMTP connection */ 202: #ifdef NVMUNIX 203: s = socket(AF_INET, SOCK_STREAM, 0, 0); 204: bind(s, &SendmailAddress, sizeof SendmailAddress, 0); 205: listen(s, 10); 206: #else NVMUNIX 207: /* do loop is to avoid 4.1b kernel bug (?) */ 208: i = 60; 209: do 210: { 211: s = socket(SOCK_STREAM, 0, &SendmailAddress, SO_ACCEPTCONN); 212: if (s < 0) 213: sleep(10); 214: } while (--i > 0 && s < 0); 215: #endif NVMUNIX 216: if (s < 0) 217: { 218: /* probably another daemon already */ 219: syserr("getconnection: can't create socket"); 220: return (-1); 221: } 222: DaemonSocket = s; 223: 224: # ifdef DEBUG 225: if (tTd(15, 1)) 226: printf("getconnection: %d\n", s); 227: # endif DEBUG 228: 229: /* wait for a connection */ 230: do 231: { 232: errno = 0; 233: #ifdef NVMUNIX 234: lotherend = sizeof otherend; 235: t = accept(s, &otherend, &lotherend, 0); 236: if (t >= 0) 237: return (t); 238: #else NVMUNIX 239: if (accept(s, &otherend) >= 0) 240: return (s); 241: #endif NVMUNIX 242: } while (errno == EINTR); 243: syserr("getconnection: accept"); 244: sleep(5); 245: (void) close(s); 246: } 247: } 248: /* 249: ** CLRDAEMON -- reset the daemon connection 250: ** 251: ** Parameters: 252: ** none. 253: ** 254: ** Returns: 255: ** none. 256: ** 257: ** Side Effects: 258: ** releases any resources used by the passive daemon. 259: */ 260: 261: clrdaemon() 262: { 263: if (DaemonSocket >= 0) 264: (void) close(DaemonSocket); 265: DaemonSocket = -1; 266: } 267: /* 268: ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 269: ** 270: ** Parameters: 271: ** host -- the name of the host. 272: ** port -- the port number to connect to. 273: ** outfile -- a pointer to a place to put the outfile 274: ** descriptor. 275: ** infile -- ditto for infile. 276: ** 277: ** Returns: 278: ** An exit code telling whether the connection could be 279: ** made and if not why not. 280: ** 281: ** Side Effects: 282: ** none. 283: */ 284: 285: makeconnection(host, port, outfile, infile) 286: char *host; 287: u_short port; 288: FILE **outfile; 289: FILE **infile; 290: { 291: register int s; 292: 293: /* 294: ** Set up the address for the mailer. 295: ** Accept "[a.b.c.d]" syntax for host name. 296: */ 297: 298: if (host[0] == '[') 299: { 300: long hid = 0; 301: int i, j; 302: register char *p = host; 303: 304: for (i = 3; i >= 0 && *p != ']' && *p != '\0'; i--) 305: { 306: j = 0; 307: while (isdigit(*++p)) 308: j = j * 10 + (*p - '0'); 309: if (*p != (i == 0 ? ']' : '.') || j > 255 || j < 0) 310: break; 311: hid |= j << ((3 - i) * 8); 312: } 313: if (i >= 0 || *p != ']' || *++p != '\0') 314: { 315: usrerr("Invalid numeric domain spec \"%s\"", host); 316: return (EX_NOHOST); 317: } 318: SendmailAddress.sin_addr.s_addr = hid; 319: } 320: else 321: { 322: struct hostent *hp; 323: 324: if ((hp = gethostbyname(host)) == NULL) 325: return (EX_NOHOST); 326: SendmailAddress.sin_addr.s_addr = *((long *) hp->h_addr); 327: } 328: #ifdef notdef 329: else if ((SendmailAddress.sin_addr.s_addr = rhost(&host)) == -1) 330: return (EX_NOHOST); 331: #endif notdef 332: 333: if (port == 0) 334: port = IPPORT_SMTP; 335: SendmailAddress.sin_port = htons(port); 336: 337: /* 338: ** Try to actually open the connection. 339: */ 340: 341: # ifdef DEBUG 342: if (tTd(16, 1)) 343: printf("makeconnection (%s)\n", host); 344: # endif DEBUG 345: 346: #ifdef NVMUNIX 347: s = socket(AF_INET, SOCK_STREAM, 0, 0); 348: #else NVMUNIX 349: s = socket(SOCK_STREAM, 0, (struct sockaddr_in *) 0, 0); 350: #endif NVMUNIX 351: if (s < 0) 352: { 353: int saverr = errno; 354: 355: syserr("makeconnection: no socket"); 356: errno = saverr; 357: goto failure; 358: } 359: 360: # ifdef DEBUG 361: if (tTd(16, 1)) 362: printf("makeconnection: %d\n", s); 363: # endif DEBUG 364: (void) fflush(CurEnv->e_xfp); /* for debugging */ 365: #ifdef NVMUNIX 366: bind(s, &SendmailAddress, sizeof SendmailAddress, 0); 367: if (connect(s, &SendmailAddress, sizeof SendmailAddress, 0) < 0) 368: #else NVMUNIX 369: if (connect(s, &SendmailAddress) < 0) 370: #endif NVMUNIX 371: { 372: /* failure, decide if temporary or not */ 373: failure: 374: switch (errno) 375: { 376: case EISCONN: 377: case ETIMEDOUT: 378: case EINPROGRESS: 379: case EALREADY: 380: case EADDRINUSE: 381: case ENETDOWN: 382: case ENETRESET: 383: case ENOBUFS: 384: case ECONNREFUSED: 385: /* there are others, I'm sure..... */ 386: return (EX_TEMPFAIL); 387: 388: default: 389: return (EX_UNAVAILABLE); 390: } 391: } 392: 393: /* connection ok, put it into canonical form */ 394: *outfile = fdopen(s, "w"); 395: *infile = fdopen(s, "r"); 396: 397: return (0); 398: } 399: 400: /* 401: ** MYHOSTNAME -- return the name of this host. 402: ** 403: ** Parameters: 404: ** hostbuf -- a place to return the name of this host. 405: ** size -- the size of hostbuf. 406: ** 407: ** Returns: 408: ** A list of aliases for this host. 409: ** NULL if it can't find an alias list. 410: ** 411: ** Side Effects: 412: ** none. 413: */ 414: 415: char ** 416: myhostname(hostbuf, size) 417: char hostbuf[]; 418: int size; 419: { 420: register char *p; 421: 422: gethostname(hostbuf, size); 423: for (p = hostbuf; *p != '\0'; p++) 424: if (islower(*p)) 425: *p -= 'a' - 'A'; 426: 427: /* now where would we find an alias list? */ 428: return (NULL); 429: } 430: 431: # else DAEMON 432: 433: /* 434: ** MYHOSTNAME -- stub version for case of no daemon code. 435: ** 436: ** Can't convert to upper case here because might be a UUCP name. 437: */ 438: 439: char ** 440: myhostname(hostbuf, size) 441: char hostbuf[]; 442: int size; 443: { 444: register FILE *f; 445: 446: hostbuf[0] = '\0'; 447: f = fopen("/usr/include/whoami", "r"); 448: if (f != NULL) 449: { 450: (void) fgets(hostbuf, size, f); 451: fixcrlf(hostbuf, TRUE); 452: (void) fclose(f); 453: } 454: return (NULL); 455: } 456: 457: #endif DAEMON