1: # include <errno.h> 2: # include "sendmail.h" 3: 4: #ifndef DAEMON 5: SCCSID(@(#)daemon.c 4.4 8/28/83 (w/o daemon mode)); 6: #else 7: 8: #include <sys/socket.h> 9: #include <netinet/in.h> 10: #include <netdb.h> 11: #include <sys/wait.h> 12: 13: SCCSID(@(#)daemon.c 4.4 8/28/83 (with daemon mode)); 14: 15: /* 16: ** DAEMON.C -- routines to use when running as a daemon. 17: ** 18: ** This entire file is highly dependent on the 4.2 BSD 19: ** interprocess communication primitives. No attempt has 20: ** been made to make this file portable to Version 7, 21: ** Version 6, MPX files, etc. If you should try such a 22: ** thing yourself, I recommend chucking the entire file 23: ** and starting from scratch. Basic semantics are: 24: ** 25: ** getrequests() 26: ** Opens a port and initiates a connection. 27: ** Returns in a child. Must set InChannel and 28: ** OutChannel appropriately. 29: ** clrdaemon() 30: ** Close any open files associated with getting 31: ** the connection; this is used when running the queue, 32: ** etc., to avoid having extra file descriptors during 33: ** the queue run and to avoid confusing the network 34: ** code (if it cares). 35: ** makeconnection(host, port, outfile, infile) 36: ** Make a connection to the named host on the given 37: ** port. Set *outfile and *infile to the files 38: ** appropriate for communication. Returns zero on 39: ** success, else an exit status describing the 40: ** error. 41: ** 42: ** The semantics of both of these should be clean. 43: */ 44: /* 45: ** GETREQUESTS -- open mail IPC port and get requests. 46: ** 47: ** Parameters: 48: ** none. 49: ** 50: ** Returns: 51: ** none. 52: ** 53: ** Side Effects: 54: ** Waits until some interesting activity occurs. When 55: ** it does, a child is created to process it, and the 56: ** parent waits for completion. Return from this 57: ** routine is always in the child. The file pointers 58: ** "InChannel" and "OutChannel" should be set to point 59: ** to the communication channel. 60: */ 61: 62: struct sockaddr_in SendmailAddress;/* internet address of sendmail */ 63: int DaemonSocket = -1; /* fd describing socket */ 64: 65: getrequests() 66: { 67: int t; 68: union wait status; 69: register struct servent *sp; 70: 71: /* 72: ** Set up the address for the mailer. 73: */ 74: 75: sp = getservbyname("smtp", "tcp"); 76: if (sp == NULL) 77: { 78: syserr("server \"smtp\" unknown"); 79: goto severe; 80: } 81: SendmailAddress.sin_family = AF_INET; 82: SendmailAddress.sin_addr.s_addr = INADDR_ANY; 83: SendmailAddress.sin_port = sp->s_port; 84: 85: /* 86: ** Try to actually open the connection. 87: */ 88: 89: # ifdef DEBUG 90: if (tTd(15, 1)) 91: printf("getrequests: port 0x%x\n", SendmailAddress.sin_port); 92: # endif DEBUG 93: 94: /* get a socket for the SMTP connection */ 95: DaemonSocket = socket(AF_INET, SOCK_STREAM, 0, 0); 96: if (DaemonSocket < 0) 97: { 98: /* probably another daemon already */ 99: syserr("getrequests: can't create socket"); 100: severe: 101: # ifdef LOG 102: if (LogLevel > 0) 103: syslog(LOG_SALERT, "cannot get connection"); 104: # endif LOG 105: finis(); 106: } 107: 108: #ifdef DEBUG 109: /* turn on network debugging? */ 110: if (tTd(15, 15)) 111: (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, 0, 0); 112: #endif DEBUG 113: 114: if (bind(DaemonSocket, &SendmailAddress, sizeof SendmailAddress, 0) < 0) 115: { 116: syserr("getrequests: cannot bind"); 117: (void) close(DaemonSocket); 118: goto severe; 119: } 120: listen(DaemonSocket, 10); 121: 122: # ifdef DEBUG 123: if (tTd(15, 1)) 124: printf("getrequests: %d\n", DaemonSocket); 125: # endif DEBUG 126: 127: for (;;) 128: { 129: register int pid; 130: auto int lotherend; 131: struct sockaddr_in otherend; 132: extern int RefuseLA; 133: 134: /* see if we are rejecting connections */ 135: while (getla() > RefuseLA) 136: sleep(5); 137: 138: /* wait for a connection */ 139: do 140: { 141: errno = 0; 142: lotherend = sizeof otherend; 143: t = accept(DaemonSocket, &otherend, &lotherend, 0); 144: } while (t < 0 && errno == EINTR); 145: if (t < 0) 146: { 147: syserr("getrequests: accept"); 148: sleep(5); 149: continue; 150: } 151: 152: /* 153: ** Create a subprocess to process the mail. 154: */ 155: 156: # ifdef DEBUG 157: if (tTd(15, 2)) 158: printf("getrequests: forking (fd = %d)\n", t); 159: # endif DEBUG 160: 161: pid = fork(); 162: if (pid < 0) 163: { 164: syserr("daemon: cannot fork"); 165: sleep(10); 166: (void) close(t); 167: continue; 168: } 169: 170: if (pid == 0) 171: { 172: extern struct hostent *gethostbyaddr(); 173: register struct hostent *hp; 174: extern char *RealHostName; /* srvrsmtp.c */ 175: char buf[MAXNAME]; 176: 177: /* 178: ** CHILD -- return to caller. 179: ** Collect verified idea of sending host. 180: ** Verify calling user id if possible here. 181: */ 182: 183: /* determine host name */ 184: hp = gethostbyaddr(&otherend.sin_addr, sizeof otherend.sin_addr, AF_INET); 185: if (hp != NULL) 186: (void) sprintf(buf, "%s.ARPA", hp->h_name); 187: else 188: /* this should produce a dotted quad */ 189: (void) sprintf(buf, "%lx", otherend.sin_addr.s_addr); 190: RealHostName = newstr(buf); 191: 192: (void) close(DaemonSocket); 193: InChannel = fdopen(t, "r"); 194: OutChannel = fdopen(t, "w"); 195: # ifdef DEBUG 196: if (tTd(15, 2)) 197: printf("getreq: returning\n"); 198: # endif DEBUG 199: # ifdef LOG 200: if (LogLevel > 11) 201: syslog(LOG_DEBUG, "connected, pid=%d", getpid()); 202: # endif LOG 203: return; 204: } 205: 206: /* 207: ** PARENT -- wait for child to terminate. 208: ** Perhaps we should allow concurrent processing? 209: */ 210: 211: # ifdef DEBUG 212: if (tTd(15, 2)) 213: { 214: sleep(2); 215: printf("getreq: parent waiting\n"); 216: } 217: # endif DEBUG 218: 219: /* close the port so that others will hang (for a while) */ 220: (void) close(t); 221: 222: /* pick up old zombies */ 223: while (wait3(&status, WNOHANG, 0) > 0) 224: continue; 225: } 226: /*NOTREACHED*/ 227: } 228: /* 229: ** CLRDAEMON -- reset the daemon connection 230: ** 231: ** Parameters: 232: ** none. 233: ** 234: ** Returns: 235: ** none. 236: ** 237: ** Side Effects: 238: ** releases any resources used by the passive daemon. 239: */ 240: 241: clrdaemon() 242: { 243: if (DaemonSocket >= 0) 244: (void) close(DaemonSocket); 245: DaemonSocket = -1; 246: } 247: /* 248: ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 249: ** 250: ** Parameters: 251: ** host -- the name of the host. 252: ** port -- the port number to connect to. 253: ** outfile -- a pointer to a place to put the outfile 254: ** descriptor. 255: ** infile -- ditto for infile. 256: ** 257: ** Returns: 258: ** An exit code telling whether the connection could be 259: ** made and if not why not. 260: ** 261: ** Side Effects: 262: ** none. 263: */ 264: 265: makeconnection(host, port, outfile, infile) 266: char *host; 267: u_short port; 268: FILE **outfile; 269: FILE **infile; 270: { 271: register int s; 272: 273: /* 274: ** Set up the address for the mailer. 275: ** Accept "[a.b.c.d]" syntax for host name. 276: */ 277: 278: if (host[0] == '[') 279: { 280: long hid; 281: register char *p = index(host, ']'); 282: 283: if (p != NULL) 284: { 285: *p = '\0'; 286: hid = inet_addr(&host[1]); 287: *p = ']'; 288: } 289: if (p == NULL || hid == -1) 290: { 291: usrerr("Invalid numeric domain spec \"%s\"", host); 292: return (EX_NOHOST); 293: } 294: SendmailAddress.sin_addr.s_addr = hid; 295: } 296: else 297: { 298: register struct hostent *hp = gethostbyname(host); 299: 300: if (hp == NULL) 301: return (EX_NOHOST); 302: bmove(hp->h_addr, (char *) &SendmailAddress.sin_addr, hp->h_length); 303: } 304: 305: /* 306: ** Determine the port number. 307: */ 308: 309: if (port != 0) 310: SendmailAddress.sin_port = htons(port); 311: else 312: { 313: register struct servent *sp = getservbyname("smtp", "tcp"); 314: 315: if (sp == NULL) 316: { 317: syserr("makeconnection: server \"smtp\" unknown"); 318: return (EX_OSFILE); 319: } 320: SendmailAddress.sin_port = sp->s_port; 321: } 322: 323: /* 324: ** Try to actually open the connection. 325: */ 326: 327: # ifdef DEBUG 328: if (tTd(16, 1)) 329: printf("makeconnection (%s)\n", host); 330: # endif DEBUG 331: 332: s = socket(AF_INET, SOCK_STREAM, 0, 0); 333: if (s < 0) 334: { 335: syserr("makeconnection: no socket"); 336: goto failure; 337: } 338: 339: # ifdef DEBUG 340: if (tTd(16, 1)) 341: printf("makeconnection: %d\n", s); 342: 343: /* turn on network debugging? */ 344: if (tTd(16, 14)) 345: (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 0, 0); 346: # endif DEBUG 347: (void) fflush(CurEnv->e_xfp); /* for debugging */ 348: errno = 0; /* for debugging */ 349: SendmailAddress.sin_family = AF_INET; 350: if (connect(s, &SendmailAddress, sizeof SendmailAddress, 0) < 0) 351: { 352: /* failure, decide if temporary or not */ 353: failure: 354: switch (errno) 355: { 356: case EISCONN: 357: case ETIMEDOUT: 358: case EINPROGRESS: 359: case EALREADY: 360: case EADDRINUSE: 361: case EHOSTDOWN: 362: case ENETDOWN: 363: case ENETRESET: 364: case ENOBUFS: 365: case ECONNREFUSED: 366: case ECONNRESET: 367: case EHOSTUNREACH: 368: case ENETUNREACH: 369: /* there are others, I'm sure..... */ 370: return (EX_TEMPFAIL); 371: 372: case EPERM: 373: /* why is this happening? */ 374: syserr("makeconnection: funny failure, addr=%lx, port=%x", 375: SendmailAddress.sin_addr.s_addr, SendmailAddress.sin_port); 376: return (EX_TEMPFAIL); 377: 378: default: 379: return (EX_UNAVAILABLE); 380: } 381: } 382: 383: /* connection ok, put it into canonical form */ 384: *outfile = fdopen(s, "w"); 385: *infile = fdopen(s, "r"); 386: 387: return (EX_OK); 388: } 389: /* 390: ** MYHOSTNAME -- return the name of this host. 391: ** 392: ** Parameters: 393: ** hostbuf -- a place to return the name of this host. 394: ** size -- the size of hostbuf. 395: ** 396: ** Returns: 397: ** A list of aliases for this host. 398: ** 399: ** Side Effects: 400: ** none. 401: */ 402: 403: char ** 404: myhostname(hostbuf, size) 405: char hostbuf[]; 406: int size; 407: { 408: extern struct hostent *gethostbyname(); 409: struct hostent *hp; 410: auto int i = size; 411: 412: gethostname(hostbuf, &i); 413: hp = gethostbyname(hostbuf); 414: if (hp != NULL) 415: return (hp->h_aliases); 416: else 417: return (NULL); 418: } 419: 420: # else DAEMON 421: 422: /* 423: ** MYHOSTNAME -- stub version for case of no daemon code. 424: ** 425: ** Can't convert to upper case here because might be a UUCP name. 426: ** 427: ** Mark, you can change this to be anything you want...... 428: */ 429: 430: char ** 431: myhostname(hostbuf, size) 432: char hostbuf[]; 433: int size; 434: { 435: register FILE *f; 436: 437: hostbuf[0] = '\0'; 438: f = fopen("/usr/include/whoami", "r"); 439: if (f != NULL) 440: { 441: (void) fgets(hostbuf, size, f); 442: fixcrlf(hostbuf, TRUE); 443: (void) fclose(f); 444: } 445: return (NULL); 446: } 447: 448: #endif DAEMON