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