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

Defined functions

clrdaemon defined in line 271; used 1 times
getrequests defined in line 84; used 1 times
makeconnection defined in line 297; used 2 times
maphostname defined in line 583; used 1 times
myhostname defined in line 548; used 2 times

Defined variables

DaemonSocket defined in line 81; used 16 times
NetName defined in line 82; used 4 times
SccsId defined in line 28; never used
SendmailAddress defined in line 79; used 15 times
h_errno defined in line 295; used 2 times
Last modified: 1986-05-07
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2014
Valid CSS Valid XHTML 1.0 Strict