1: /* 2: ** Sendmail 3: ** Copyright (c) 1983 Eric P. Allman 4: ** Berkeley, California 5: ** 6: ** Copyright (c) 1983 Regents of the University of California. 7: ** All rights reserved. The Berkeley software License Agreement 8: ** specifies the terms and conditions for redistribution. 9: */ 10: 11: 12: # include <errno.h> 13: # include "sendmail.h" 14: 15: # ifndef DAEMON 16: # ifndef lint 17: static char SccsId[] = "@(#)daemon.c 5.19 (Berkeley) 5/6/86 (w/o daemon mode)"; 18: # endif not lint 19: # else 20: 21: # include <netdb.h> 22: # include <sys/signal.h> 23: # include <sys/wait.h> 24: # include <sys/time.h> 25: # include <sys/resource.h> 26: 27: # ifndef lint 28: static char SccsId[] = "@(#)daemon.c 5.19 (Berkeley) 5/6/86 (with daemon mode)"; 29: # endif not lint 30: 31: /* 32: ** DAEMON.C -- routines to use when running as a daemon. 33: ** 34: ** This entire file is highly dependent on the 4.2 BSD 35: ** interprocess communication primitives. No attempt has 36: ** been made to make this file portable to Version 7, 37: ** Version 6, MPX files, etc. If you should try such a 38: ** thing yourself, I recommend chucking the entire file 39: ** and starting from scratch. Basic semantics are: 40: ** 41: ** getrequests() 42: ** Opens a port and initiates a connection. 43: ** Returns in a child. Must set InChannel and 44: ** OutChannel appropriately. 45: ** clrdaemon() 46: ** Close any open files associated with getting 47: ** the connection; this is used when running the queue, 48: ** etc., to avoid having extra file descriptors during 49: ** the queue run and to avoid confusing the network 50: ** code (if it cares). 51: ** makeconnection(host, port, outfile, infile) 52: ** Make a connection to the named host on the given 53: ** port. Set *outfile and *infile to the files 54: ** appropriate for communication. Returns zero on 55: ** success, else an exit status describing the 56: ** error. 57: ** maphostname(hbuf, hbufsize) 58: ** Convert the entry in hbuf into a canonical form. It 59: ** may not be larger than hbufsize. 60: */ 61: /* 62: ** GETREQUESTS -- open mail IPC port and get requests. 63: ** 64: ** Parameters: 65: ** none. 66: ** 67: ** Returns: 68: ** none. 69: ** 70: ** Side Effects: 71: ** Waits until some interesting activity occurs. When 72: ** it does, a child is created to process it, and the 73: ** parent waits for completion. Return from this 74: ** routine is always in the child. The file pointers 75: ** "InChannel" and "OutChannel" should be set to point 76: ** to the communication channel. 77: */ 78: 79: struct sockaddr_in SendmailAddress;/* internet address of sendmail */ 80: 81: int DaemonSocket = -1; /* fd describing socket */ 82: char *NetName; /* name of home (local?) network */ 83: 84: getrequests() 85: { 86: int t; 87: register struct servent *sp; 88: int on = 1; 89: extern reapchild(); 90: 91: /* 92: ** Set up the address for the mailer. 93: */ 94: 95: sp = getservbyname("smtp", "tcp"); 96: if (sp == NULL) 97: { 98: syserr("server \"smtp\" unknown"); 99: goto severe; 100: } 101: SendmailAddress.sin_family = AF_INET; 102: SendmailAddress.sin_addr.s_addr = INADDR_ANY; 103: SendmailAddress.sin_port = sp->s_port; 104: 105: /* 106: ** Try to actually open the connection. 107: */ 108: 109: # ifdef DEBUG 110: if (tTd(15, 1)) 111: printf("getrequests: port 0x%x\n", SendmailAddress.sin_port); 112: # endif DEBUG 113: 114: /* get a socket for the SMTP connection */ 115: DaemonSocket = socket(AF_INET, SOCK_STREAM, 0); 116: if (DaemonSocket < 0) 117: { 118: /* probably another daemon already */ 119: syserr("getrequests: can't create socket"); 120: severe: 121: # ifdef LOG 122: if (LogLevel > 0) 123: syslog(LOG_ALERT, "cannot get connection"); 124: # endif LOG 125: finis(); 126: } 127: 128: #ifdef DEBUG 129: /* turn on network debugging? */ 130: if (tTd(15, 15)) 131: (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on); 132: #endif DEBUG 133: 134: (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on); 135: (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof on); 136: 137: if (bind(DaemonSocket, &SendmailAddress, sizeof SendmailAddress) < 0) 138: { 139: syserr("getrequests: cannot bind"); 140: (void) close(DaemonSocket); 141: goto severe; 142: } 143: if (listen(DaemonSocket, 10) < 0) 144: { 145: syserr("getrequests: cannot listen"); 146: (void) close(DaemonSocket); 147: goto severe; 148: } 149: 150: (void) signal(SIGCHLD, reapchild); 151: 152: # ifdef DEBUG 153: if (tTd(15, 1)) 154: printf("getrequests: %d\n", DaemonSocket); 155: # endif DEBUG 156: 157: for (;;) 158: { 159: register int pid; 160: auto int lotherend; 161: struct sockaddr_in otherend; 162: extern int RefuseLA; 163: 164: /* see if we are rejecting connections */ 165: while (getla() > RefuseLA) 166: sleep(5); 167: 168: /* wait for a connection */ 169: do 170: { 171: errno = 0; 172: lotherend = sizeof otherend; 173: t = accept(DaemonSocket, &otherend, &lotherend); 174: } while (t < 0 && errno == EINTR); 175: if (t < 0) 176: { 177: syserr("getrequests: accept"); 178: sleep(5); 179: continue; 180: } 181: 182: /* 183: ** Create a subprocess to process the mail. 184: */ 185: 186: # ifdef DEBUG 187: if (tTd(15, 2)) 188: printf("getrequests: forking (fd = %d)\n", t); 189: # endif DEBUG 190: 191: pid = fork(); 192: if (pid < 0) 193: { 194: syserr("daemon: cannot fork"); 195: sleep(10); 196: (void) close(t); 197: continue; 198: } 199: 200: if (pid == 0) 201: { 202: extern struct hostent *gethostbyaddr(); 203: register struct hostent *hp; 204: char buf[MAXNAME]; 205: 206: /* 207: ** CHILD -- return to caller. 208: ** Collect verified idea of sending host. 209: ** Verify calling user id if possible here. 210: */ 211: 212: (void) signal(SIGCHLD, SIG_DFL); 213: 214: /* determine host name */ 215: hp = gethostbyaddr((char *) &otherend.sin_addr, sizeof otherend.sin_addr, AF_INET); 216: if (hp != NULL) 217: { 218: (void) strcpy(buf, hp->h_name); 219: if (NetName != NULL && NetName[0] != '\0' && 220: index(hp->h_name, '.') == NULL) 221: { 222: (void) strcat(buf, "."); 223: (void) strcat(buf, NetName); 224: } 225: } 226: else 227: { 228: extern char *inet_ntoa(); 229: 230: /* produce a dotted quad */ 231: (void) sprintf(buf, "[%s]", 232: inet_ntoa(otherend.sin_addr)); 233: } 234: 235: /* should we check for illegal connection here? XXX */ 236: 237: RealHostName = newstr(buf); 238: 239: (void) close(DaemonSocket); 240: InChannel = fdopen(t, "r"); 241: OutChannel = fdopen(dup(t), "w"); 242: # ifdef DEBUG 243: if (tTd(15, 2)) 244: printf("getreq: returning\n"); 245: # endif DEBUG 246: # ifdef LOG 247: if (LogLevel > 11) 248: syslog(LOG_DEBUG, "connected, pid=%d", getpid()); 249: # endif LOG 250: return; 251: } 252: 253: /* close the port so that others will hang (for a while) */ 254: (void) close(t); 255: } 256: /*NOTREACHED*/ 257: } 258: /* 259: ** CLRDAEMON -- reset the daemon connection 260: ** 261: ** Parameters: 262: ** none. 263: ** 264: ** Returns: 265: ** none. 266: ** 267: ** Side Effects: 268: ** releases any resources used by the passive daemon. 269: */ 270: 271: clrdaemon() 272: { 273: if (DaemonSocket >= 0) 274: (void) close(DaemonSocket); 275: DaemonSocket = -1; 276: } 277: /* 278: ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 279: ** 280: ** Parameters: 281: ** host -- the name of the host. 282: ** port -- the port number to connect to. 283: ** outfile -- a pointer to a place to put the outfile 284: ** descriptor. 285: ** infile -- ditto for infile. 286: ** 287: ** Returns: 288: ** An exit code telling whether the connection could be 289: ** made and if not why not. 290: ** 291: ** Side Effects: 292: ** none. 293: */ 294: 295: int h_errno; /*this will go away when code implemented*/ 296: 297: makeconnection(host, port, outfile, infile) 298: char *host; 299: u_short port; 300: FILE **outfile; 301: FILE **infile; 302: { 303: register int s; 304: int sav_errno; 305: 306: /* 307: ** Set up the address for the mailer. 308: ** Accept "[a.b.c.d]" syntax for host name. 309: */ 310: 311: h_errno = 0; 312: errno = 0; 313: 314: if (host[0] == '[') 315: { 316: long hid; 317: register char *p = index(host, ']'); 318: 319: if (p != NULL) 320: { 321: *p = '\0'; 322: hid = inet_addr(&host[1]); 323: *p = ']'; 324: } 325: if (p == NULL || hid == -1) 326: { 327: usrerr("Invalid numeric domain spec \"%s\"", host); 328: return (EX_NOHOST); 329: } 330: SendmailAddress.sin_addr.s_addr = hid; 331: } 332: else 333: { 334: register struct hostent *hp = gethostbyname(host); 335: 336: if (hp == NULL) 337: { 338: if (errno == ETIMEDOUT || h_errno == TRY_AGAIN) 339: return (EX_TEMPFAIL); 340: 341: /* 342: ** XXX Should look for mail forwarder record here 343: ** XXX if (h_errno == NO_ADDRESS). 344: */ 345: 346: return (EX_NOHOST); 347: } 348: bcopy(hp->h_addr, (char *) &SendmailAddress.sin_addr, hp->h_length); 349: } 350: 351: /* 352: ** Determine the port number. 353: */ 354: 355: if (port != 0) 356: SendmailAddress.sin_port = htons(port); 357: else 358: { 359: register struct servent *sp = getservbyname("smtp", "tcp"); 360: 361: if (sp == NULL) 362: { 363: syserr("makeconnection: server \"smtp\" unknown"); 364: return (EX_OSFILE); 365: } 366: SendmailAddress.sin_port = sp->s_port; 367: } 368: 369: /* 370: ** Try to actually open the connection. 371: */ 372: 373: # ifdef DEBUG 374: if (tTd(16, 1)) 375: printf("makeconnection (%s)\n", host); 376: # endif DEBUG 377: 378: s = socket(AF_INET, SOCK_STREAM, 0); 379: if (s < 0) 380: { 381: syserr("makeconnection: no socket"); 382: sav_errno = errno; 383: goto failure; 384: } 385: 386: # ifdef DEBUG 387: if (tTd(16, 1)) 388: printf("makeconnection: %d\n", s); 389: 390: /* turn on network debugging? */ 391: if (tTd(16, 14)) 392: { 393: int on = 1; 394: (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on); 395: } 396: # endif DEBUG 397: (void) fflush(CurEnv->e_xfp); /* for debugging */ 398: errno = 0; /* for debugging */ 399: SendmailAddress.sin_family = AF_INET; 400: if (connect(s, &SendmailAddress, sizeof SendmailAddress) < 0) 401: { 402: sav_errno = errno; 403: (void) close(s); 404: /* failure, decide if temporary or not */ 405: failure: 406: switch (sav_errno) 407: { 408: case EISCONN: 409: case ETIMEDOUT: 410: case EINPROGRESS: 411: case EALREADY: 412: case EADDRINUSE: 413: case EHOSTDOWN: 414: case ENETDOWN: 415: case ENETRESET: 416: case ENOBUFS: 417: case ECONNREFUSED: 418: case ECONNRESET: 419: case EHOSTUNREACH: 420: case ENETUNREACH: 421: /* there are others, I'm sure..... */ 422: return (EX_TEMPFAIL); 423: 424: case EPERM: 425: /* why is this happening? */ 426: syserr("makeconnection: funny failure, addr=%lx, port=%x", 427: SendmailAddress.sin_addr.s_addr, SendmailAddress.sin_port); 428: return (EX_TEMPFAIL); 429: 430: default: 431: return (EX_UNAVAILABLE); 432: } 433: } 434: 435: /* connection ok, put it into canonical form */ 436: *outfile = fdopen(s, "w"); 437: *infile = fdopen(s, "r"); 438: 439: return (EX_OK); 440: } 441: /* 442: ** MYHOSTNAME -- return the name of this host. 443: ** 444: ** Parameters: 445: ** hostbuf -- a place to return the name of this host. 446: ** size -- the size of hostbuf. 447: ** 448: ** Returns: 449: ** A list of aliases for this host. 450: ** 451: ** Side Effects: 452: ** none. 453: */ 454: 455: char ** 456: myhostname(hostbuf, size) 457: char hostbuf[]; 458: int size; 459: { 460: extern struct hostent *gethostbyname(); 461: struct hostent *hp; 462: 463: if (gethostname(hostbuf, size) < 0) 464: { 465: (void) strcpy(hostbuf, "localhost"); 466: } 467: hp = gethostbyname(hostbuf); 468: if (hp != NULL) 469: { 470: (void) strcpy(hostbuf, hp->h_name); 471: return (hp->h_aliases); 472: } 473: else 474: return (NULL); 475: } 476: /* 477: ** MAPHOSTNAME -- turn a hostname into canonical form 478: ** 479: ** Parameters: 480: ** hbuf -- a buffer containing a hostname. 481: ** hbsize -- the size of hbuf. 482: ** 483: ** Returns: 484: ** none. 485: ** 486: ** Side Effects: 487: ** Looks up the host specified in hbuf. If it is not 488: ** the canonical name for that host, replace it with 489: ** the canonical name. If the name is unknown, or it 490: ** is already the canonical name, leave it unchanged. 491: */ 492: 493: maphostname(hbuf, hbsize) 494: char *hbuf; 495: int hbsize; 496: { 497: register struct hostent *hp; 498: extern struct hostent *gethostbyname(); 499: 500: /* 501: ** If first character is a bracket, then it is an address 502: ** lookup. Address is copied into a temporary buffer to 503: ** strip the brackets and to preserve hbuf if address is 504: ** unknown. 505: */ 506: 507: if (*hbuf == '[') 508: { 509: extern struct hostent *gethostbyaddr(); 510: u_long in_addr; 511: char ptr[256]; 512: char *bptr; 513: 514: (void) strcpy(ptr, hbuf); 515: bptr = index(ptr,']'); 516: *bptr = '\0'; 517: in_addr = inet_addr(&ptr[1]); 518: hp = gethostbyaddr((char *) &in_addr, sizeof(struct in_addr), AF_INET); 519: if (hp == NULL) 520: return; 521: } 522: else 523: { 524: makelower(hbuf); 525: hp = gethostbyname(hbuf); 526: } 527: if (hp != NULL) 528: { 529: int i = strlen(hp->h_name); 530: 531: if (i >= hbsize) 532: hp->h_name[--i] = '\0'; 533: (void) strcpy(hbuf, hp->h_name); 534: } 535: } 536: 537: # else DAEMON 538: /* code for systems without sophisticated networking */ 539: 540: /* 541: ** MYHOSTNAME -- stub version for case of no daemon code. 542: ** 543: ** Can't convert to upper case here because might be a UUCP name. 544: ** 545: ** Mark, you can change this to be anything you want...... 546: */ 547: 548: char ** 549: myhostname(hostbuf, size) 550: char hostbuf[]; 551: int size; 552: { 553: register FILE *f; 554: 555: hostbuf[0] = '\0'; 556: f = fopen("/usr/include/whoami", "r"); 557: if (f != NULL) 558: { 559: (void) fgets(hostbuf, size, f); 560: fixcrlf(hostbuf, TRUE); 561: (void) fclose(f); 562: } 563: return (NULL); 564: } 565: /* 566: ** MAPHOSTNAME -- turn a hostname into canonical form 567: ** 568: ** Parameters: 569: ** hbuf -- a buffer containing a hostname. 570: ** hbsize -- the size of hbuf. 571: ** 572: ** Returns: 573: ** none. 574: ** 575: ** Side Effects: 576: ** Looks up the host specified in hbuf. If it is not 577: ** the canonical name for that host, replace it with 578: ** the canonical name. If the name is unknown, or it 579: ** is already the canonical name, leave it unchanged. 580: */ 581: 582: /*ARGSUSED*/ 583: maphostname(hbuf, hbsize) 584: char *hbuf; 585: int hbsize; 586: { 587: return; 588: } 589: 590: #endif DAEMON