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