|
|
1.1 ! root 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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.