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 static char SccsId[] = "@(#)daemon.c 5.2 (Berkeley) 06/07/85 (w/o daemon mode)"; 17 #else 18 19 #include <sys/socket.h> 20 #include <netinet/in.h> 21 #include <netdb.h> 22 #include <sys/wait.h> 23 24 static char SccsId[] = "@(#)daemon.c 5.2 (Berkeley) 06/07/85 (with daemon mode)"; 25 26 /* 27 ** DAEMON.C -- routines to use when running as a daemon. 28 ** 29 ** This entire file is highly dependent on the 4.2 BSD 30 ** interprocess communication primitives. No attempt has 31 ** been made to make this file portable to Version 7, 32 ** Version 6, MPX files, etc. If you should try such a 33 ** thing yourself, I recommend chucking the entire file 34 ** and starting from scratch. Basic semantics are: 35 ** 36 ** getrequests() 37 ** Opens a port and initiates a connection. 38 ** Returns in a child. Must set InChannel and 39 ** OutChannel appropriately. 40 ** clrdaemon() 41 ** Close any open files associated with getting 42 ** the connection; this is used when running the queue, 43 ** etc., to avoid having extra file descriptors during 44 ** the queue run and to avoid confusing the network 45 ** code (if it cares). 46 ** makeconnection(host, port, outfile, infile) 47 ** Make a connection to the named host on the given 48 ** port. Set *outfile and *infile to the files 49 ** appropriate for communication. Returns zero on 50 ** success, else an exit status describing the 51 ** error. 52 ** 53 ** The semantics of both of these should be clean. 54 */ 55 /* 56 ** GETREQUESTS -- open mail IPC port and get requests. 57 ** 58 ** Parameters: 59 ** none. 60 ** 61 ** Returns: 62 ** none. 63 ** 64 ** Side Effects: 65 ** Waits until some interesting activity occurs. When 66 ** it does, a child is created to process it, and the 67 ** parent waits for completion. Return from this 68 ** routine is always in the child. The file pointers 69 ** "InChannel" and "OutChannel" should be set to point 70 ** to the communication channel. 71 */ 72 73 struct sockaddr_in SendmailAddress;/* internet address of sendmail */ 74 75 int DaemonSocket = -1; /* fd describing socket */ 76 char *NetName; /* name of home (local?) network */ 77 78 getrequests() 79 { 80 int t; 81 union wait status; 82 register struct servent *sp; 83 84 /* 85 ** Set up the address for the mailer. 86 */ 87 88 sp = getservbyname("smtp", "tcp"); 89 if (sp == NULL) 90 { 91 syserr("server \"smtp\" unknown"); 92 goto severe; 93 } 94 SendmailAddress.sin_family = AF_INET; 95 SendmailAddress.sin_addr.s_addr = INADDR_ANY; 96 SendmailAddress.sin_port = sp->s_port; 97 98 /* 99 ** Try to actually open the connection. 100 */ 101 102 # ifdef DEBUG 103 if (tTd(15, 1)) 104 printf("getrequests: port 0x%x\n", SendmailAddress.sin_port); 105 # endif DEBUG 106 107 /* get a socket for the SMTP connection */ 108 DaemonSocket = socket(AF_INET, SOCK_STREAM, 0, 0); 109 if (DaemonSocket < 0) 110 { 111 /* probably another daemon already */ 112 syserr("getrequests: can't create socket"); 113 severe: 114 # ifdef LOG 115 if (LogLevel > 0) 116 syslog(LOG_SALERT, "cannot get connection"); 117 # endif LOG 118 finis(); 119 } 120 121 #ifdef DEBUG 122 /* turn on network debugging? */ 123 if (tTd(15, 15)) 124 (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, 0, 0); 125 #endif DEBUG 126 127 if (bind(DaemonSocket, &SendmailAddress, sizeof SendmailAddress, 0) < 0) 128 { 129 syserr("getrequests: cannot bind"); 130 (void) close(DaemonSocket); 131 goto severe; 132 } 133 listen(DaemonSocket, 10); 134 135 # ifdef DEBUG 136 if (tTd(15, 1)) 137 printf("getrequests: %d\n", DaemonSocket); 138 # endif DEBUG 139 140 for (;;) 141 { 142 register int pid; 143 auto int lotherend; 144 struct sockaddr_in otherend; 145 extern int RefuseLA; 146 147 /* see if we are rejecting connections */ 148 while (getla() > RefuseLA) 149 sleep(5); 150 151 /* wait for a connection */ 152 do 153 { 154 errno = 0; 155 lotherend = sizeof otherend; 156 t = accept(DaemonSocket, &otherend, &lotherend, 0); 157 } while (t < 0 && errno == EINTR); 158 if (t < 0) 159 { 160 syserr("getrequests: accept"); 161 sleep(5); 162 continue; 163 } 164 165 /* 166 ** Create a subprocess to process the mail. 167 */ 168 169 # ifdef DEBUG 170 if (tTd(15, 2)) 171 printf("getrequests: forking (fd = %d)\n", t); 172 # endif DEBUG 173 174 pid = fork(); 175 if (pid < 0) 176 { 177 syserr("daemon: cannot fork"); 178 sleep(10); 179 (void) close(t); 180 continue; 181 } 182 183 if (pid == 0) 184 { 185 extern struct hostent *gethostbyaddr(); 186 register struct hostent *hp; 187 extern char *RealHostName; /* srvrsmtp.c */ 188 char buf[MAXNAME]; 189 190 /* 191 ** CHILD -- return to caller. 192 ** Collect verified idea of sending host. 193 ** Verify calling user id if possible here. 194 */ 195 196 /* determine host name */ 197 hp = gethostbyaddr(&otherend.sin_addr, sizeof otherend.sin_addr, AF_INET); 198 if (hp != NULL) 199 { 200 strcpy(buf, hp->h_name); 201 if (NetName != NULL && NetName[0] != '\0' && 202 index(hp->h_name, '.') == NULL) 203 { 204 strcat(buf, "."); 205 strcat(buf, NetName); 206 } 207 } 208 else 209 { 210 extern char *inet_ntoa(); 211 212 /* produce a dotted quad */ 213 (void) sprintf(buf, "[%s]", 214 inet_ntoa(otherend.sin_addr)); 215 } 216 217 /* should we check for illegal connection here? XXX */ 218 219 RealHostName = newstr(buf); 220 221 (void) close(DaemonSocket); 222 InChannel = fdopen(t, "r"); 223 OutChannel = fdopen(dup(t), "w"); 224 # ifdef DEBUG 225 if (tTd(15, 2)) 226 printf("getreq: returning\n"); 227 # endif DEBUG 228 # ifdef LOG 229 if (LogLevel > 11) 230 syslog(LOG_DEBUG, "connected, pid=%d", getpid()); 231 # endif LOG 232 return; 233 } 234 235 /* 236 ** PARENT -- wait for child to terminate. 237 ** Perhaps we should allow concurrent processing? 238 */ 239 240 # ifdef DEBUG 241 if (tTd(15, 2)) 242 { 243 sleep(2); 244 printf("getreq: parent waiting\n"); 245 } 246 # endif DEBUG 247 248 /* close the port so that others will hang (for a while) */ 249 (void) close(t); 250 251 /* pick up old zombies */ 252 while (wait3(&status, WNOHANG, 0) > 0) 253 continue; 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 makeconnection(host, port, outfile, infile) 295 char *host; 296 u_short port; 297 FILE **outfile; 298 FILE **infile; 299 { 300 register int s; 301 302 /* 303 ** Set up the address for the mailer. 304 ** Accept "[a.b.c.d]" syntax for host name. 305 */ 306 307 if (host[0] == '[') 308 { 309 long hid; 310 register char *p = index(host, ']'); 311 312 if (p != NULL) 313 { 314 *p = '\0'; 315 hid = inet_addr(&host[1]); 316 *p = ']'; 317 } 318 if (p == NULL || hid == -1) 319 { 320 usrerr("Invalid numeric domain spec \"%s\"", host); 321 return (EX_NOHOST); 322 } 323 SendmailAddress.sin_addr.s_addr = hid; 324 } 325 else 326 { 327 register struct hostent *hp = gethostbyname(host); 328 329 if (hp == NULL) 330 return (EX_NOHOST); 331 bcopy(hp->h_addr, (char *) &SendmailAddress.sin_addr, hp->h_length); 332 } 333 334 /* 335 ** Determine the port number. 336 */ 337 338 if (port != 0) 339 SendmailAddress.sin_port = htons(port); 340 else 341 { 342 register struct servent *sp = getservbyname("smtp", "tcp"); 343 344 if (sp == NULL) 345 { 346 syserr("makeconnection: server \"smtp\" unknown"); 347 return (EX_OSFILE); 348 } 349 SendmailAddress.sin_port = sp->s_port; 350 } 351 352 /* 353 ** Try to actually open the connection. 354 */ 355 356 # ifdef DEBUG 357 if (tTd(16, 1)) 358 printf("makeconnection (%s)\n", host); 359 # endif DEBUG 360 361 s = socket(AF_INET, SOCK_STREAM, 0, 0); 362 if (s < 0) 363 { 364 syserr("makeconnection: no socket"); 365 goto failure; 366 } 367 368 # ifdef DEBUG 369 if (tTd(16, 1)) 370 printf("makeconnection: %d\n", s); 371 372 /* turn on network debugging? */ 373 if (tTd(16, 14)) 374 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 0, 0); 375 # endif DEBUG 376 (void) fflush(CurEnv->e_xfp); /* for debugging */ 377 errno = 0; /* for debugging */ 378 SendmailAddress.sin_family = AF_INET; 379 if (connect(s, &SendmailAddress, sizeof SendmailAddress, 0) < 0) 380 { 381 /* failure, decide if temporary or not */ 382 failure: 383 switch (errno) 384 { 385 case EISCONN: 386 case ETIMEDOUT: 387 case EINPROGRESS: 388 case EALREADY: 389 case EADDRINUSE: 390 case EHOSTDOWN: 391 case ENETDOWN: 392 case ENETRESET: 393 case ENOBUFS: 394 case ECONNREFUSED: 395 case ECONNRESET: 396 case EHOSTUNREACH: 397 case ENETUNREACH: 398 /* there are others, I'm sure..... */ 399 CurEnv->e_flags &= ~EF_FATALERRS; 400 return (EX_TEMPFAIL); 401 402 case EPERM: 403 /* why is this happening? */ 404 syserr("makeconnection: funny failure, addr=%lx, port=%x", 405 SendmailAddress.sin_addr.s_addr, SendmailAddress.sin_port); 406 return (EX_TEMPFAIL); 407 408 default: 409 return (EX_UNAVAILABLE); 410 } 411 } 412 413 /* connection ok, put it into canonical form */ 414 *outfile = fdopen(s, "w"); 415 *infile = fdopen(s, "r"); 416 417 return (EX_OK); 418 } 419 /* 420 ** MYHOSTNAME -- return the name of this host. 421 ** 422 ** Parameters: 423 ** hostbuf -- a place to return the name of this host. 424 ** size -- the size of hostbuf. 425 ** 426 ** Returns: 427 ** A list of aliases for this host. 428 ** 429 ** Side Effects: 430 ** none. 431 */ 432 433 char ** 434 myhostname(hostbuf, size) 435 char hostbuf[]; 436 int size; 437 { 438 extern struct hostent *gethostbyname(); 439 struct hostent *hp; 440 441 gethostname(hostbuf, size); 442 hp = gethostbyname(hostbuf); 443 if (hp != NULL) 444 { 445 strcpy(hostbuf, hp->h_name); 446 return (hp->h_aliases); 447 } 448 else 449 return (NULL); 450 } 451 /* 452 ** MAPHOSTNAME -- turn a hostname into canonical form 453 ** 454 ** Parameters: 455 ** hbuf -- a buffer containing a hostname. 456 ** hbsize -- the size of hbuf. 457 ** 458 ** Returns: 459 ** none. 460 ** 461 ** Side Effects: 462 ** Looks up the host specified in hbuf. If it is not 463 ** the canonical name for that host, replace it with 464 ** the canonical name. If the name is unknown, or it 465 ** is already the canonical name, leave it unchanged. 466 */ 467 468 maphostname(hbuf, hbsize) 469 char *hbuf; 470 int hbsize; 471 { 472 register struct hostent *hp; 473 extern struct hostent *gethostbyname(); 474 475 makelower(hbuf); 476 hp = gethostbyname(hbuf); 477 if (hp != NULL) 478 { 479 int i = strlen(hp->h_name); 480 481 if (i >= hbsize) 482 hp->h_name[--i] = '\0'; 483 strcpy(hbuf, hp->h_name); 484 } 485 } 486 487 # else DAEMON 488 /* code for systems without sophisticated networking */ 489 490 /* 491 ** MYHOSTNAME -- stub version for case of no daemon code. 492 ** 493 ** Can't convert to upper case here because might be a UUCP name. 494 ** 495 ** Mark, you can change this to be anything you want...... 496 */ 497 498 char ** 499 myhostname(hostbuf, size) 500 char hostbuf[]; 501 int size; 502 { 503 register FILE *f; 504 505 hostbuf[0] = '\0'; 506 f = fopen("/usr/include/whoami", "r"); 507 if (f != NULL) 508 { 509 (void) fgets(hostbuf, size, f); 510 fixcrlf(hostbuf, TRUE); 511 (void) fclose(f); 512 } 513 return (NULL); 514 } 515 /* 516 ** MAPHOSTNAME -- turn a hostname into canonical form 517 ** 518 ** Parameters: 519 ** hbuf -- a buffer containing a hostname. 520 ** hbsize -- the size of hbuf. 521 ** 522 ** Returns: 523 ** none. 524 ** 525 ** Side Effects: 526 ** Looks up the host specified in hbuf. If it is not 527 ** the canonical name for that host, replace it with 528 ** the canonical name. If the name is unknown, or it 529 ** is already the canonical name, leave it unchanged. 530 */ 531 532 /*ARGSUSED*/ 533 maphostname(hbuf, hbsize) 534 char *hbuf; 535 int hbsize; 536 { 537 return; 538 } 539 540 541 #endif DAEMON 542