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