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