1939f5b94Sdist /* 20942ea6aSbostic * Copyright (c) 1983 Eric P. Allman 3da1c6175Sbostic * Copyright (c) 1988 Regents of the University of California. 4da1c6175Sbostic * All rights reserved. 5da1c6175Sbostic * 63bc94712Sbostic * %sccs.include.redist.c% 7939f5b94Sdist */ 8939f5b94Sdist 97aa493c5Seric #include <errno.h> 10a8c080f0Seric #include <signal.h> 116c05f684Sbostic #include "sendmail.h" 127fa39d90Seric 13af5e902cSeric #ifndef lint 14da1c6175Sbostic #ifdef DAEMON 15*850144caSeric static char sccsid[] = "@(#)daemon.c 6.29 (Berkeley) 03/30/93 (with daemon mode)"; 16d0a9e852Seric #else 17*850144caSeric static char sccsid[] = "@(#)daemon.c 6.29 (Berkeley) 03/30/93 (without daemon mode)"; 18da1c6175Sbostic #endif 19da1c6175Sbostic #endif /* not lint */ 20da1c6175Sbostic 21da1c6175Sbostic #ifdef DAEMON 22d0a9e852Seric 231c71e510Seric # include <netdb.h> 241e1663f7Swnj # include <sys/wait.h> 25af5e902cSeric # include <sys/time.h> 26d0a9e852Seric 277fa39d90Seric /* 287fa39d90Seric ** DAEMON.C -- routines to use when running as a daemon. 2947b12ae1Seric ** 3047b12ae1Seric ** This entire file is highly dependent on the 4.2 BSD 3147b12ae1Seric ** interprocess communication primitives. No attempt has 3247b12ae1Seric ** been made to make this file portable to Version 7, 3347b12ae1Seric ** Version 6, MPX files, etc. If you should try such a 3447b12ae1Seric ** thing yourself, I recommend chucking the entire file 3547b12ae1Seric ** and starting from scratch. Basic semantics are: 3647b12ae1Seric ** 3747b12ae1Seric ** getrequests() 3847b12ae1Seric ** Opens a port and initiates a connection. 3947b12ae1Seric ** Returns in a child. Must set InChannel and 4047b12ae1Seric ** OutChannel appropriately. 41b7d7afcbSeric ** clrdaemon() 42b7d7afcbSeric ** Close any open files associated with getting 43b7d7afcbSeric ** the connection; this is used when running the queue, 44b7d7afcbSeric ** etc., to avoid having extra file descriptors during 45b7d7afcbSeric ** the queue run and to avoid confusing the network 46b7d7afcbSeric ** code (if it cares). 47914346b1Seric ** makeconnection(host, port, outfile, infile, usesecureport) 4847b12ae1Seric ** Make a connection to the named host on the given 4947b12ae1Seric ** port. Set *outfile and *infile to the files 5047b12ae1Seric ** appropriate for communication. Returns zero on 5147b12ae1Seric ** success, else an exit status describing the 5247b12ae1Seric ** error. 5305b57da8Seric ** maphostname(map, hbuf, hbufsiz, avp) 5405b57da8Seric ** Convert the entry in hbuf into a canonical form. 557fa39d90Seric */ 56e2f2f828Seric 57e2f2f828Seric extern char *anynet_ntoa(); 587fa39d90Seric /* 597fa39d90Seric ** GETREQUESTS -- open mail IPC port and get requests. 607fa39d90Seric ** 617fa39d90Seric ** Parameters: 627fa39d90Seric ** none. 637fa39d90Seric ** 647fa39d90Seric ** Returns: 657fa39d90Seric ** none. 667fa39d90Seric ** 677fa39d90Seric ** Side Effects: 687fa39d90Seric ** Waits until some interesting activity occurs. When 697fa39d90Seric ** it does, a child is created to process it, and the 707fa39d90Seric ** parent waits for completion. Return from this 71147303b1Seric ** routine is always in the child. The file pointers 72147303b1Seric ** "InChannel" and "OutChannel" should be set to point 73147303b1Seric ** to the communication channel. 747fa39d90Seric */ 757fa39d90Seric 76b7d7afcbSeric int DaemonSocket = -1; /* fd describing socket */ 77bfb80540Seric SOCKADDR DaemonAddr; /* socket for incoming */ 781c71e510Seric 797fa39d90Seric getrequests() 807fa39d90Seric { 811c71e510Seric int t; 821c71e510Seric register struct servent *sp; 837868dfc2Seric int on = 1; 8415d084d5Seric bool refusingconnections = TRUE; 850aae1086Seric FILE *pidf; 869b100374Sbostic extern void reapchild(); 87eb889047Seric 88a8268164Seric /* 891c71e510Seric ** Set up the address for the mailer. 90eb889047Seric */ 91eb889047Seric 92bfb80540Seric if (DaemonAddr.sin.sin_family == 0) 93bfb80540Seric DaemonAddr.sin.sin_family = AF_INET; 94bfb80540Seric if (DaemonAddr.sin.sin_addr.s_addr == 0) 95bfb80540Seric DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY; 96bfb80540Seric if (DaemonAddr.sin.sin_port == 0) 97bfb80540Seric { 981c71e510Seric sp = getservbyname("smtp", "tcp"); 991c71e510Seric if (sp == NULL) 100d0a9e852Seric { 10108b25121Seric syserr("554 server \"smtp\" unknown"); 102a1961f2aSeric goto severe; 1031c71e510Seric } 104bfb80540Seric DaemonAddr.sin.sin_port = sp->s_port; 105bfb80540Seric } 1061c71e510Seric 1071c71e510Seric /* 1081c71e510Seric ** Try to actually open the connection. 1091c71e510Seric */ 1101c71e510Seric 1111c71e510Seric if (tTd(15, 1)) 112bfb80540Seric printf("getrequests: port 0x%x\n", DaemonAddr.sin.sin_port); 1131c71e510Seric 1141c71e510Seric /* get a socket for the SMTP connection */ 115af5e902cSeric DaemonSocket = socket(AF_INET, SOCK_STREAM, 0); 116b7d7afcbSeric if (DaemonSocket < 0) 1171c71e510Seric { 1181c71e510Seric /* probably another daemon already */ 1191c71e510Seric syserr("getrequests: can't create socket"); 1201c71e510Seric severe: 121b0ba8827Seric # ifdef LOG 122b0ba8827Seric if (LogLevel > 0) 1230c034190Seric syslog(LOG_ALERT, "problem creating SMTP socket"); 1246c2c3107Seric # endif /* LOG */ 12547b12ae1Seric finis(); 126d0a9e852Seric } 1271b6e4a15Seric 1281b6e4a15Seric /* turn on network debugging? */ 129a2ef5fa4Seric if (tTd(15, 101)) 13052308a50Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on); 1311b6e4a15Seric 1327868dfc2Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on); 1337868dfc2Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof on); 1347868dfc2Seric 135bfb80540Seric if (bind(DaemonSocket, &DaemonAddr.sa, sizeof DaemonAddr) < 0) 1361c71e510Seric { 1371c71e510Seric syserr("getrequests: cannot bind"); 138b7d7afcbSeric (void) close(DaemonSocket); 1391c71e510Seric goto severe; 1401c71e510Seric } 1411c71e510Seric 1421cd247eeSeric (void) signal(SIGCHLD, reapchild); 14352308a50Seric 1440aae1086Seric /* write the pid to the log file for posterity */ 1450aae1086Seric pidf = fopen(PidFile, "w"); 1460aae1086Seric if (pidf != NULL) 1470aae1086Seric { 1480aae1086Seric fprintf(pidf, "%d\n", getpid()); 1490aae1086Seric fclose(pidf); 1500aae1086Seric } 1510aae1086Seric 1520aae1086Seric 1531c71e510Seric if (tTd(15, 1)) 154b7d7afcbSeric printf("getrequests: %d\n", DaemonSocket); 1551c71e510Seric 1561c71e510Seric for (;;) 1571c71e510Seric { 1583a099713Seric register int pid; 159a44d5a5eSeric auto int lotherend; 16015d084d5Seric extern bool refuseconnections(); 1613a099713Seric 1623a099713Seric /* see if we are rejecting connections */ 16315d084d5Seric CurrentLA = getla(); 16415d084d5Seric if (refuseconnections()) 1656775ec03Sbostic { 16615d084d5Seric if (!refusingconnections) 16715d084d5Seric { 16815d084d5Seric /* don't queue so peer will fail quickly */ 16915d084d5Seric (void) listen(DaemonSocket, 0); 17015d084d5Seric refusingconnections = TRUE; 17115d084d5Seric } 17271e5e267Seric setproctitle("rejecting connections: load average: %d", 17371e5e267Seric CurrentLA); 1743a099713Seric sleep(5); 17515d084d5Seric continue; 17615d084d5Seric } 17715d084d5Seric 17815d084d5Seric if (refusingconnections) 17915d084d5Seric { 18015d084d5Seric /* start listening again */ 18115d084d5Seric if (listen(DaemonSocket, 10) < 0) 18215d084d5Seric { 18315d084d5Seric syserr("getrequests: cannot listen"); 18415d084d5Seric (void) close(DaemonSocket); 18515d084d5Seric goto severe; 18615d084d5Seric } 18715d084d5Seric setproctitle("accepting connections"); 18815d084d5Seric refusingconnections = FALSE; 1896775ec03Sbostic } 190a44d5a5eSeric 1911c71e510Seric /* wait for a connection */ 1921c71e510Seric do 1931c71e510Seric { 1941c71e510Seric errno = 0; 1959f9a15b6Skarels lotherend = sizeof RealHostAddr; 1969b100374Sbostic t = accept(DaemonSocket, 1979b100374Sbostic (struct sockaddr *)&RealHostAddr, &lotherend); 1981c71e510Seric } while (t < 0 && errno == EINTR); 1991c71e510Seric if (t < 0) 2001c71e510Seric { 2011c71e510Seric syserr("getrequests: accept"); 2021c71e510Seric sleep(5); 2031c71e510Seric continue; 2041c71e510Seric } 205d0a9e852Seric 206d0a9e852Seric /* 207d0a9e852Seric ** Create a subprocess to process the mail. 208d0a9e852Seric */ 209d0a9e852Seric 21061e4310fSeric if (tTd(15, 2)) 2111c71e510Seric printf("getrequests: forking (fd = %d)\n", t); 212eb889047Seric 213a8268164Seric pid = fork(); 214a8268164Seric if (pid < 0) 215a8268164Seric { 216a8268164Seric syserr("daemon: cannot fork"); 217a8268164Seric sleep(10); 2181c71e510Seric (void) close(t); 219a8268164Seric continue; 220a8268164Seric } 221a8268164Seric 222a8268164Seric if (pid == 0) 223a8268164Seric { 224a44d5a5eSeric extern struct hostent *gethostbyaddr(); 225a44d5a5eSeric register struct hostent *hp; 226a44d5a5eSeric char buf[MAXNAME]; 227a44d5a5eSeric 228a8268164Seric /* 229a8268164Seric ** CHILD -- return to caller. 230a44d5a5eSeric ** Collect verified idea of sending host. 231a8268164Seric ** Verify calling user id if possible here. 232a8268164Seric */ 233a8268164Seric 2341cd247eeSeric (void) signal(SIGCHLD, SIG_DFL); 235779ac194Seric 236a44d5a5eSeric /* determine host name */ 23783c1f4bcSeric switch (RealHostAddr.sa.sa_family) 23883c1f4bcSeric { 23983c1f4bcSeric #ifdef NETINET 24083c1f4bcSeric case AF_INET: 24183c1f4bcSeric hp = gethostbyaddr((char *) &RealHostAddr.sin.sin_addr, 24283c1f4bcSeric sizeof RealHostAddr.sin.sin_addr, 24383c1f4bcSeric AF_INET); 24483c1f4bcSeric break; 24583c1f4bcSeric #endif 24683c1f4bcSeric 24783c1f4bcSeric #ifdef NETISO 24883c1f4bcSeric case AF_ISO: 24983c1f4bcSeric hp = gethostbyaddr((char *) &RealHostAddr.siso.siso_addr, 25083c1f4bcSeric sizeof RealHostAddr.siso.siso_addr, 25183c1f4bcSeric AF_ISO); 25283c1f4bcSeric break; 25383c1f4bcSeric #endif 25483c1f4bcSeric 25583c1f4bcSeric default: 25683c1f4bcSeric hp = gethostbyaddr(RealHostAddr.sa.sa_data, 25783c1f4bcSeric sizeof RealHostAddr.sa.sa_data, 25883c1f4bcSeric RealHostAddr.sa.sa_family); 25983c1f4bcSeric break; 26083c1f4bcSeric } 26183c1f4bcSeric 262a44d5a5eSeric if (hp != NULL) 263fefbbe29Seric (void) strcpy(buf, hp->h_name); 264a44d5a5eSeric else 26529dcf4baSeric { 26629dcf4baSeric /* produce a dotted quad */ 26729dcf4baSeric (void) sprintf(buf, "[%s]", 268e2f2f828Seric anynet_ntoa(&RealHostAddr)); 26929dcf4baSeric } 27029dcf4baSeric 2712a6bc25bSeric #ifdef LOG 272845e533cSeric if (LogLevel > 10) 2732a6bc25bSeric { 2742a6bc25bSeric /* log connection information */ 2752a6bc25bSeric syslog(LOG_INFO, "connect from %s (%s)", 276e2f2f828Seric buf, anynet_ntoa(&RealHostAddr)); 2772a6bc25bSeric } 2782a6bc25bSeric #endif 2792a6bc25bSeric 28029dcf4baSeric /* should we check for illegal connection here? XXX */ 28129dcf4baSeric 282a44d5a5eSeric RealHostName = newstr(buf); 283a44d5a5eSeric 284b7d7afcbSeric (void) close(DaemonSocket); 2851c71e510Seric InChannel = fdopen(t, "r"); 2861d5bd586Seric OutChannel = fdopen(dup(t), "w"); 28761e4310fSeric if (tTd(15, 2)) 288d0a9e852Seric printf("getreq: returning\n"); 289a8268164Seric return; 290a8268164Seric } 291a8268164Seric 2923c154354Seric /* close the port so that others will hang (for a while) */ 2933c154354Seric (void) close(t); 2948e3e4b17Seric } 2953c154354Seric /*NOTREACHED*/ 2963c154354Seric } 2978e3e4b17Seric /* 298b7d7afcbSeric ** CLRDAEMON -- reset the daemon connection 299b7d7afcbSeric ** 300b7d7afcbSeric ** Parameters: 301b7d7afcbSeric ** none. 302b7d7afcbSeric ** 303b7d7afcbSeric ** Returns: 304b7d7afcbSeric ** none. 305b7d7afcbSeric ** 306b7d7afcbSeric ** Side Effects: 307b7d7afcbSeric ** releases any resources used by the passive daemon. 308b7d7afcbSeric */ 309b7d7afcbSeric 310b7d7afcbSeric clrdaemon() 311b7d7afcbSeric { 312b7d7afcbSeric if (DaemonSocket >= 0) 313b7d7afcbSeric (void) close(DaemonSocket); 314b7d7afcbSeric DaemonSocket = -1; 315b7d7afcbSeric } 316b7d7afcbSeric /* 317bfb80540Seric ** SETDAEMONOPTIONS -- set options for running the daemon 318bfb80540Seric ** 319bfb80540Seric ** Parameters: 320bfb80540Seric ** p -- the options line. 321bfb80540Seric ** 322bfb80540Seric ** Returns: 323bfb80540Seric ** none. 324bfb80540Seric */ 325bfb80540Seric 326bfb80540Seric setdaemonoptions(p) 327bfb80540Seric register char *p; 328bfb80540Seric { 329*850144caSeric if (DaemonAddr.sa.sa_family == AF_UNSPEC) 330*850144caSeric DaemonAddr.sa.sa_family = AF_INET; 331*850144caSeric 332bfb80540Seric while (p != NULL) 333bfb80540Seric { 334bfb80540Seric register char *f; 335bfb80540Seric register char *v; 336bfb80540Seric 337bfb80540Seric while (isascii(*p) && isspace(*p)) 338bfb80540Seric p++; 339bfb80540Seric if (*p == '\0') 340bfb80540Seric break; 341bfb80540Seric f = p; 342bfb80540Seric p = strchr(p, ','); 343bfb80540Seric if (p != NULL) 344bfb80540Seric *p++ = '\0'; 345bfb80540Seric v = strchr(f, '='); 346bfb80540Seric if (v == NULL) 347bfb80540Seric continue; 348bfb80540Seric while (isascii(*++v) && isspace(*v)) 349bfb80540Seric continue; 350bfb80540Seric 351bfb80540Seric switch (*f) 352bfb80540Seric { 353*850144caSeric case 'F': /* address family */ 354*850144caSeric if (isascii(*v) && isdigit(*v)) 355*850144caSeric DaemonAddr.sa.sa_family = atoi(v); 356*850144caSeric #ifdef NETINET 357*850144caSeric else if (strcasecmp(v, "inet") == 0) 358*850144caSeric DaemonAddr.sa.sa_family = AF_INET; 359*850144caSeric #endif 360*850144caSeric #ifdef NETISO 361*850144caSeric else if (strcasecmp(v, "iso") == 0) 362*850144caSeric DaemonAddr.sa.sa_family = AF_ISO; 363*850144caSeric #endif 364*850144caSeric #ifdef NETNS 365*850144caSeric else if (strcasecmp(v, "ns") == 0) 366*850144caSeric DaemonAddr.sa.sa_family = AF_NS; 367*850144caSeric #endif 368*850144caSeric #ifdef NETX25 369*850144caSeric else if (strcasecmp(v, "x.25") == 0) 370*850144caSeric DaemonAddr.sa.sa_family = AF_CCITT; 371*850144caSeric #endif 372*850144caSeric else 373*850144caSeric syserr("554 Unknown address family %s in Family=option", v); 374*850144caSeric break; 375*850144caSeric 376*850144caSeric case 'A': /* address */ 377*850144caSeric switch (DaemonAddr.sa.sa_family) 378*850144caSeric { 379*850144caSeric #ifdef NETINET 380*850144caSeric case AF_INET: 381*850144caSeric if (isascii(*v) && isdigit(*v)) 382*850144caSeric DaemonAddr.sin.sin_addr.s_addr = inet_network(v); 383*850144caSeric else 384*850144caSeric { 385*850144caSeric register struct netent *np; 386*850144caSeric 387*850144caSeric np = getnetbyname(v); 388*850144caSeric if (np == NULL) 389*850144caSeric syserr("554 network \"%s\" unknown", v); 390*850144caSeric else 391*850144caSeric DaemonAddr.sin.sin_addr.s_addr = np->n_net; 392*850144caSeric } 393*850144caSeric break; 394*850144caSeric #endif 395*850144caSeric 396*850144caSeric default: 397*850144caSeric syserr("554 Address= option unsupported for family %d", 398*850144caSeric DaemonAddr.sa.sa_family); 399*850144caSeric break; 400*850144caSeric } 401*850144caSeric break; 402*850144caSeric 403bfb80540Seric case 'P': /* port */ 404*850144caSeric switch (DaemonAddr.sa.sa_family) 405*850144caSeric { 406*850144caSeric short port; 407*850144caSeric 408*850144caSeric #ifdef NETINET 409*850144caSeric case AF_INET: 410bfb80540Seric if (isascii(*v) && isdigit(*v)) 411bfb80540Seric DaemonAddr.sin.sin_port = atoi(v); 412bfb80540Seric else 413bfb80540Seric { 414bfb80540Seric register struct servent *sp; 415bfb80540Seric 416bfb80540Seric sp = getservbyname(v, "tcp"); 417bfb80540Seric if (sp == NULL) 418bfb80540Seric syserr("554 server \"%s\" unknown", v); 419bfb80540Seric else 420bfb80540Seric DaemonAddr.sin.sin_port = sp->s_port; 421bfb80540Seric } 422bfb80540Seric break; 423*850144caSeric #endif 424bfb80540Seric 425*850144caSeric #ifdef NETISO 426*850144caSeric case AF_ISO: 427*850144caSeric /* assume two byte transport selector */ 428bfb80540Seric if (isascii(*v) && isdigit(*v)) 429*850144caSeric port = atoi(v); 430bfb80540Seric else 431bfb80540Seric { 432*850144caSeric register struct servent *sp; 433bfb80540Seric 434*850144caSeric sp = getservbyname(v, "tcp"); 435*850144caSeric if (sp == NULL) 436*850144caSeric syserr("554 server \"%s\" unknown", v); 437bfb80540Seric else 438*850144caSeric port = sp->s_port; 439*850144caSeric } 440*850144caSeric bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2); 441*850144caSeric break; 442*850144caSeric #endif 443*850144caSeric 444*850144caSeric default: 445*850144caSeric syserr("554 Port= option unsupported for family %d", 446*850144caSeric DaemonAddr.sa.sa_family); 447*850144caSeric break; 448bfb80540Seric } 449bfb80540Seric break; 450bfb80540Seric } 451bfb80540Seric } 452bfb80540Seric } 453bfb80540Seric /* 4547aa493c5Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 4557aa493c5Seric ** 4567aa493c5Seric ** Parameters: 4577aa493c5Seric ** host -- the name of the host. 45848ff0a9dSeric ** port -- the port number to connect to. 459655feedbSeric ** mci -- a pointer to the mail connection information 460655feedbSeric ** structure to be filled in. 461914346b1Seric ** usesecureport -- if set, use a low numbered (reserved) 462914346b1Seric ** port to provide some rudimentary authentication. 4637aa493c5Seric ** 4647aa493c5Seric ** Returns: 4657aa493c5Seric ** An exit code telling whether the connection could be 4667aa493c5Seric ** made and if not why not. 4677aa493c5Seric ** 4687aa493c5Seric ** Side Effects: 4697aa493c5Seric ** none. 4707aa493c5Seric */ 4717aa493c5Seric 472e2f2f828Seric SOCKADDR CurHostAddr; /* address of current host */ 47371ff6caaSeric 474b31e7f2bSeric int 475655feedbSeric makeconnection(host, port, mci, usesecureport) 4767aa493c5Seric char *host; 477210215eaSeric u_short port; 478b31e7f2bSeric register MCI *mci; 479914346b1Seric bool usesecureport; 4807aa493c5Seric { 48104344589Sbloom register int i, s; 48204344589Sbloom register struct hostent *hp = (struct hostent *)NULL; 483e2f2f828Seric SOCKADDR addr; 4846286bb75Sbloom int sav_errno; 485e2f2f828Seric int addrlen; 486134746fbSeric #ifdef NAMED_BIND 487134746fbSeric extern int h_errno; 488134746fbSeric #endif 4897aa493c5Seric 4907aa493c5Seric /* 4917aa493c5Seric ** Set up the address for the mailer. 49271096d12Seric ** Accept "[a.b.c.d]" syntax for host name. 4937aa493c5Seric */ 4947aa493c5Seric 495134746fbSeric #ifdef NAMED_BIND 496794bdbb9Smiriam h_errno = 0; 497134746fbSeric #endif 498794bdbb9Smiriam errno = 0; 499967778e2Seric bzero(&CurHostAddr, sizeof CurHostAddr); 500794bdbb9Smiriam 50171096d12Seric if (host[0] == '[') 50271096d12Seric { 503a44d5a5eSeric long hid; 5046c2c3107Seric register char *p = strchr(host, ']'); 50571096d12Seric 506a44d5a5eSeric if (p != NULL) 50771096d12Seric { 508a44d5a5eSeric *p = '\0'; 509a44d5a5eSeric hid = inet_addr(&host[1]); 510a7e21fe6Seric if (hid == -1) 511a7e21fe6Seric { 512a7e21fe6Seric /* try it as a host name (avoid MX lookup) */ 513a7e21fe6Seric hp = gethostbyname(&host[1]); 514a7e21fe6Seric *p = ']'; 515a7e21fe6Seric goto gothostent; 516a7e21fe6Seric } 517a44d5a5eSeric *p = ']'; 51871096d12Seric } 519a7e21fe6Seric if (p == NULL) 52071096d12Seric { 52108b25121Seric usrerr("553 Invalid numeric domain spec \"%s\"", host); 52271096d12Seric return (EX_NOHOST); 52371096d12Seric } 52483c1f4bcSeric addr.sin.sin_family = AF_INET; 52583c1f4bcSeric addr.sin.sin_addr.s_addr = hid; 52671096d12Seric } 5271c71e510Seric else 5281c71e510Seric { 52904344589Sbloom hp = gethostbyname(host); 530a7e21fe6Seric gothostent: 531794bdbb9Smiriam if (hp == NULL) 532794bdbb9Smiriam { 533134746fbSeric #ifdef NAMED_BIND 534794bdbb9Smiriam if (errno == ETIMEDOUT || h_errno == TRY_AGAIN) 53552308a50Seric return (EX_TEMPFAIL); 53682e5d8ddSeric 537134746fbSeric /* if name server is specified, assume temp fail */ 538134746fbSeric if (errno == ECONNREFUSED && UseNameServer) 539134746fbSeric return (EX_TEMPFAIL); 540134746fbSeric #endif 5417aa493c5Seric return (EX_NOHOST); 542794bdbb9Smiriam } 54383c1f4bcSeric addr.sa.sa_family = hp->h_addrtype; 54483c1f4bcSeric switch (hp->h_addrtype) 54583c1f4bcSeric { 54683c1f4bcSeric #ifdef NETINET 54783c1f4bcSeric case AF_INET: 548e2f2f828Seric bcopy(hp->h_addr, 54983c1f4bcSeric &addr.sin.sin_addr, 550e2f2f828Seric hp->h_length); 55183c1f4bcSeric break; 55283c1f4bcSeric #endif 55383c1f4bcSeric 55483c1f4bcSeric default: 555e2f2f828Seric bcopy(hp->h_addr, 55683c1f4bcSeric addr.sa.sa_data, 557e2f2f828Seric hp->h_length); 55883c1f4bcSeric break; 55983c1f4bcSeric } 56004344589Sbloom i = 1; 5611c71e510Seric } 5621c71e510Seric 5631c71e510Seric /* 5641c71e510Seric ** Determine the port number. 5651c71e510Seric */ 5661c71e510Seric 567fd7c0790Seric if (port != 0) 568e2f2f828Seric port = htons(port); 569fd7c0790Seric else 5701c71e510Seric { 5711c71e510Seric register struct servent *sp = getservbyname("smtp", "tcp"); 5721c71e510Seric 5731c71e510Seric if (sp == NULL) 5741c71e510Seric { 57508b25121Seric syserr("554 makeconnection: server \"smtp\" unknown"); 576845e533cSeric return (EX_OSERR); 5771c71e510Seric } 578e2f2f828Seric port = sp->s_port; 579e2f2f828Seric } 580e2f2f828Seric 58183c1f4bcSeric switch (addr.sa.sa_family) 582e2f2f828Seric { 583e2f2f828Seric case AF_INET: 58483c1f4bcSeric addr.sin.sin_port = port; 585e2f2f828Seric addrlen = sizeof (struct sockaddr_in); 586e2f2f828Seric break; 587e2f2f828Seric 588e2f2f828Seric #ifdef NETISO 589e2f2f828Seric case AF_ISO: 590e2f2f828Seric /* assume two byte transport selector */ 591e2f2f828Seric bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 592e2f2f828Seric addrlen = sizeof (struct sockaddr_iso); 593e2f2f828Seric break; 594e2f2f828Seric #endif 595e2f2f828Seric 596e2f2f828Seric default: 59783c1f4bcSeric syserr("Can't connect to address family %d", addr.sa.sa_family); 598e2f2f828Seric return (EX_NOHOST); 5991c71e510Seric } 6007aa493c5Seric 6017aa493c5Seric /* 6027aa493c5Seric ** Try to actually open the connection. 6037aa493c5Seric */ 6047aa493c5Seric 605aea02ca1Seric for (;;) 606aea02ca1Seric { 60761e4310fSeric if (tTd(16, 1)) 608e2f2f828Seric printf("makeconnection (%s [%s])\n", 609e2f2f828Seric host, anynet_ntoa(&addr)); 6107aa493c5Seric 611226e3022Seric /* save for logging */ 612226e3022Seric CurHostAddr = addr; 613226e3022Seric 614914346b1Seric if (usesecureport) 615914346b1Seric { 616914346b1Seric int rport = IPPORT_RESERVED - 1; 617914346b1Seric 618914346b1Seric s = rresvport(&rport); 619914346b1Seric } 620914346b1Seric else 621914346b1Seric { 622af5e902cSeric s = socket(AF_INET, SOCK_STREAM, 0); 623914346b1Seric } 6247aa493c5Seric if (s < 0) 6257aa493c5Seric { 6266286bb75Sbloom sav_errno = errno; 627914346b1Seric syserr("makeconnection: no socket"); 6287aa493c5Seric goto failure; 6297aa493c5Seric } 6307aa493c5Seric 63161e4310fSeric if (tTd(16, 1)) 632b31e7f2bSeric printf("makeconnection: fd=%d\n", s); 6331b6e4a15Seric 6341b6e4a15Seric /* turn on network debugging? */ 635a2ef5fa4Seric if (tTd(16, 101)) 63652308a50Seric { 63752308a50Seric int on = 1; 638aea02ca1Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, 639aea02ca1Seric (char *)&on, sizeof on); 64052308a50Seric } 64187d6e633Srick if (CurEnv->e_xfp != NULL) 642877a6142Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 6434bd6a662Seric errno = 0; /* for debugging */ 644e2f2f828Seric if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 645aea02ca1Seric break; 646aea02ca1Seric 647aea02ca1Seric /* couldn't connect.... figure out why */ 6486286bb75Sbloom sav_errno = errno; 6496286bb75Sbloom (void) close(s); 65004344589Sbloom if (hp && hp->h_addr_list[i]) 65104344589Sbloom { 652e2f2f828Seric extern char *errstring(); 653e2f2f828Seric 654aea02ca1Seric if (tTd(16, 1)) 655e2f2f828Seric printf("Connect failed (%s); trying new address....\n", 656e2f2f828Seric errstring(sav_errno)); 65783c1f4bcSeric switch (addr.sa.sa_family) 65883c1f4bcSeric { 65983c1f4bcSeric #ifdef NETINET 66083c1f4bcSeric case AF_INET: 661e2f2f828Seric bcopy(hp->h_addr_list[i++], 66283c1f4bcSeric &addr.sin.sin_addr, 663e2f2f828Seric hp->h_length); 66483c1f4bcSeric break; 66583c1f4bcSeric #endif 66683c1f4bcSeric 66783c1f4bcSeric default: 668e2f2f828Seric bcopy(hp->h_addr_list[i++], 66983c1f4bcSeric addr.sa.sa_data, 670914346b1Seric hp->h_length); 67183c1f4bcSeric break; 67283c1f4bcSeric } 673aea02ca1Seric continue; 67404344589Sbloom } 67504344589Sbloom 6767aa493c5Seric /* failure, decide if temporary or not */ 6777aa493c5Seric failure: 678e2de2524Seric if (transienterror(sav_errno)) 679e2de2524Seric return EX_TEMPFAIL; 680e2de2524Seric else 68187d6e633Srick { 68287d6e633Srick extern char *errstring(); 68387d6e633Srick 68408b25121Seric message("%s", errstring(sav_errno)); 6857aa493c5Seric return (EX_UNAVAILABLE); 6867aa493c5Seric } 6877aa493c5Seric } 6887aa493c5Seric 6897aa493c5Seric /* connection ok, put it into canonical form */ 690655feedbSeric mci->mci_out = fdopen(s, "w"); 691655feedbSeric mci->mci_in = fdopen(dup(s), "r"); 6927aa493c5Seric 693dca8e1f7Seric return (EX_OK); 6947aa493c5Seric } 695444eaf03Seric /* 696444eaf03Seric ** MYHOSTNAME -- return the name of this host. 697444eaf03Seric ** 698444eaf03Seric ** Parameters: 699444eaf03Seric ** hostbuf -- a place to return the name of this host. 700897f1869Seric ** size -- the size of hostbuf. 701444eaf03Seric ** 702444eaf03Seric ** Returns: 703444eaf03Seric ** A list of aliases for this host. 704444eaf03Seric ** 705444eaf03Seric ** Side Effects: 70638ad259dSeric ** Sets the MyIpAddrs buffer to a list of my IP addresses. 707444eaf03Seric */ 708444eaf03Seric 70938ad259dSeric struct in_addr MyIpAddrs[MAXIPADDR + 1]; 71038ad259dSeric 711444eaf03Seric char ** 712897f1869Seric myhostname(hostbuf, size) 713444eaf03Seric char hostbuf[]; 714897f1869Seric int size; 715444eaf03Seric { 71638ad259dSeric register struct hostent *hp; 717444eaf03Seric extern struct hostent *gethostbyname(); 718444eaf03Seric 719af5e902cSeric if (gethostname(hostbuf, size) < 0) 720af5e902cSeric { 721af5e902cSeric (void) strcpy(hostbuf, "localhost"); 722af5e902cSeric } 723a44d5a5eSeric hp = gethostbyname(hostbuf); 724a44d5a5eSeric if (hp != NULL) 7257364df9fSeric { 72638ad259dSeric (void) strncpy(hostbuf, hp->h_name, size - 1); 72738ad259dSeric hostbuf[size - 1] = '\0'; 72838ad259dSeric 72938ad259dSeric if (hp->h_addrtype == AF_INET && hp->h_length == 4) 73038ad259dSeric { 73138ad259dSeric register int i; 73238ad259dSeric 73338ad259dSeric for (i = 0; i < MAXIPADDR; i++) 73438ad259dSeric { 73538ad259dSeric if (hp->h_addr_list[i] == NULL) 73638ad259dSeric break; 73738ad259dSeric MyIpAddrs[i].s_addr = *(u_long *) hp->h_addr_list[i]; 73838ad259dSeric } 73938ad259dSeric MyIpAddrs[i].s_addr = 0; 74038ad259dSeric } 74138ad259dSeric 742a44d5a5eSeric return (hp->h_aliases); 7437364df9fSeric } 744444eaf03Seric else 745444eaf03Seric return (NULL); 746444eaf03Seric } 747cb452edcSeric /* 748320e0d1cSeric ** GETREALHOSTNAME -- get the real host name asociated with a file descriptor 749320e0d1cSeric ** 750320e0d1cSeric ** Parameters: 751320e0d1cSeric ** fd -- the descriptor 752320e0d1cSeric ** 753320e0d1cSeric ** Returns: 754320e0d1cSeric ** The host name associated with this descriptor, if it can 755320e0d1cSeric ** be determined. 756320e0d1cSeric ** NULL otherwise. 757320e0d1cSeric ** 758320e0d1cSeric ** Side Effects: 759320e0d1cSeric ** none 760320e0d1cSeric */ 761320e0d1cSeric 762320e0d1cSeric char * 763320e0d1cSeric getrealhostname(fd) 764320e0d1cSeric int fd; 765320e0d1cSeric { 766320e0d1cSeric register struct hostent *hp; 767e4a929e2Seric SOCKADDR sa; 768e2f2f828Seric int salen; 769320e0d1cSeric char hbuf[MAXNAME]; 770320e0d1cSeric extern struct hostent *gethostbyaddr(); 771320e0d1cSeric 772e2f2f828Seric salen = sizeof sa; 77325f5a145Seric if (getsockname(fd, &sa.sa, &salen) < 0 || salen <= 0) 774320e0d1cSeric return NULL; 77525f5a145Seric hp = gethostbyaddr(sa.sa.sa_data, salen, sa.sa.sa_family); 776320e0d1cSeric if (hp != NULL) 777320e0d1cSeric (void) strcpy(hbuf, hp->h_name); 778320e0d1cSeric else 779e2f2f828Seric (void) sprintf(hbuf, "[%s]", anynet_ntoa(&sa)); 780320e0d1cSeric return hbuf; 781320e0d1cSeric } 782320e0d1cSeric /* 78315d084d5Seric ** MAPHOSTNAME -- turn a hostname into canonical form 78415d084d5Seric ** 78515d084d5Seric ** Parameters: 78605b57da8Seric ** map -- a pointer to this map (unused). 78715d084d5Seric ** hbuf -- a buffer containing a hostname. 78815d084d5Seric ** hbsize -- the size of hbuf. 789d798a1deSeric ** avp -- unused -- for compatibility with other mapping 790d798a1deSeric ** functions. 79115d084d5Seric ** 79215d084d5Seric ** Returns: 79315d084d5Seric ** The mapping, if found. 79415d084d5Seric ** NULL if no mapping found. 79515d084d5Seric ** 79615d084d5Seric ** Side Effects: 79715d084d5Seric ** Looks up the host specified in hbuf. If it is not 79815d084d5Seric ** the canonical name for that host, return the canonical 79915d084d5Seric ** name. 800f36ede03Sbostic */ 801cb452edcSeric 80215d084d5Seric char * 80305b57da8Seric maphostname(map, hbuf, hbsize, avp) 80405b57da8Seric MAP *map; 80599f7cf32Seric char *hbuf; 80699f7cf32Seric int hbsize; 80715d084d5Seric char **avp; 80899f7cf32Seric { 80999f7cf32Seric register struct hostent *hp; 8105f78836eSmiriam u_long in_addr; 81105b57da8Seric char *cp; 81238ad259dSeric int i; 813f36ede03Sbostic struct hostent *gethostbyaddr(); 8145f78836eSmiriam 81599b358daSeric /* allow room for null */ 81615d084d5Seric hbsize--; 81715d084d5Seric 818f36ede03Sbostic /* 819f36ede03Sbostic * If first character is a bracket, then it is an address 820f36ede03Sbostic * lookup. Address is copied into a temporary buffer to 821f36ede03Sbostic * strip the brackets and to preserve hbuf if address is 822f36ede03Sbostic * unknown. 823f36ede03Sbostic */ 82415d084d5Seric 825cb452edcSeric if (*hbuf != '[') 82615d084d5Seric { 827d798a1deSeric extern bool getcanonname(); 828d798a1deSeric 8298cb4653dSeric if (tTd(9, 1)) 8309040ec4fSeric printf("maphostname(%s, %d) => ", hbuf, hbsize); 831d5c60ac0Seric if (getcanonname(hbuf, hbsize)) 8329040ec4fSeric { 8339040ec4fSeric if (tTd(9, 1)) 8349040ec4fSeric printf("%s\n", hbuf); 83515d084d5Seric return hbuf; 8369040ec4fSeric } 83715d084d5Seric else 8389040ec4fSeric { 8399040ec4fSeric if (tTd(9, 1)) 8409040ec4fSeric printf("FAIL\n"); 84115d084d5Seric return NULL; 84215d084d5Seric } 8439040ec4fSeric } 84405b57da8Seric if ((cp = strchr(hbuf, ']')) == NULL) 84515d084d5Seric return (NULL); 84634e39927Sbostic *cp = '\0'; 84705b57da8Seric in_addr = inet_addr(&hbuf[1]); 84838ad259dSeric 84938ad259dSeric /* check to see if this is one of our addresses */ 85038ad259dSeric for (i = 0; MyIpAddrs[i].s_addr != 0; i++) 85138ad259dSeric { 85238ad259dSeric if (MyIpAddrs[i].s_addr == in_addr) 85338ad259dSeric { 85438ad259dSeric strncpy(hbuf, MyHostName, hbsize); 85538ad259dSeric hbuf[hbsize] = '\0'; 85638ad259dSeric return hbuf; 85738ad259dSeric } 85838ad259dSeric } 85938ad259dSeric 86038ad259dSeric /* nope -- ask the name server */ 86131601fa7Seric hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET); 8625f78836eSmiriam if (hp == NULL) 86315d084d5Seric return (NULL); 86415d084d5Seric 86538ad259dSeric /* found a match -- copy out */ 86605b57da8Seric if (strlen(hp->h_name) > hbsize) 86705b57da8Seric hp->h_name[hbsize] = '\0'; 868fefbbe29Seric (void) strcpy(hbuf, hp->h_name); 86915d084d5Seric return hbuf; 87099f7cf32Seric } 871e2f2f828Seric /* 872e2f2f828Seric ** ANYNET_NTOA -- convert a network address to printable form. 873e2f2f828Seric ** 874e2f2f828Seric ** Parameters: 875e2f2f828Seric ** sap -- a pointer to a sockaddr structure. 876e2f2f828Seric ** 877e2f2f828Seric ** Returns: 878e2f2f828Seric ** A printable version of that sockaddr. 879e2f2f828Seric */ 880e2f2f828Seric 881e2f2f828Seric char * 882e2f2f828Seric anynet_ntoa(sap) 883e2f2f828Seric register SOCKADDR *sap; 884e2f2f828Seric { 885e2f2f828Seric register char *bp; 886e2f2f828Seric register char *ap; 887e2f2f828Seric int l; 888e2f2f828Seric static char buf[80]; 889e2f2f828Seric 8908cb4653dSeric /* check for null/zero family */ 8918cb4653dSeric if (sap == NULL) 8928cb4653dSeric return "NULLADDR"; 8938cb4653dSeric if (sap->sa.sa_family == 0) 8948cb4653dSeric return "0"; 8958cb4653dSeric 89683c1f4bcSeric #ifdef NETINET 89783c1f4bcSeric if (sap->sa.sa_family == AF_INET) 898e2f2f828Seric { 899e2f2f828Seric extern char *inet_ntoa(); 900e2f2f828Seric 901e2f2f828Seric return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr); 902e2f2f828Seric } 90383c1f4bcSeric #endif 904e2f2f828Seric 905e2f2f828Seric /* unknown family -- just dump bytes */ 90683c1f4bcSeric (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 907e2f2f828Seric bp = &buf[strlen(buf)]; 90883c1f4bcSeric ap = sap->sa.sa_data; 90983c1f4bcSeric for (l = sizeof sap->sa.sa_data; --l >= 0; ) 910e2f2f828Seric { 911e2f2f828Seric (void) sprintf(bp, "%02x:", *ap++ & 0377); 912e2f2f828Seric bp += 3; 913e2f2f828Seric } 914e2f2f828Seric *--bp = '\0'; 915e2f2f828Seric return buf; 916e2f2f828Seric } 917f36ede03Sbostic 9186c2c3107Seric # else /* DAEMON */ 91999f7cf32Seric /* code for systems without sophisticated networking */ 920444eaf03Seric 921444eaf03Seric /* 922444eaf03Seric ** MYHOSTNAME -- stub version for case of no daemon code. 92321e9914dSeric ** 92421e9914dSeric ** Can't convert to upper case here because might be a UUCP name. 925897f1869Seric ** 926897f1869Seric ** Mark, you can change this to be anything you want...... 927444eaf03Seric */ 928444eaf03Seric 929444eaf03Seric char ** 930897f1869Seric myhostname(hostbuf, size) 931444eaf03Seric char hostbuf[]; 932897f1869Seric int size; 933444eaf03Seric { 934444eaf03Seric register FILE *f; 935444eaf03Seric 936444eaf03Seric hostbuf[0] = '\0'; 937444eaf03Seric f = fopen("/usr/include/whoami", "r"); 938444eaf03Seric if (f != NULL) 939444eaf03Seric { 940897f1869Seric (void) fgets(hostbuf, size, f); 941444eaf03Seric fixcrlf(hostbuf, TRUE); 942444eaf03Seric (void) fclose(f); 943444eaf03Seric } 944444eaf03Seric return (NULL); 945444eaf03Seric } 94699f7cf32Seric /* 947320e0d1cSeric ** GETREALHOSTNAME -- get the real host name asociated with a file descriptor 948320e0d1cSeric ** 949320e0d1cSeric ** Parameters: 950320e0d1cSeric ** fd -- the descriptor 951320e0d1cSeric ** 952320e0d1cSeric ** Returns: 953320e0d1cSeric ** The host name associated with this descriptor, if it can 954320e0d1cSeric ** be determined. 955320e0d1cSeric ** NULL otherwise. 956320e0d1cSeric ** 957320e0d1cSeric ** Side Effects: 958320e0d1cSeric ** none 959320e0d1cSeric */ 960320e0d1cSeric 961320e0d1cSeric char * 962320e0d1cSeric getrealhostname(fd) 963320e0d1cSeric int fd; 964320e0d1cSeric { 965320e0d1cSeric return NULL; 966320e0d1cSeric } 967320e0d1cSeric /* 96899f7cf32Seric ** MAPHOSTNAME -- turn a hostname into canonical form 96999f7cf32Seric ** 97099f7cf32Seric ** Parameters: 97105b57da8Seric ** map -- a pointer to the database map. 97299f7cf32Seric ** hbuf -- a buffer containing a hostname. 97315d084d5Seric ** avp -- a pointer to a (cf file defined) argument vector. 97499f7cf32Seric ** 97599f7cf32Seric ** Returns: 97615d084d5Seric ** mapped host name 977cb452edcSeric ** FALSE otherwise. 97899f7cf32Seric ** 97999f7cf32Seric ** Side Effects: 98099f7cf32Seric ** Looks up the host specified in hbuf. If it is not 98199f7cf32Seric ** the canonical name for that host, replace it with 98299f7cf32Seric ** the canonical name. If the name is unknown, or it 98399f7cf32Seric ** is already the canonical name, leave it unchanged. 98499f7cf32Seric */ 98599f7cf32Seric 98699f7cf32Seric /*ARGSUSED*/ 98715d084d5Seric char * 98805b57da8Seric maphostname(map, hbuf, hbsize, avp) 98905b57da8Seric MAP *map; 99099f7cf32Seric char *hbuf; 99199f7cf32Seric int hbsize; 99215d084d5Seric char **avp; 99399f7cf32Seric { 99415d084d5Seric return NULL; 99599f7cf32Seric } 99699f7cf32Seric 9976c2c3107Seric #endif /* DAEMON */ 998