1939f5b94Sdist /* 20942ea6aSbostic * Copyright (c) 1983 Eric P. Allman 3c9d2fa25Sbostic * Copyright (c) 1988, 1993 4c9d2fa25Sbostic * The Regents of the University of California. All rights reserved. 5da1c6175Sbostic * 63bc94712Sbostic * %sccs.include.redist.c% 7939f5b94Sdist */ 8939f5b94Sdist 97aa493c5Seric #include <errno.h> 106c05f684Sbostic #include "sendmail.h" 117fa39d90Seric 12af5e902cSeric #ifndef lint 13da1c6175Sbostic #ifdef DAEMON 14*e5311662Seric static char sccsid[] = "@(#)daemon.c 8.27 (Berkeley) 12/17/93 (with daemon mode)"; 15d0a9e852Seric #else 16*e5311662Seric static char sccsid[] = "@(#)daemon.c 8.27 (Berkeley) 12/17/93 (without daemon mode)"; 17da1c6175Sbostic #endif 18da1c6175Sbostic #endif /* not lint */ 19da1c6175Sbostic 20da1c6175Sbostic #ifdef DAEMON 21d0a9e852Seric 221c71e510Seric # include <netdb.h> 23af5e902cSeric # include <sys/time.h> 24d8d0a4aeSeric # include <arpa/inet.h> 25d0a9e852Seric 263490b9dfSeric #ifdef NAMED_BIND 273490b9dfSeric # include <arpa/nameser.h> 283490b9dfSeric # include <resolv.h> 293490b9dfSeric #endif 303490b9dfSeric 317fa39d90Seric /* 327fa39d90Seric ** DAEMON.C -- routines to use when running as a daemon. 3347b12ae1Seric ** 3447b12ae1Seric ** This entire file is highly dependent on the 4.2 BSD 3547b12ae1Seric ** interprocess communication primitives. No attempt has 3647b12ae1Seric ** been made to make this file portable to Version 7, 3747b12ae1Seric ** Version 6, MPX files, etc. If you should try such a 3847b12ae1Seric ** thing yourself, I recommend chucking the entire file 3947b12ae1Seric ** and starting from scratch. Basic semantics are: 4047b12ae1Seric ** 4147b12ae1Seric ** getrequests() 4247b12ae1Seric ** Opens a port and initiates a connection. 4347b12ae1Seric ** Returns in a child. Must set InChannel and 4447b12ae1Seric ** OutChannel appropriately. 45b7d7afcbSeric ** clrdaemon() 46b7d7afcbSeric ** Close any open files associated with getting 47b7d7afcbSeric ** the connection; this is used when running the queue, 48b7d7afcbSeric ** etc., to avoid having extra file descriptors during 49b7d7afcbSeric ** the queue run and to avoid confusing the network 50b7d7afcbSeric ** code (if it cares). 51914346b1Seric ** makeconnection(host, port, outfile, infile, usesecureport) 5247b12ae1Seric ** Make a connection to the named host on the given 5347b12ae1Seric ** port. Set *outfile and *infile to the files 5447b12ae1Seric ** appropriate for communication. Returns zero on 5547b12ae1Seric ** success, else an exit status describing the 5647b12ae1Seric ** error. 5708de856eSeric ** host_map_lookup(map, hbuf, avp, pstat) 5805b57da8Seric ** Convert the entry in hbuf into a canonical form. 597fa39d90Seric */ 607fa39d90Seric /* 617fa39d90Seric ** GETREQUESTS -- open mail IPC port and get requests. 627fa39d90Seric ** 637fa39d90Seric ** Parameters: 647fa39d90Seric ** none. 657fa39d90Seric ** 667fa39d90Seric ** Returns: 677fa39d90Seric ** none. 687fa39d90Seric ** 697fa39d90Seric ** Side Effects: 707fa39d90Seric ** Waits until some interesting activity occurs. When 717fa39d90Seric ** it does, a child is created to process it, and the 727fa39d90Seric ** parent waits for completion. Return from this 73147303b1Seric ** routine is always in the child. The file pointers 74147303b1Seric ** "InChannel" and "OutChannel" should be set to point 75147303b1Seric ** to the communication channel. 767fa39d90Seric */ 777fa39d90Seric 78b7d7afcbSeric int DaemonSocket = -1; /* fd describing socket */ 79bfb80540Seric SOCKADDR DaemonAddr; /* socket for incoming */ 80bfc1eaf8Seric int ListenQueueSize = 10; /* size of listen queue */ 81b35447dbSeric int TcpRcvBufferSize = 0; /* size of TCP receive buffer */ 82b35447dbSeric int TcpSndBufferSize = 0; /* size of TCP send buffer */ 831c71e510Seric 847fa39d90Seric getrequests() 857fa39d90Seric { 861c71e510Seric int t; 877868dfc2Seric int on = 1; 8815d084d5Seric bool refusingconnections = TRUE; 890aae1086Seric FILE *pidf; 90dadb8687Seric int socksize; 919b100374Sbostic extern void reapchild(); 92eb889047Seric 93a8268164Seric /* 941c71e510Seric ** Set up the address for the mailer. 95eb889047Seric */ 96eb889047Seric 97bfb80540Seric if (DaemonAddr.sin.sin_family == 0) 98bfb80540Seric DaemonAddr.sin.sin_family = AF_INET; 99bfb80540Seric if (DaemonAddr.sin.sin_addr.s_addr == 0) 100bfb80540Seric DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY; 101bfb80540Seric if (DaemonAddr.sin.sin_port == 0) 102bfb80540Seric { 103*e5311662Seric register struct servent *sp; 104*e5311662Seric 1051c71e510Seric sp = getservbyname("smtp", "tcp"); 1061c71e510Seric if (sp == NULL) 107d0a9e852Seric { 108ad977999Seric syserr("554 service \"smtp\" unknown"); 109*e5311662Seric DaemonAddr.sin.sin_port = htons(25); 1101c71e510Seric } 111*e5311662Seric else 112bfb80540Seric DaemonAddr.sin.sin_port = sp->s_port; 113bfb80540Seric } 1141c71e510Seric 1151c71e510Seric /* 1161c71e510Seric ** Try to actually open the connection. 1171c71e510Seric */ 1181c71e510Seric 1191c71e510Seric if (tTd(15, 1)) 120bfb80540Seric printf("getrequests: port 0x%x\n", DaemonAddr.sin.sin_port); 1211c71e510Seric 1221c71e510Seric /* get a socket for the SMTP connection */ 12398e28903Seric DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0); 124b7d7afcbSeric if (DaemonSocket < 0) 1251c71e510Seric { 1261c71e510Seric /* probably another daemon already */ 1271c71e510Seric syserr("getrequests: can't create socket"); 1281c71e510Seric severe: 129b0ba8827Seric # ifdef LOG 130b0ba8827Seric if (LogLevel > 0) 1310c034190Seric syslog(LOG_ALERT, "problem creating SMTP socket"); 1326c2c3107Seric # endif /* LOG */ 13347b12ae1Seric finis(); 134d0a9e852Seric } 1351b6e4a15Seric 1361b6e4a15Seric /* turn on network debugging? */ 137a2ef5fa4Seric if (tTd(15, 101)) 13852308a50Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on); 1391b6e4a15Seric 1407868dfc2Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on); 1417868dfc2Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof on); 1427868dfc2Seric 14308feafeaSeric #ifdef SO_RCVBUF 14408feafeaSeric if (TcpRcvBufferSize > 0) 14508feafeaSeric { 14608feafeaSeric if (setsockopt(DaemonSocket, SOL_SOCKET, SO_RCVBUF, 147bf217a95Seric (char *) &TcpRcvBufferSize, 14808feafeaSeric sizeof(TcpRcvBufferSize)) < 0) 14908feafeaSeric syserr("getrequests: setsockopt(SO_RCVBUF)"); 15008feafeaSeric } 15108feafeaSeric #endif 15208feafeaSeric 15398e28903Seric switch (DaemonAddr.sa.sa_family) 15498e28903Seric { 15598e28903Seric # ifdef NETINET 15698e28903Seric case AF_INET: 157dadb8687Seric socksize = sizeof DaemonAddr.sin; 15898e28903Seric break; 15998e28903Seric # endif 16098e28903Seric 16198e28903Seric # ifdef NETISO 16298e28903Seric case AF_ISO: 163dadb8687Seric socksize = sizeof DaemonAddr.siso; 16498e28903Seric break; 16598e28903Seric # endif 16698e28903Seric 16798e28903Seric default: 168dadb8687Seric socksize = sizeof DaemonAddr; 16998e28903Seric break; 17098e28903Seric } 17198e28903Seric 172dadb8687Seric if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0) 1731c71e510Seric { 1741c71e510Seric syserr("getrequests: cannot bind"); 175b7d7afcbSeric (void) close(DaemonSocket); 1761c71e510Seric goto severe; 1771c71e510Seric } 1781c71e510Seric 1792b9178d3Seric (void) setsignal(SIGCHLD, reapchild); 18052308a50Seric 1810aae1086Seric /* write the pid to the log file for posterity */ 1820aae1086Seric pidf = fopen(PidFile, "w"); 1830aae1086Seric if (pidf != NULL) 1840aae1086Seric { 18537950f67Seric extern char *CommandLineArgs; 18637950f67Seric 18737950f67Seric /* write the process id on line 1 */ 1880aae1086Seric fprintf(pidf, "%d\n", getpid()); 18937950f67Seric 19037950f67Seric /* line 2 contains all command line flags */ 19137950f67Seric fprintf(pidf, "%s\n", CommandLineArgs); 19237950f67Seric 19337950f67Seric /* flush and close */ 1940aae1086Seric fclose(pidf); 1950aae1086Seric } 1960aae1086Seric 1970aae1086Seric 1981c71e510Seric if (tTd(15, 1)) 199b7d7afcbSeric printf("getrequests: %d\n", DaemonSocket); 2001c71e510Seric 2011c71e510Seric for (;;) 2021c71e510Seric { 2033a099713Seric register int pid; 204a44d5a5eSeric auto int lotherend; 20515d084d5Seric extern bool refuseconnections(); 2063a099713Seric 2073a099713Seric /* see if we are rejecting connections */ 20815d084d5Seric CurrentLA = getla(); 20915d084d5Seric if (refuseconnections()) 2106775ec03Sbostic { 21115d084d5Seric if (!refusingconnections) 21215d084d5Seric { 21315d084d5Seric /* don't queue so peer will fail quickly */ 21415d084d5Seric (void) listen(DaemonSocket, 0); 21515d084d5Seric refusingconnections = TRUE; 21615d084d5Seric } 21771e5e267Seric setproctitle("rejecting connections: load average: %d", 21871e5e267Seric CurrentLA); 2193a099713Seric sleep(5); 22015d084d5Seric continue; 22115d084d5Seric } 22215d084d5Seric 22315d084d5Seric if (refusingconnections) 22415d084d5Seric { 22515d084d5Seric /* start listening again */ 226bfc1eaf8Seric if (listen(DaemonSocket, ListenQueueSize) < 0) 22715d084d5Seric { 22815d084d5Seric syserr("getrequests: cannot listen"); 22915d084d5Seric (void) close(DaemonSocket); 23015d084d5Seric goto severe; 23115d084d5Seric } 23215d084d5Seric setproctitle("accepting connections"); 23315d084d5Seric refusingconnections = FALSE; 2346775ec03Sbostic } 235a44d5a5eSeric 2361c71e510Seric /* wait for a connection */ 2371c71e510Seric do 2381c71e510Seric { 2391c71e510Seric errno = 0; 240dadb8687Seric lotherend = socksize; 2419b100374Sbostic t = accept(DaemonSocket, 2429b100374Sbostic (struct sockaddr *)&RealHostAddr, &lotherend); 2431c71e510Seric } while (t < 0 && errno == EINTR); 2441c71e510Seric if (t < 0) 2451c71e510Seric { 2461c71e510Seric syserr("getrequests: accept"); 2471c71e510Seric sleep(5); 2481c71e510Seric continue; 2491c71e510Seric } 250d0a9e852Seric 251d0a9e852Seric /* 252d0a9e852Seric ** Create a subprocess to process the mail. 253d0a9e852Seric */ 254d0a9e852Seric 25561e4310fSeric if (tTd(15, 2)) 2561c71e510Seric printf("getrequests: forking (fd = %d)\n", t); 257eb889047Seric 258a8268164Seric pid = fork(); 259a8268164Seric if (pid < 0) 260a8268164Seric { 261a8268164Seric syserr("daemon: cannot fork"); 262a8268164Seric sleep(10); 2631c71e510Seric (void) close(t); 264a8268164Seric continue; 265a8268164Seric } 266a8268164Seric 267a8268164Seric if (pid == 0) 268a8268164Seric { 269da662164Seric char *p; 2709f8b0eadSeric extern char *hostnamebyanyaddr(); 271a44d5a5eSeric 272a8268164Seric /* 273a8268164Seric ** CHILD -- return to caller. 274a44d5a5eSeric ** Collect verified idea of sending host. 275a8268164Seric ** Verify calling user id if possible here. 276a8268164Seric */ 277a8268164Seric 2782b9178d3Seric (void) setsignal(SIGCHLD, SIG_DFL); 279e17a3a5aSeric OpMode = MD_SMTP; 280779ac194Seric 281a44d5a5eSeric /* determine host name */ 282da662164Seric p = hostnamebyanyaddr(&RealHostAddr); 283da662164Seric RealHostName = newstr(p); 28429dcf4baSeric 2852a6bc25bSeric #ifdef LOG 2861f2ff1a4Seric if (LogLevel > 11) 2872a6bc25bSeric { 2882a6bc25bSeric /* log connection information */ 2892a6bc25bSeric syslog(LOG_INFO, "connect from %s (%s)", 2909f8b0eadSeric RealHostName, anynet_ntoa(&RealHostAddr)); 2912a6bc25bSeric } 2922a6bc25bSeric #endif 2932a6bc25bSeric 294244b09d1Seric (void) close(DaemonSocket); 295335eae58Seric if ((InChannel = fdopen(t, "r")) == NULL || 296335eae58Seric (t = dup(t)) < 0 || 297335eae58Seric (OutChannel = fdopen(t, "w")) == NULL) 298335eae58Seric { 299335eae58Seric syserr("cannot open SMTP server channel, fd=%d", t); 300335eae58Seric exit(0); 301335eae58Seric } 302244b09d1Seric 30329dcf4baSeric /* should we check for illegal connection here? XXX */ 304e17a3a5aSeric #ifdef XLA 305e17a3a5aSeric if (!xla_host_ok(RealHostName)) 306e17a3a5aSeric { 307244b09d1Seric message("421 Too many SMTP sessions for this host"); 308e17a3a5aSeric exit(0); 309e17a3a5aSeric } 310e17a3a5aSeric #endif 311a44d5a5eSeric 31261e4310fSeric if (tTd(15, 2)) 313d0a9e852Seric printf("getreq: returning\n"); 314a8268164Seric return; 315a8268164Seric } 316a8268164Seric 3173c154354Seric /* close the port so that others will hang (for a while) */ 3183c154354Seric (void) close(t); 3198e3e4b17Seric } 3203c154354Seric /*NOTREACHED*/ 3213c154354Seric } 3228e3e4b17Seric /* 323b7d7afcbSeric ** CLRDAEMON -- reset the daemon connection 324b7d7afcbSeric ** 325b7d7afcbSeric ** Parameters: 326b7d7afcbSeric ** none. 327b7d7afcbSeric ** 328b7d7afcbSeric ** Returns: 329b7d7afcbSeric ** none. 330b7d7afcbSeric ** 331b7d7afcbSeric ** Side Effects: 332b7d7afcbSeric ** releases any resources used by the passive daemon. 333b7d7afcbSeric */ 334b7d7afcbSeric 335b7d7afcbSeric clrdaemon() 336b7d7afcbSeric { 337b7d7afcbSeric if (DaemonSocket >= 0) 338b7d7afcbSeric (void) close(DaemonSocket); 339b7d7afcbSeric DaemonSocket = -1; 340b7d7afcbSeric } 341b7d7afcbSeric /* 342bfb80540Seric ** SETDAEMONOPTIONS -- set options for running the daemon 343bfb80540Seric ** 344bfb80540Seric ** Parameters: 345bfb80540Seric ** p -- the options line. 346bfb80540Seric ** 347bfb80540Seric ** Returns: 348bfb80540Seric ** none. 349bfb80540Seric */ 350bfb80540Seric 351bfb80540Seric setdaemonoptions(p) 352bfb80540Seric register char *p; 353bfb80540Seric { 354850144caSeric if (DaemonAddr.sa.sa_family == AF_UNSPEC) 355850144caSeric DaemonAddr.sa.sa_family = AF_INET; 356850144caSeric 357bfb80540Seric while (p != NULL) 358bfb80540Seric { 359bfb80540Seric register char *f; 360bfb80540Seric register char *v; 361bfb80540Seric 362bfb80540Seric while (isascii(*p) && isspace(*p)) 363bfb80540Seric p++; 364bfb80540Seric if (*p == '\0') 365bfb80540Seric break; 366bfb80540Seric f = p; 367bfb80540Seric p = strchr(p, ','); 368bfb80540Seric if (p != NULL) 369bfb80540Seric *p++ = '\0'; 370bfb80540Seric v = strchr(f, '='); 371bfb80540Seric if (v == NULL) 372bfb80540Seric continue; 373bfb80540Seric while (isascii(*++v) && isspace(*v)) 374bfb80540Seric continue; 375bfb80540Seric 376bfb80540Seric switch (*f) 377bfb80540Seric { 378850144caSeric case 'F': /* address family */ 379850144caSeric if (isascii(*v) && isdigit(*v)) 380850144caSeric DaemonAddr.sa.sa_family = atoi(v); 381850144caSeric #ifdef NETINET 382850144caSeric else if (strcasecmp(v, "inet") == 0) 383850144caSeric DaemonAddr.sa.sa_family = AF_INET; 384850144caSeric #endif 385850144caSeric #ifdef NETISO 386850144caSeric else if (strcasecmp(v, "iso") == 0) 387850144caSeric DaemonAddr.sa.sa_family = AF_ISO; 388850144caSeric #endif 389850144caSeric #ifdef NETNS 390850144caSeric else if (strcasecmp(v, "ns") == 0) 391850144caSeric DaemonAddr.sa.sa_family = AF_NS; 392850144caSeric #endif 393850144caSeric #ifdef NETX25 394850144caSeric else if (strcasecmp(v, "x.25") == 0) 395850144caSeric DaemonAddr.sa.sa_family = AF_CCITT; 396850144caSeric #endif 397850144caSeric else 398850144caSeric syserr("554 Unknown address family %s in Family=option", v); 399850144caSeric break; 400850144caSeric 401850144caSeric case 'A': /* address */ 402850144caSeric switch (DaemonAddr.sa.sa_family) 403850144caSeric { 404850144caSeric #ifdef NETINET 405850144caSeric case AF_INET: 406850144caSeric if (isascii(*v) && isdigit(*v)) 407850144caSeric DaemonAddr.sin.sin_addr.s_addr = inet_network(v); 408850144caSeric else 409850144caSeric { 410850144caSeric register struct netent *np; 411850144caSeric 412850144caSeric np = getnetbyname(v); 413850144caSeric if (np == NULL) 414850144caSeric syserr("554 network \"%s\" unknown", v); 415850144caSeric else 416850144caSeric DaemonAddr.sin.sin_addr.s_addr = np->n_net; 417850144caSeric } 418850144caSeric break; 419850144caSeric #endif 420850144caSeric 421850144caSeric default: 422850144caSeric syserr("554 Address= option unsupported for family %d", 423850144caSeric DaemonAddr.sa.sa_family); 424850144caSeric break; 425850144caSeric } 426850144caSeric break; 427850144caSeric 428bfb80540Seric case 'P': /* port */ 429850144caSeric switch (DaemonAddr.sa.sa_family) 430850144caSeric { 431850144caSeric short port; 432850144caSeric 433850144caSeric #ifdef NETINET 434850144caSeric case AF_INET: 435bfb80540Seric if (isascii(*v) && isdigit(*v)) 43676b70c58Seric DaemonAddr.sin.sin_port = htons(atoi(v)); 437bfb80540Seric else 438bfb80540Seric { 439bfb80540Seric register struct servent *sp; 440bfb80540Seric 441bfb80540Seric sp = getservbyname(v, "tcp"); 442bfb80540Seric if (sp == NULL) 443ad977999Seric syserr("554 service \"%s\" unknown", v); 444bfb80540Seric else 445bfb80540Seric DaemonAddr.sin.sin_port = sp->s_port; 446bfb80540Seric } 447bfb80540Seric break; 448850144caSeric #endif 449bfb80540Seric 450850144caSeric #ifdef NETISO 451850144caSeric case AF_ISO: 452850144caSeric /* assume two byte transport selector */ 453bfb80540Seric if (isascii(*v) && isdigit(*v)) 45476b70c58Seric port = htons(atoi(v)); 455bfb80540Seric else 456bfb80540Seric { 457850144caSeric register struct servent *sp; 458bfb80540Seric 459850144caSeric sp = getservbyname(v, "tcp"); 460850144caSeric if (sp == NULL) 461ad977999Seric syserr("554 service \"%s\" unknown", v); 462bfb80540Seric else 463850144caSeric port = sp->s_port; 464850144caSeric } 465850144caSeric bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2); 466850144caSeric break; 467850144caSeric #endif 468850144caSeric 469850144caSeric default: 470850144caSeric syserr("554 Port= option unsupported for family %d", 471850144caSeric DaemonAddr.sa.sa_family); 472850144caSeric break; 473bfb80540Seric } 474bfb80540Seric break; 475bfc1eaf8Seric 476bfc1eaf8Seric case 'L': /* listen queue size */ 477bfc1eaf8Seric ListenQueueSize = atoi(v); 478bfc1eaf8Seric break; 479b35447dbSeric 480b35447dbSeric case 'S': /* send buffer size */ 481b35447dbSeric TcpSndBufferSize = atoi(v); 482b35447dbSeric break; 483b35447dbSeric 484b35447dbSeric case 'R': /* receive buffer size */ 485b35447dbSeric TcpRcvBufferSize = atoi(v); 486b35447dbSeric break; 487bfb80540Seric } 488bfb80540Seric } 489bfb80540Seric } 490bfb80540Seric /* 4917aa493c5Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 4927aa493c5Seric ** 4937aa493c5Seric ** Parameters: 4947aa493c5Seric ** host -- the name of the host. 49548ff0a9dSeric ** port -- the port number to connect to. 496655feedbSeric ** mci -- a pointer to the mail connection information 497655feedbSeric ** structure to be filled in. 498914346b1Seric ** usesecureport -- if set, use a low numbered (reserved) 499914346b1Seric ** port to provide some rudimentary authentication. 5007aa493c5Seric ** 5017aa493c5Seric ** Returns: 5027aa493c5Seric ** An exit code telling whether the connection could be 5037aa493c5Seric ** made and if not why not. 5047aa493c5Seric ** 5057aa493c5Seric ** Side Effects: 5067aa493c5Seric ** none. 5077aa493c5Seric */ 5087aa493c5Seric 509e2f2f828Seric SOCKADDR CurHostAddr; /* address of current host */ 51071ff6caaSeric 511b31e7f2bSeric int 512655feedbSeric makeconnection(host, port, mci, usesecureport) 5137aa493c5Seric char *host; 514210215eaSeric u_short port; 515b31e7f2bSeric register MCI *mci; 516914346b1Seric bool usesecureport; 5177aa493c5Seric { 51804344589Sbloom register int i, s; 51904344589Sbloom register struct hostent *hp = (struct hostent *)NULL; 520e2f2f828Seric SOCKADDR addr; 5216286bb75Sbloom int sav_errno; 522e2f2f828Seric int addrlen; 523134746fbSeric #ifdef NAMED_BIND 524134746fbSeric extern int h_errno; 525134746fbSeric #endif 5267aa493c5Seric 5277aa493c5Seric /* 5287aa493c5Seric ** Set up the address for the mailer. 52971096d12Seric ** Accept "[a.b.c.d]" syntax for host name. 5307aa493c5Seric */ 5317aa493c5Seric 532134746fbSeric #ifdef NAMED_BIND 533794bdbb9Smiriam h_errno = 0; 534134746fbSeric #endif 535794bdbb9Smiriam errno = 0; 536967778e2Seric bzero(&CurHostAddr, sizeof CurHostAddr); 537c931b82bSeric SmtpPhase = mci->mci_phase = "initial connection"; 538d945ebe8Seric CurHostName = host; 539794bdbb9Smiriam 54071096d12Seric if (host[0] == '[') 54171096d12Seric { 542a44d5a5eSeric long hid; 5436c2c3107Seric register char *p = strchr(host, ']'); 54471096d12Seric 545a44d5a5eSeric if (p != NULL) 54671096d12Seric { 547a44d5a5eSeric *p = '\0'; 5484d9c42c2Seric #ifdef NETINET 549a44d5a5eSeric hid = inet_addr(&host[1]); 550a7e21fe6Seric if (hid == -1) 5514d9c42c2Seric #endif 552a7e21fe6Seric { 553a7e21fe6Seric /* try it as a host name (avoid MX lookup) */ 554a7e21fe6Seric hp = gethostbyname(&host[1]); 555a7e21fe6Seric *p = ']'; 556a7e21fe6Seric goto gothostent; 557a7e21fe6Seric } 558a44d5a5eSeric *p = ']'; 55971096d12Seric } 560a7e21fe6Seric if (p == NULL) 56171096d12Seric { 56208b25121Seric usrerr("553 Invalid numeric domain spec \"%s\"", host); 56371096d12Seric return (EX_NOHOST); 56471096d12Seric } 5654d9c42c2Seric #ifdef NETINET 5664d9c42c2Seric addr.sin.sin_family = AF_INET; /*XXX*/ 56783c1f4bcSeric addr.sin.sin_addr.s_addr = hid; 5684d9c42c2Seric #endif 56971096d12Seric } 5701c71e510Seric else 5711c71e510Seric { 57204344589Sbloom hp = gethostbyname(host); 573a7e21fe6Seric gothostent: 574794bdbb9Smiriam if (hp == NULL) 575794bdbb9Smiriam { 576134746fbSeric #ifdef NAMED_BIND 577794bdbb9Smiriam if (errno == ETIMEDOUT || h_errno == TRY_AGAIN) 57852308a50Seric return (EX_TEMPFAIL); 57982e5d8ddSeric 580134746fbSeric /* if name server is specified, assume temp fail */ 581134746fbSeric if (errno == ECONNREFUSED && UseNameServer) 582134746fbSeric return (EX_TEMPFAIL); 583134746fbSeric #endif 5847aa493c5Seric return (EX_NOHOST); 585794bdbb9Smiriam } 58683c1f4bcSeric addr.sa.sa_family = hp->h_addrtype; 58783c1f4bcSeric switch (hp->h_addrtype) 58883c1f4bcSeric { 58983c1f4bcSeric #ifdef NETINET 59083c1f4bcSeric case AF_INET: 591e2f2f828Seric bcopy(hp->h_addr, 59283c1f4bcSeric &addr.sin.sin_addr, 593859d5010Seric sizeof addr.sin.sin_addr); 59483c1f4bcSeric break; 59583c1f4bcSeric #endif 59683c1f4bcSeric 59783c1f4bcSeric default: 598e2f2f828Seric bcopy(hp->h_addr, 59983c1f4bcSeric addr.sa.sa_data, 600e2f2f828Seric hp->h_length); 60183c1f4bcSeric break; 60283c1f4bcSeric } 60304344589Sbloom i = 1; 6041c71e510Seric } 6051c71e510Seric 6061c71e510Seric /* 6071c71e510Seric ** Determine the port number. 6081c71e510Seric */ 6091c71e510Seric 610fd7c0790Seric if (port != 0) 611e2f2f828Seric port = htons(port); 612fd7c0790Seric else 6131c71e510Seric { 6141c71e510Seric register struct servent *sp = getservbyname("smtp", "tcp"); 6151c71e510Seric 6161c71e510Seric if (sp == NULL) 6171c71e510Seric { 618ad977999Seric syserr("554 makeconnection: service \"smtp\" unknown"); 619*e5311662Seric port = htons(25); 6201c71e510Seric } 621*e5311662Seric else 622e2f2f828Seric port = sp->s_port; 623e2f2f828Seric } 624e2f2f828Seric 62583c1f4bcSeric switch (addr.sa.sa_family) 626e2f2f828Seric { 6274d9c42c2Seric #ifdef NETINET 628e2f2f828Seric case AF_INET: 62983c1f4bcSeric addr.sin.sin_port = port; 630e2f2f828Seric addrlen = sizeof (struct sockaddr_in); 631e2f2f828Seric break; 6324d9c42c2Seric #endif 633e2f2f828Seric 634e2f2f828Seric #ifdef NETISO 635e2f2f828Seric case AF_ISO: 636e2f2f828Seric /* assume two byte transport selector */ 637e2f2f828Seric bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 638e2f2f828Seric addrlen = sizeof (struct sockaddr_iso); 639e2f2f828Seric break; 640e2f2f828Seric #endif 641e2f2f828Seric 642e2f2f828Seric default: 64383c1f4bcSeric syserr("Can't connect to address family %d", addr.sa.sa_family); 644e2f2f828Seric return (EX_NOHOST); 6451c71e510Seric } 6467aa493c5Seric 6477aa493c5Seric /* 6487aa493c5Seric ** Try to actually open the connection. 6497aa493c5Seric */ 6507aa493c5Seric 651e17a3a5aSeric #ifdef XLA 652e17a3a5aSeric /* if too many connections, don't bother trying */ 653e17a3a5aSeric if (!xla_noqueue_ok(host)) 654e17a3a5aSeric return EX_TEMPFAIL; 655e17a3a5aSeric #endif 656e17a3a5aSeric 657aea02ca1Seric for (;;) 658aea02ca1Seric { 65961e4310fSeric if (tTd(16, 1)) 660e2f2f828Seric printf("makeconnection (%s [%s])\n", 661e2f2f828Seric host, anynet_ntoa(&addr)); 6627aa493c5Seric 663226e3022Seric /* save for logging */ 664226e3022Seric CurHostAddr = addr; 665226e3022Seric 666914346b1Seric if (usesecureport) 667914346b1Seric { 668914346b1Seric int rport = IPPORT_RESERVED - 1; 669914346b1Seric 670914346b1Seric s = rresvport(&rport); 671914346b1Seric } 672914346b1Seric else 673914346b1Seric { 674af5e902cSeric s = socket(AF_INET, SOCK_STREAM, 0); 675914346b1Seric } 6767aa493c5Seric if (s < 0) 6777aa493c5Seric { 6786286bb75Sbloom sav_errno = errno; 679914346b1Seric syserr("makeconnection: no socket"); 6807aa493c5Seric goto failure; 6817aa493c5Seric } 6827aa493c5Seric 683b35447dbSeric #ifdef SO_SNDBUF 684b35447dbSeric if (TcpSndBufferSize > 0) 685b35447dbSeric { 686b35447dbSeric if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 687bf217a95Seric (char *) &TcpSndBufferSize, 688b35447dbSeric sizeof(TcpSndBufferSize)) < 0) 689b35447dbSeric syserr("makeconnection: setsockopt(SO_SNDBUF)"); 690b35447dbSeric } 691b35447dbSeric #endif 692b35447dbSeric 69361e4310fSeric if (tTd(16, 1)) 694b31e7f2bSeric printf("makeconnection: fd=%d\n", s); 6951b6e4a15Seric 6961b6e4a15Seric /* turn on network debugging? */ 697a2ef5fa4Seric if (tTd(16, 101)) 69852308a50Seric { 69952308a50Seric int on = 1; 700aea02ca1Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, 701aea02ca1Seric (char *)&on, sizeof on); 70252308a50Seric } 70387d6e633Srick if (CurEnv->e_xfp != NULL) 704877a6142Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 7054bd6a662Seric errno = 0; /* for debugging */ 706e2f2f828Seric if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 707aea02ca1Seric break; 708aea02ca1Seric 709aea02ca1Seric /* couldn't connect.... figure out why */ 7106286bb75Sbloom sav_errno = errno; 7116286bb75Sbloom (void) close(s); 71204344589Sbloom if (hp && hp->h_addr_list[i]) 71304344589Sbloom { 714aea02ca1Seric if (tTd(16, 1)) 715e2f2f828Seric printf("Connect failed (%s); trying new address....\n", 716e2f2f828Seric errstring(sav_errno)); 71783c1f4bcSeric switch (addr.sa.sa_family) 71883c1f4bcSeric { 71983c1f4bcSeric #ifdef NETINET 72083c1f4bcSeric case AF_INET: 721e2f2f828Seric bcopy(hp->h_addr_list[i++], 72283c1f4bcSeric &addr.sin.sin_addr, 723859d5010Seric sizeof addr.sin.sin_addr); 72483c1f4bcSeric break; 72583c1f4bcSeric #endif 72683c1f4bcSeric 72783c1f4bcSeric default: 728e2f2f828Seric bcopy(hp->h_addr_list[i++], 72983c1f4bcSeric addr.sa.sa_data, 730914346b1Seric hp->h_length); 73183c1f4bcSeric break; 73283c1f4bcSeric } 733aea02ca1Seric continue; 73404344589Sbloom } 73504344589Sbloom 7367aa493c5Seric /* failure, decide if temporary or not */ 7377aa493c5Seric failure: 738244b09d1Seric #ifdef XLA 739244b09d1Seric xla_host_end(host); 740244b09d1Seric #endif 741e2de2524Seric if (transienterror(sav_errno)) 742e2de2524Seric return EX_TEMPFAIL; 743e2de2524Seric else 74487d6e633Srick { 74508b25121Seric message("%s", errstring(sav_errno)); 7467aa493c5Seric return (EX_UNAVAILABLE); 7477aa493c5Seric } 7487aa493c5Seric } 7497aa493c5Seric 7507aa493c5Seric /* connection ok, put it into canonical form */ 751335eae58Seric if ((mci->mci_out = fdopen(s, "w")) == NULL || 752335eae58Seric (s = dup(s)) < 0 || 753ab81ee53Seric (mci->mci_in = fdopen(s, "r")) == NULL) 754335eae58Seric { 755335eae58Seric syserr("cannot open SMTP client channel, fd=%d", s); 756335eae58Seric return EX_TEMPFAIL; 757335eae58Seric } 7587aa493c5Seric 759dca8e1f7Seric return (EX_OK); 7607aa493c5Seric } 761444eaf03Seric /* 762444eaf03Seric ** MYHOSTNAME -- return the name of this host. 763444eaf03Seric ** 764444eaf03Seric ** Parameters: 765444eaf03Seric ** hostbuf -- a place to return the name of this host. 766897f1869Seric ** size -- the size of hostbuf. 767444eaf03Seric ** 768444eaf03Seric ** Returns: 769444eaf03Seric ** A list of aliases for this host. 770444eaf03Seric ** 771444eaf03Seric ** Side Effects: 772d8d0a4aeSeric ** Adds numeric codes to $=w. 773444eaf03Seric */ 774444eaf03Seric 775444eaf03Seric char ** 776897f1869Seric myhostname(hostbuf, size) 777444eaf03Seric char hostbuf[]; 778897f1869Seric int size; 779444eaf03Seric { 78038ad259dSeric register struct hostent *hp; 781444eaf03Seric extern struct hostent *gethostbyname(); 782444eaf03Seric 783af5e902cSeric if (gethostname(hostbuf, size) < 0) 784af5e902cSeric { 785af5e902cSeric (void) strcpy(hostbuf, "localhost"); 786af5e902cSeric } 787a44d5a5eSeric hp = gethostbyname(hostbuf); 788a44d5a5eSeric if (hp != NULL) 7897364df9fSeric { 79038ad259dSeric (void) strncpy(hostbuf, hp->h_name, size - 1); 79138ad259dSeric hostbuf[size - 1] = '\0'; 79238ad259dSeric 79338ad259dSeric if (hp->h_addrtype == AF_INET && hp->h_length == 4) 79438ad259dSeric { 79538ad259dSeric register int i; 79638ad259dSeric 797d8d0a4aeSeric for (i = 0; hp->h_addr_list[i] != NULL; i++) 79838ad259dSeric { 799d8d0a4aeSeric char ipbuf[100]; 800d8d0a4aeSeric 801d8d0a4aeSeric sprintf(ipbuf, "[%s]", 802d8d0a4aeSeric inet_ntoa(*((struct in_addr *) hp->h_addr_list[i]))); 803d8d0a4aeSeric setclass('w', ipbuf); 80438ad259dSeric } 80538ad259dSeric } 80638ad259dSeric 807a44d5a5eSeric return (hp->h_aliases); 8087364df9fSeric } 809444eaf03Seric else 810444eaf03Seric return (NULL); 811444eaf03Seric } 812cb452edcSeric /* 8139f8b0eadSeric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 8149f8b0eadSeric ** 8159f8b0eadSeric ** Uses RFC1413 protocol to try to get info from the other end. 816320e0d1cSeric ** 817320e0d1cSeric ** Parameters: 818320e0d1cSeric ** fd -- the descriptor 819320e0d1cSeric ** 820320e0d1cSeric ** Returns: 8219f8b0eadSeric ** The user@host information associated with this descriptor. 822320e0d1cSeric ** 823320e0d1cSeric ** Side Effects: 8249f8b0eadSeric ** Sets RealHostName to the name of the host at the other end. 825320e0d1cSeric */ 826320e0d1cSeric 827c73f2aa4Seric #if IDENTPROTO 8289f8b0eadSeric 8299f8b0eadSeric static jmp_buf CtxAuthTimeout; 8309f8b0eadSeric 8319f8b0eadSeric static 8329f8b0eadSeric authtimeout() 8339f8b0eadSeric { 8349f8b0eadSeric longjmp(CtxAuthTimeout, 1); 8359f8b0eadSeric } 8369f8b0eadSeric 8379f8b0eadSeric #endif 8389f8b0eadSeric 839320e0d1cSeric char * 8409f8b0eadSeric getauthinfo(fd) 841320e0d1cSeric int fd; 842320e0d1cSeric { 8439f8b0eadSeric SOCKADDR fa; 8449f8b0eadSeric int falen; 845a5546e24Seric register char *p; 846c73f2aa4Seric #if IDENTPROTO 8479f8b0eadSeric SOCKADDR la; 8489f8b0eadSeric int lalen; 8499f8b0eadSeric register struct servent *sp; 8509f8b0eadSeric int s; 8519f8b0eadSeric int i; 8529f8b0eadSeric EVENT *ev; 8539f8b0eadSeric #endif 8549f8b0eadSeric static char hbuf[MAXNAME * 2 + 2]; 8559f8b0eadSeric extern char *hostnamebyanyaddr(); 8569f8b0eadSeric extern char RealUserName[]; /* main.c */ 857320e0d1cSeric 8589f8b0eadSeric falen = sizeof fa; 8593940f49dSeric if (getpeername(fd, &fa.sa, &falen) < 0 || falen <= 0 || 8603940f49dSeric fa.sa.sa_family == 0) 8619f8b0eadSeric { 8629f8b0eadSeric RealHostName = "localhost"; 8639f8b0eadSeric (void) sprintf(hbuf, "%s@localhost", RealUserName); 86453853673Seric if (tTd(9, 1)) 8659f8b0eadSeric printf("getauthinfo: %s\n", hbuf); 866320e0d1cSeric return hbuf; 867320e0d1cSeric } 8689f8b0eadSeric 869da662164Seric p = hostnamebyanyaddr(&fa); 870da662164Seric RealHostName = newstr(p); 8719f8b0eadSeric RealHostAddr = fa; 8729f8b0eadSeric 873c73f2aa4Seric #if IDENTPROTO 8749f8b0eadSeric lalen = sizeof la; 8759f8b0eadSeric if (fa.sa.sa_family != AF_INET || 8769f8b0eadSeric getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 8779f8b0eadSeric la.sa.sa_family != AF_INET) 8789f8b0eadSeric { 8799f8b0eadSeric /* no ident info */ 8809f8b0eadSeric goto noident; 8819f8b0eadSeric } 8829f8b0eadSeric 8839f8b0eadSeric /* create ident query */ 884f2d880b6Seric (void) sprintf(hbuf, "%d,%d\r\n", 885f2d880b6Seric ntohs(fa.sin.sin_port), ntohs(la.sin.sin_port)); 8869f8b0eadSeric 8879f8b0eadSeric /* create local address */ 888d6af7dadSeric la.sin.sin_port = 0; 8899f8b0eadSeric 8909f8b0eadSeric /* create foreign address */ 8919f8b0eadSeric sp = getservbyname("auth", "tcp"); 8929f8b0eadSeric if (sp != NULL) 8939f8b0eadSeric fa.sin.sin_port = sp->s_port; 8949f8b0eadSeric else 8951038598cSeric fa.sin.sin_port = htons(113); 8969f8b0eadSeric 8979f8b0eadSeric s = -1; 8989f8b0eadSeric if (setjmp(CtxAuthTimeout) != 0) 8999f8b0eadSeric { 9009f8b0eadSeric if (s >= 0) 9019f8b0eadSeric (void) close(s); 9029f8b0eadSeric goto noident; 9039f8b0eadSeric } 9049f8b0eadSeric 9059f8b0eadSeric /* put a timeout around the whole thing */ 906a0f780efSeric ev = setevent(TimeOuts.to_ident, authtimeout, 0); 9079f8b0eadSeric 908d6af7dadSeric /* connect to foreign IDENT server using same address as SMTP socket */ 9099f8b0eadSeric s = socket(AF_INET, SOCK_STREAM, 0); 9109f8b0eadSeric if (s < 0) 9119f8b0eadSeric { 9129f8b0eadSeric clrevent(ev); 9139f8b0eadSeric goto noident; 9149f8b0eadSeric } 915d6af7dadSeric if (bind(s, &la.sa, sizeof la.sin) < 0 || 916d6af7dadSeric connect(s, &fa.sa, sizeof fa.sin) < 0) 9179f8b0eadSeric { 9189f8b0eadSeric closeident: 9199f8b0eadSeric (void) close(s); 9209f8b0eadSeric clrevent(ev); 9219f8b0eadSeric goto noident; 9229f8b0eadSeric } 9239f8b0eadSeric 92453853673Seric if (tTd(9, 10)) 9259f8b0eadSeric printf("getauthinfo: sent %s", hbuf); 9269f8b0eadSeric 9279f8b0eadSeric /* send query */ 9289f8b0eadSeric if (write(s, hbuf, strlen(hbuf)) < 0) 9299f8b0eadSeric goto closeident; 9309f8b0eadSeric 9319f8b0eadSeric /* get result */ 9329f8b0eadSeric i = read(s, hbuf, sizeof hbuf); 9339f8b0eadSeric (void) close(s); 9349f8b0eadSeric clrevent(ev); 9359f8b0eadSeric if (i <= 0) 9369f8b0eadSeric goto noident; 9379f8b0eadSeric if (hbuf[--i] == '\n' && hbuf[--i] == '\r') 9389f8b0eadSeric i--; 9399f8b0eadSeric hbuf[++i] = '\0'; 9409f8b0eadSeric 94153853673Seric if (tTd(9, 3)) 9429f8b0eadSeric printf("getauthinfo: got %s\n", hbuf); 9439f8b0eadSeric 9449f8b0eadSeric /* parse result */ 9459f8b0eadSeric p = strchr(hbuf, ':'); 9469f8b0eadSeric if (p == NULL) 9479f8b0eadSeric { 9489f8b0eadSeric /* malformed response */ 9499f8b0eadSeric goto noident; 9509f8b0eadSeric } 9519f8b0eadSeric while (isascii(*++p) && isspace(*p)) 9529f8b0eadSeric continue; 9539f8b0eadSeric if (strncasecmp(p, "userid", 6) != 0) 9549f8b0eadSeric { 9559f8b0eadSeric /* presumably an error string */ 9569f8b0eadSeric goto noident; 9579f8b0eadSeric } 9589f8b0eadSeric p += 6; 9599f8b0eadSeric while (isascii(*p) && isspace(*p)) 9609f8b0eadSeric p++; 9619f8b0eadSeric if (*p++ != ':') 9629f8b0eadSeric { 9639f8b0eadSeric /* either useridxx or malformed response */ 9649f8b0eadSeric goto noident; 9659f8b0eadSeric } 9669f8b0eadSeric 9679f8b0eadSeric /* p now points to the OSTYPE field */ 9689f8b0eadSeric p = strchr(p, ':'); 9699f8b0eadSeric if (p == NULL) 9709f8b0eadSeric { 9719f8b0eadSeric /* malformed response */ 9729f8b0eadSeric goto noident; 9739f8b0eadSeric } 97453853673Seric 97553853673Seric /* 1413 says don't do this -- but it's broken otherwise */ 97653853673Seric while (isascii(*++p) && isspace(*p)) 97753853673Seric continue; 9789f8b0eadSeric 9799f8b0eadSeric /* p now points to the authenticated name */ 9809f8b0eadSeric (void) sprintf(hbuf, "%s@%s", p, RealHostName); 98153853673Seric goto finish; 98253853673Seric 98353853673Seric #endif /* IDENTPROTO */ 98453853673Seric 98553853673Seric noident: 98653853673Seric (void) strcpy(hbuf, RealHostName); 98753853673Seric 98853853673Seric finish: 9899f8b0eadSeric if (RealHostName[0] != '[') 9909f8b0eadSeric { 9919f8b0eadSeric p = &hbuf[strlen(hbuf)]; 9929f8b0eadSeric (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr)); 9939f8b0eadSeric } 99453853673Seric if (tTd(9, 1)) 9959f8b0eadSeric printf("getauthinfo: %s\n", hbuf); 9969f8b0eadSeric return hbuf; 9979f8b0eadSeric } 998320e0d1cSeric /* 99908de856eSeric ** HOST_MAP_LOOKUP -- turn a hostname into canonical form 100015d084d5Seric ** 100115d084d5Seric ** Parameters: 100205b57da8Seric ** map -- a pointer to this map (unused). 100308de856eSeric ** name -- the (presumably unqualified) hostname. 100400b385a9Seric ** av -- unused -- for compatibility with other mapping 1005d798a1deSeric ** functions. 10062d29d43aSeric ** statp -- an exit status (out parameter) -- set to 10072d29d43aSeric ** EX_TEMPFAIL if the name server is unavailable. 100815d084d5Seric ** 100915d084d5Seric ** Returns: 101015d084d5Seric ** The mapping, if found. 101115d084d5Seric ** NULL if no mapping found. 101215d084d5Seric ** 101315d084d5Seric ** Side Effects: 101415d084d5Seric ** Looks up the host specified in hbuf. If it is not 101515d084d5Seric ** the canonical name for that host, return the canonical 101615d084d5Seric ** name. 1017f36ede03Sbostic */ 1018cb452edcSeric 101915d084d5Seric char * 102000b385a9Seric host_map_lookup(map, name, av, statp) 102105b57da8Seric MAP *map; 102208de856eSeric char *name; 102300b385a9Seric char **av; 10242d29d43aSeric int *statp; 102599f7cf32Seric { 102699f7cf32Seric register struct hostent *hp; 10275f78836eSmiriam u_long in_addr; 102805b57da8Seric char *cp; 102938ad259dSeric int i; 1030eea91d78Seric register STAB *s; 103192270fb3Seric char *timeoutmsg = "Recipient domain nameserver timed out"; 103200b385a9Seric char hbuf[MAXNAME]; 1033eea91d78Seric extern struct hostent *gethostbyaddr(); 1034eea91d78Seric extern int h_errno; 10355f78836eSmiriam 1036f36ede03Sbostic /* 1037eea91d78Seric ** See if we have already looked up this name. If so, just 1038eea91d78Seric ** return it. 1039eea91d78Seric */ 1040eea91d78Seric 104108de856eSeric s = stab(name, ST_NAMECANON, ST_ENTER); 1042eea91d78Seric if (bitset(NCF_VALID, s->s_namecanon.nc_flags)) 1043eea91d78Seric { 1044f92c3297Seric if (tTd(9, 1)) 104508de856eSeric printf("host_map_lookup(%s) => CACHE %s\n", 104608de856eSeric name, s->s_namecanon.nc_cname); 1047eea91d78Seric errno = s->s_namecanon.nc_errno; 1048eea91d78Seric h_errno = s->s_namecanon.nc_herrno; 1049eea91d78Seric *statp = s->s_namecanon.nc_stat; 105092270fb3Seric if (CurEnv->e_message == NULL && *statp == EX_TEMPFAIL) 105192270fb3Seric CurEnv->e_message = newstr(timeoutmsg); 1052eea91d78Seric return s->s_namecanon.nc_cname; 1053eea91d78Seric } 1054eea91d78Seric 1055eea91d78Seric /* 1056eea91d78Seric ** If first character is a bracket, then it is an address 1057eea91d78Seric ** lookup. Address is copied into a temporary buffer to 105808de856eSeric ** strip the brackets and to preserve name if address is 1059eea91d78Seric ** unknown. 1060f36ede03Sbostic */ 106115d084d5Seric 106208de856eSeric if (*name != '[') 106315d084d5Seric { 1064d798a1deSeric extern bool getcanonname(); 1065d798a1deSeric 10668cb4653dSeric if (tTd(9, 1)) 106708de856eSeric printf("host_map_lookup(%s) => ", name); 1068eea91d78Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 106908de856eSeric (void) strcpy(hbuf, name); 10701f2ff1a4Seric if (getcanonname(hbuf, sizeof hbuf - 1, TRUE)) 10719040ec4fSeric { 10729040ec4fSeric if (tTd(9, 1)) 10739040ec4fSeric printf("%s\n", hbuf); 107400b385a9Seric cp = map_rewrite(map, hbuf, strlen(hbuf), av); 107500b385a9Seric s->s_namecanon.nc_cname = newstr(cp); 107600b385a9Seric return cp; 10779040ec4fSeric } 107815d084d5Seric else 10799040ec4fSeric { 10802d29d43aSeric register struct hostent *hp; 10812d29d43aSeric 10829040ec4fSeric if (tTd(9, 1)) 10832d29d43aSeric printf("FAIL (%d)\n", h_errno); 1084eea91d78Seric s->s_namecanon.nc_errno = errno; 1085eea91d78Seric s->s_namecanon.nc_herrno = h_errno; 10862d29d43aSeric switch (h_errno) 10872d29d43aSeric { 10882d29d43aSeric case TRY_AGAIN: 108989cb2793Seric if (UseNameServer) 10908820d51bSeric { 109192270fb3Seric message(timeoutmsg); 10928820d51bSeric if (CurEnv->e_message == NULL) 109392270fb3Seric CurEnv->e_message = newstr(timeoutmsg); 10948820d51bSeric } 10952d29d43aSeric *statp = EX_TEMPFAIL; 10962d29d43aSeric break; 10972d29d43aSeric 10982d29d43aSeric case HOST_NOT_FOUND: 10992d29d43aSeric *statp = EX_NOHOST; 11002d29d43aSeric break; 11012d29d43aSeric 11022d29d43aSeric case NO_RECOVERY: 11032d29d43aSeric *statp = EX_SOFTWARE; 11042d29d43aSeric break; 11052d29d43aSeric 11062d29d43aSeric default: 11072d29d43aSeric *statp = EX_UNAVAILABLE; 11082d29d43aSeric break; 11092d29d43aSeric } 1110eea91d78Seric s->s_namecanon.nc_stat = *statp; 11112d29d43aSeric if (*statp != EX_TEMPFAIL || UseNameServer) 111215d084d5Seric return NULL; 11132d29d43aSeric 11142d29d43aSeric /* 11152d29d43aSeric ** Try to look it up in /etc/hosts 11162d29d43aSeric */ 11172d29d43aSeric 111808de856eSeric hp = gethostbyname(name); 11192d29d43aSeric if (hp == NULL) 11202d29d43aSeric { 11212d29d43aSeric /* no dice there either */ 1122eea91d78Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 11232d29d43aSeric return NULL; 11242d29d43aSeric } 11252d29d43aSeric 1126eea91d78Seric s->s_namecanon.nc_stat = *statp = EX_OK; 112700b385a9Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 112800b385a9Seric s->s_namecanon.nc_cname = newstr(cp); 112900b385a9Seric return cp; 113015d084d5Seric } 11319040ec4fSeric } 113208de856eSeric if ((cp = strchr(name, ']')) == NULL) 113315d084d5Seric return (NULL); 113434e39927Sbostic *cp = '\0'; 113508de856eSeric in_addr = inet_addr(&name[1]); 113638ad259dSeric 113738ad259dSeric /* nope -- ask the name server */ 113831601fa7Seric hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET); 1139eea91d78Seric s->s_namecanon.nc_errno = errno; 1140eea91d78Seric s->s_namecanon.nc_herrno = h_errno; 1141eea91d78Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 11425f78836eSmiriam if (hp == NULL) 1143eea91d78Seric { 1144eea91d78Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 114515d084d5Seric return (NULL); 1146eea91d78Seric } 114715d084d5Seric 114838ad259dSeric /* found a match -- copy out */ 114900b385a9Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 1150eea91d78Seric s->s_namecanon.nc_stat = *statp = EX_OK; 115100b385a9Seric s->s_namecanon.nc_cname = newstr(cp); 115200b385a9Seric return cp; 115399f7cf32Seric } 1154e2f2f828Seric /* 1155e2f2f828Seric ** ANYNET_NTOA -- convert a network address to printable form. 1156e2f2f828Seric ** 1157e2f2f828Seric ** Parameters: 1158e2f2f828Seric ** sap -- a pointer to a sockaddr structure. 1159e2f2f828Seric ** 1160e2f2f828Seric ** Returns: 1161e2f2f828Seric ** A printable version of that sockaddr. 1162e2f2f828Seric */ 1163e2f2f828Seric 1164e2f2f828Seric char * 1165e2f2f828Seric anynet_ntoa(sap) 1166e2f2f828Seric register SOCKADDR *sap; 1167e2f2f828Seric { 1168e2f2f828Seric register char *bp; 1169e2f2f828Seric register char *ap; 1170e2f2f828Seric int l; 1171e387851eSeric static char buf[100]; 1172e2f2f828Seric 11738cb4653dSeric /* check for null/zero family */ 11748cb4653dSeric if (sap == NULL) 11758cb4653dSeric return "NULLADDR"; 11768cb4653dSeric if (sap->sa.sa_family == 0) 11778cb4653dSeric return "0"; 11788cb4653dSeric 1179e387851eSeric switch (sap->sa.sa_family) 1180e387851eSeric { 1181e387851eSeric #ifdef MAYBENEXTRELEASE /*** UNTESTED *** UNTESTED *** UNTESTED ***/ 1182139b52c8Seric #ifdef NETUNIX 1183e387851eSeric case AF_UNIX: 1184c24cf5a4Seric if (sap->sunix.sun_path[0] != '\0') 1185c24cf5a4Seric sprintf(buf, "[UNIX: %.64s]", sap->sunix.sun_path); 1186e387851eSeric else 1187e387851eSeric sprintf(buf, "[UNIX: localhost]"); 1188e387851eSeric return buf; 1189e387851eSeric #endif 1190139b52c8Seric #endif 1191e387851eSeric 119283c1f4bcSeric #ifdef NETINET 1193e387851eSeric case AF_INET: 1194e2f2f828Seric return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr); 119583c1f4bcSeric #endif 1196e2f2f828Seric 1197e387851eSeric default: 1198e387851eSeric /* this case is only to ensure syntactic correctness */ 1199e387851eSeric break; 1200e387851eSeric } 1201e387851eSeric 1202e2f2f828Seric /* unknown family -- just dump bytes */ 120383c1f4bcSeric (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 1204e2f2f828Seric bp = &buf[strlen(buf)]; 120583c1f4bcSeric ap = sap->sa.sa_data; 120683c1f4bcSeric for (l = sizeof sap->sa.sa_data; --l >= 0; ) 1207e2f2f828Seric { 1208e2f2f828Seric (void) sprintf(bp, "%02x:", *ap++ & 0377); 1209e2f2f828Seric bp += 3; 1210e2f2f828Seric } 1211e2f2f828Seric *--bp = '\0'; 1212e2f2f828Seric return buf; 1213e2f2f828Seric } 12149f8b0eadSeric /* 12159f8b0eadSeric ** HOSTNAMEBYANYADDR -- return name of host based on address 12169f8b0eadSeric ** 12179f8b0eadSeric ** Parameters: 12189f8b0eadSeric ** sap -- SOCKADDR pointer 12199f8b0eadSeric ** 12209f8b0eadSeric ** Returns: 12219f8b0eadSeric ** text representation of host name. 12229f8b0eadSeric ** 12239f8b0eadSeric ** Side Effects: 12249f8b0eadSeric ** none. 12259f8b0eadSeric */ 12269f8b0eadSeric 12279f8b0eadSeric char * 12289f8b0eadSeric hostnamebyanyaddr(sap) 12299f8b0eadSeric register SOCKADDR *sap; 12309f8b0eadSeric { 12319f8b0eadSeric register struct hostent *hp; 12323490b9dfSeric int saveretry; 12333490b9dfSeric 1234e387851eSeric #ifdef NAMED_BIND 12353490b9dfSeric /* shorten name server timeout to avoid higher level timeouts */ 12363490b9dfSeric saveretry = _res.retry; 12373490b9dfSeric _res.retry = 3; 12383490b9dfSeric #endif /* NAMED_BIND */ 12393490b9dfSeric 12409f8b0eadSeric switch (sap->sa.sa_family) 12419f8b0eadSeric { 12429f8b0eadSeric #ifdef NETINET 12439f8b0eadSeric case AF_INET: 12449f8b0eadSeric hp = gethostbyaddr((char *) &sap->sin.sin_addr, 12459f8b0eadSeric sizeof sap->sin.sin_addr, 12469f8b0eadSeric AF_INET); 12479f8b0eadSeric break; 12489f8b0eadSeric #endif 12499f8b0eadSeric 12509f8b0eadSeric #ifdef NETISO 12519f8b0eadSeric case AF_ISO: 12529f8b0eadSeric hp = gethostbyaddr((char *) &sap->siso.siso_addr, 12539f8b0eadSeric sizeof sap->siso.siso_addr, 12549f8b0eadSeric AF_ISO); 12559f8b0eadSeric break; 12569f8b0eadSeric #endif 12579f8b0eadSeric 1258e387851eSeric #ifdef MAYBENEXTRELEASE /*** UNTESTED *** UNTESTED *** UNTESTED ***/ 1259e387851eSeric case AF_UNIX: 1260e387851eSeric hp = NULL; 1261e387851eSeric break; 1262e387851eSeric #endif 1263e387851eSeric 12649f8b0eadSeric default: 12659f8b0eadSeric hp = gethostbyaddr(sap->sa.sa_data, 12669f8b0eadSeric sizeof sap->sa.sa_data, 12679f8b0eadSeric sap->sa.sa_family); 12689f8b0eadSeric break; 12699f8b0eadSeric } 12709f8b0eadSeric 12713490b9dfSeric #ifdef NAMED_BIND 12723490b9dfSeric _res.retry = saveretry; 12733490b9dfSeric #endif /* NAMED_BIND */ 12743490b9dfSeric 12759f8b0eadSeric if (hp != NULL) 12769f8b0eadSeric return hp->h_name; 12779f8b0eadSeric else 12789f8b0eadSeric { 12799f8b0eadSeric /* produce a dotted quad */ 12809f8b0eadSeric static char buf[512]; 12819f8b0eadSeric 12829f8b0eadSeric (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 12839f8b0eadSeric return buf; 12849f8b0eadSeric } 12859f8b0eadSeric } 1286f36ede03Sbostic 12876c2c3107Seric # else /* DAEMON */ 128899f7cf32Seric /* code for systems without sophisticated networking */ 1289444eaf03Seric 1290444eaf03Seric /* 1291444eaf03Seric ** MYHOSTNAME -- stub version for case of no daemon code. 129221e9914dSeric ** 129321e9914dSeric ** Can't convert to upper case here because might be a UUCP name. 1294897f1869Seric ** 1295897f1869Seric ** Mark, you can change this to be anything you want...... 1296444eaf03Seric */ 1297444eaf03Seric 1298444eaf03Seric char ** 1299897f1869Seric myhostname(hostbuf, size) 1300444eaf03Seric char hostbuf[]; 1301897f1869Seric int size; 1302444eaf03Seric { 1303444eaf03Seric register FILE *f; 1304444eaf03Seric 1305444eaf03Seric hostbuf[0] = '\0'; 1306444eaf03Seric f = fopen("/usr/include/whoami", "r"); 1307444eaf03Seric if (f != NULL) 1308444eaf03Seric { 1309897f1869Seric (void) fgets(hostbuf, size, f); 1310444eaf03Seric fixcrlf(hostbuf, TRUE); 1311444eaf03Seric (void) fclose(f); 1312444eaf03Seric } 1313444eaf03Seric return (NULL); 1314444eaf03Seric } 131599f7cf32Seric /* 13169f8b0eadSeric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 1317320e0d1cSeric ** 1318320e0d1cSeric ** Parameters: 1319320e0d1cSeric ** fd -- the descriptor 1320320e0d1cSeric ** 1321320e0d1cSeric ** Returns: 1322320e0d1cSeric ** The host name associated with this descriptor, if it can 1323320e0d1cSeric ** be determined. 1324320e0d1cSeric ** NULL otherwise. 1325320e0d1cSeric ** 1326320e0d1cSeric ** Side Effects: 1327320e0d1cSeric ** none 1328320e0d1cSeric */ 1329320e0d1cSeric 1330320e0d1cSeric char * 13319f8b0eadSeric getauthinfo(fd) 1332320e0d1cSeric int fd; 1333320e0d1cSeric { 1334320e0d1cSeric return NULL; 1335320e0d1cSeric } 1336320e0d1cSeric /* 133799f7cf32Seric ** MAPHOSTNAME -- turn a hostname into canonical form 133899f7cf32Seric ** 133999f7cf32Seric ** Parameters: 134005b57da8Seric ** map -- a pointer to the database map. 134108de856eSeric ** name -- a buffer containing a hostname. 134215d084d5Seric ** avp -- a pointer to a (cf file defined) argument vector. 13432d29d43aSeric ** statp -- an exit status (out parameter). 134499f7cf32Seric ** 134599f7cf32Seric ** Returns: 134615d084d5Seric ** mapped host name 1347cb452edcSeric ** FALSE otherwise. 134899f7cf32Seric ** 134999f7cf32Seric ** Side Effects: 135008de856eSeric ** Looks up the host specified in name. If it is not 135199f7cf32Seric ** the canonical name for that host, replace it with 135299f7cf32Seric ** the canonical name. If the name is unknown, or it 135399f7cf32Seric ** is already the canonical name, leave it unchanged. 135499f7cf32Seric */ 135599f7cf32Seric 135699f7cf32Seric /*ARGSUSED*/ 135715d084d5Seric char * 135808de856eSeric host_map_lookup(map, name, avp, statp) 135905b57da8Seric MAP *map; 136008de856eSeric char *name; 136115d084d5Seric char **avp; 13622d29d43aSeric char *statp; 136399f7cf32Seric { 13642d29d43aSeric register struct hostent *hp; 13652d29d43aSeric 136608de856eSeric hp = gethostbyname(name); 13672d29d43aSeric if (hp != NULL) 13682d29d43aSeric return hp->h_name; 13692d29d43aSeric *statp = EX_NOHOST; 137015d084d5Seric return NULL; 137199f7cf32Seric } 137299f7cf32Seric 13736c2c3107Seric #endif /* DAEMON */ 1374