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