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

Defined functions

clrdaemon defined in line 270; used 1 times
getrequests defined in line 83; used 1 times
makeconnection defined in line 296; used 2 times
maphostname defined in line 585; used 1 times
myhostname defined in line 546; used 2 times

Defined variables

DaemonSocket defined in line 80; used 16 times
NetName defined in line 81; used 4 times
SccsId defined in line 27; never used
SendmailAddress defined in line 78; used 15 times
h_errno defined in line 294; used 2 times
Last modified: 1997-10-03
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4807
Valid CSS Valid XHTML 1.0 Strict