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*747df804Seric static char sccsid[] = "@(#)daemon.c 8.41 (Berkeley) 04/13/94 (with daemon mode)"; 15d0a9e852Seric #else 16*747df804Seric static char sccsid[] = "@(#)daemon.c 8.41 (Berkeley) 04/13/94 (without daemon mode)"; 17da1c6175Sbostic #endif 18da1c6175Sbostic #endif /* not lint */ 19da1c6175Sbostic 20da1c6175Sbostic #ifdef DAEMON 21d0a9e852Seric 221c71e510Seric # include <netdb.h> 23d8d0a4aeSeric # include <arpa/inet.h> 24d0a9e852Seric 259d4a8008Seric #if NAMED_BIND 263490b9dfSeric # include <arpa/nameser.h> 273490b9dfSeric # include <resolv.h> 283490b9dfSeric #endif 293490b9dfSeric 307fa39d90Seric /* 317fa39d90Seric ** DAEMON.C -- routines to use when running as a daemon. 3247b12ae1Seric ** 3347b12ae1Seric ** This entire file is highly dependent on the 4.2 BSD 3447b12ae1Seric ** interprocess communication primitives. No attempt has 3547b12ae1Seric ** been made to make this file portable to Version 7, 3647b12ae1Seric ** Version 6, MPX files, etc. If you should try such a 3747b12ae1Seric ** thing yourself, I recommend chucking the entire file 3847b12ae1Seric ** and starting from scratch. Basic semantics are: 3947b12ae1Seric ** 4047b12ae1Seric ** getrequests() 4147b12ae1Seric ** Opens a port and initiates a connection. 4247b12ae1Seric ** Returns in a child. Must set InChannel and 4347b12ae1Seric ** OutChannel appropriately. 44b7d7afcbSeric ** clrdaemon() 45b7d7afcbSeric ** Close any open files associated with getting 46b7d7afcbSeric ** the connection; this is used when running the queue, 47b7d7afcbSeric ** etc., to avoid having extra file descriptors during 48b7d7afcbSeric ** the queue run and to avoid confusing the network 49b7d7afcbSeric ** code (if it cares). 50914346b1Seric ** makeconnection(host, port, outfile, infile, usesecureport) 5147b12ae1Seric ** Make a connection to the named host on the given 5247b12ae1Seric ** port. Set *outfile and *infile to the files 5347b12ae1Seric ** appropriate for communication. Returns zero on 5447b12ae1Seric ** success, else an exit status describing the 5547b12ae1Seric ** error. 5608de856eSeric ** host_map_lookup(map, hbuf, avp, pstat) 5705b57da8Seric ** Convert the entry in hbuf into a canonical form. 587fa39d90Seric */ 597fa39d90Seric /* 607fa39d90Seric ** GETREQUESTS -- open mail IPC port and get requests. 617fa39d90Seric ** 627fa39d90Seric ** Parameters: 637fa39d90Seric ** none. 647fa39d90Seric ** 657fa39d90Seric ** Returns: 667fa39d90Seric ** none. 677fa39d90Seric ** 687fa39d90Seric ** Side Effects: 697fa39d90Seric ** Waits until some interesting activity occurs. When 707fa39d90Seric ** it does, a child is created to process it, and the 717fa39d90Seric ** parent waits for completion. Return from this 72147303b1Seric ** routine is always in the child. The file pointers 73147303b1Seric ** "InChannel" and "OutChannel" should be set to point 74147303b1Seric ** to the communication channel. 757fa39d90Seric */ 767fa39d90Seric 77b7d7afcbSeric int DaemonSocket = -1; /* fd describing socket */ 78bfb80540Seric SOCKADDR DaemonAddr; /* socket for incoming */ 79bfc1eaf8Seric int ListenQueueSize = 10; /* size of listen queue */ 80b35447dbSeric int TcpRcvBufferSize = 0; /* size of TCP receive buffer */ 81b35447dbSeric int TcpSndBufferSize = 0; /* size of TCP send buffer */ 821c71e510Seric 837fa39d90Seric getrequests() 847fa39d90Seric { 851c71e510Seric int t; 867868dfc2Seric int on = 1; 8715d084d5Seric bool refusingconnections = TRUE; 880aae1086Seric FILE *pidf; 89dadb8687Seric int socksize; 909b100374Sbostic extern void reapchild(); 91eb889047Seric 92a8268164Seric /* 931c71e510Seric ** Set up the address for the mailer. 94eb889047Seric */ 95eb889047Seric 96bfb80540Seric if (DaemonAddr.sin.sin_family == 0) 97bfb80540Seric DaemonAddr.sin.sin_family = AF_INET; 98bfb80540Seric if (DaemonAddr.sin.sin_addr.s_addr == 0) 99bfb80540Seric DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY; 100bfb80540Seric if (DaemonAddr.sin.sin_port == 0) 101bfb80540Seric { 102e5311662Seric register struct servent *sp; 103e5311662Seric 1041c71e510Seric sp = getservbyname("smtp", "tcp"); 1051c71e510Seric if (sp == NULL) 106d0a9e852Seric { 107ad977999Seric syserr("554 service \"smtp\" unknown"); 108e5311662Seric DaemonAddr.sin.sin_port = htons(25); 1091c71e510Seric } 110e5311662Seric else 111bfb80540Seric DaemonAddr.sin.sin_port = sp->s_port; 112bfb80540Seric } 1131c71e510Seric 1141c71e510Seric /* 1151c71e510Seric ** Try to actually open the connection. 1161c71e510Seric */ 1171c71e510Seric 1181c71e510Seric if (tTd(15, 1)) 119bfb80540Seric printf("getrequests: port 0x%x\n", DaemonAddr.sin.sin_port); 1201c71e510Seric 1211c71e510Seric /* get a socket for the SMTP connection */ 12298e28903Seric DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0); 123b7d7afcbSeric if (DaemonSocket < 0) 1241c71e510Seric { 1251c71e510Seric /* probably another daemon already */ 1261c71e510Seric syserr("getrequests: can't create socket"); 1271c71e510Seric severe: 128b0ba8827Seric # ifdef LOG 129b0ba8827Seric if (LogLevel > 0) 1300c034190Seric syslog(LOG_ALERT, "problem creating SMTP socket"); 1316c2c3107Seric # endif /* LOG */ 13247b12ae1Seric finis(); 133d0a9e852Seric } 1341b6e4a15Seric 1351b6e4a15Seric /* turn on network debugging? */ 136a2ef5fa4Seric if (tTd(15, 101)) 13752308a50Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on); 1381b6e4a15Seric 1397868dfc2Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on); 1407868dfc2Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof on); 1417868dfc2Seric 14208feafeaSeric #ifdef SO_RCVBUF 14308feafeaSeric if (TcpRcvBufferSize > 0) 14408feafeaSeric { 14508feafeaSeric if (setsockopt(DaemonSocket, SOL_SOCKET, SO_RCVBUF, 146bf217a95Seric (char *) &TcpRcvBufferSize, 14708feafeaSeric sizeof(TcpRcvBufferSize)) < 0) 14808feafeaSeric syserr("getrequests: setsockopt(SO_RCVBUF)"); 14908feafeaSeric } 15008feafeaSeric #endif 15108feafeaSeric 15298e28903Seric switch (DaemonAddr.sa.sa_family) 15398e28903Seric { 15498e28903Seric # ifdef NETINET 15598e28903Seric case AF_INET: 156dadb8687Seric socksize = sizeof DaemonAddr.sin; 15798e28903Seric break; 15898e28903Seric # endif 15998e28903Seric 16098e28903Seric # ifdef NETISO 16198e28903Seric case AF_ISO: 162dadb8687Seric socksize = sizeof DaemonAddr.siso; 16398e28903Seric break; 16498e28903Seric # endif 16598e28903Seric 16698e28903Seric default: 167dadb8687Seric socksize = sizeof DaemonAddr; 16898e28903Seric break; 16998e28903Seric } 17098e28903Seric 171dadb8687Seric if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0) 1721c71e510Seric { 1731c71e510Seric syserr("getrequests: cannot bind"); 174b7d7afcbSeric (void) close(DaemonSocket); 1751c71e510Seric goto severe; 1761c71e510Seric } 1771c71e510Seric 1782b9178d3Seric (void) setsignal(SIGCHLD, reapchild); 17952308a50Seric 1800aae1086Seric /* write the pid to the log file for posterity */ 1810aae1086Seric pidf = fopen(PidFile, "w"); 1820aae1086Seric if (pidf != NULL) 1830aae1086Seric { 18437950f67Seric extern char *CommandLineArgs; 18537950f67Seric 18637950f67Seric /* write the process id on line 1 */ 1870aae1086Seric fprintf(pidf, "%d\n", getpid()); 18837950f67Seric 18937950f67Seric /* line 2 contains all command line flags */ 19037950f67Seric fprintf(pidf, "%s\n", CommandLineArgs); 19137950f67Seric 19237950f67Seric /* flush and close */ 1930aae1086Seric fclose(pidf); 1940aae1086Seric } 1950aae1086Seric 1960aae1086Seric 1971c71e510Seric if (tTd(15, 1)) 198b7d7afcbSeric printf("getrequests: %d\n", DaemonSocket); 1991c71e510Seric 2001c71e510Seric for (;;) 2011c71e510Seric { 2023a099713Seric register int pid; 203a44d5a5eSeric auto int lotherend; 20415d084d5Seric extern bool refuseconnections(); 2053a099713Seric 2063a099713Seric /* see if we are rejecting connections */ 20715d084d5Seric CurrentLA = getla(); 20815d084d5Seric if (refuseconnections()) 2096775ec03Sbostic { 21015d084d5Seric if (!refusingconnections) 21115d084d5Seric { 21215d084d5Seric /* don't queue so peer will fail quickly */ 21315d084d5Seric (void) listen(DaemonSocket, 0); 21415d084d5Seric refusingconnections = TRUE; 21515d084d5Seric } 21671e5e267Seric setproctitle("rejecting connections: load average: %d", 21771e5e267Seric CurrentLA); 2183a099713Seric sleep(5); 21915d084d5Seric continue; 22015d084d5Seric } 22115d084d5Seric 22215d084d5Seric if (refusingconnections) 22315d084d5Seric { 22415d084d5Seric /* start listening again */ 225bfc1eaf8Seric if (listen(DaemonSocket, ListenQueueSize) < 0) 22615d084d5Seric { 22715d084d5Seric syserr("getrequests: cannot listen"); 22815d084d5Seric (void) close(DaemonSocket); 22915d084d5Seric goto severe; 23015d084d5Seric } 23115d084d5Seric setproctitle("accepting connections"); 23215d084d5Seric refusingconnections = FALSE; 2336775ec03Sbostic } 234a44d5a5eSeric 2351c71e510Seric /* wait for a connection */ 2361c71e510Seric do 2371c71e510Seric { 2381c71e510Seric errno = 0; 239dadb8687Seric lotherend = socksize; 2409b100374Sbostic t = accept(DaemonSocket, 2419b100374Sbostic (struct sockaddr *)&RealHostAddr, &lotherend); 2421c71e510Seric } while (t < 0 && errno == EINTR); 2431c71e510Seric if (t < 0) 2441c71e510Seric { 2451c71e510Seric syserr("getrequests: accept"); 2461c71e510Seric sleep(5); 2471c71e510Seric continue; 2481c71e510Seric } 249d0a9e852Seric 250d0a9e852Seric /* 251d0a9e852Seric ** Create a subprocess to process the mail. 252d0a9e852Seric */ 253d0a9e852Seric 25461e4310fSeric if (tTd(15, 2)) 2551c71e510Seric printf("getrequests: forking (fd = %d)\n", t); 256eb889047Seric 257a8268164Seric pid = fork(); 258a8268164Seric if (pid < 0) 259a8268164Seric { 260a8268164Seric syserr("daemon: cannot fork"); 261a8268164Seric sleep(10); 2621c71e510Seric (void) close(t); 263a8268164Seric continue; 264a8268164Seric } 265a8268164Seric 266a8268164Seric if (pid == 0) 267a8268164Seric { 268da662164Seric char *p; 2699f8b0eadSeric extern char *hostnamebyanyaddr(); 270a44d5a5eSeric 271a8268164Seric /* 272a8268164Seric ** CHILD -- return to caller. 273a44d5a5eSeric ** Collect verified idea of sending host. 274a8268164Seric ** Verify calling user id if possible here. 275a8268164Seric */ 276a8268164Seric 2772b9178d3Seric (void) setsignal(SIGCHLD, SIG_DFL); 2789f9b003eSeric DisConnected = FALSE; 279779ac194Seric 2804dd09a90Seric setproctitle("startup with %s", 2814dd09a90Seric anynet_ntoa(&RealHostAddr)); 2824dd09a90Seric 283a44d5a5eSeric /* determine host name */ 284da662164Seric p = hostnamebyanyaddr(&RealHostAddr); 285da662164Seric RealHostName = newstr(p); 2864dd09a90Seric setproctitle("startup with %s", p); 28729dcf4baSeric 2882a6bc25bSeric #ifdef LOG 2891f2ff1a4Seric if (LogLevel > 11) 2902a6bc25bSeric { 2912a6bc25bSeric /* log connection information */ 2922a6bc25bSeric syslog(LOG_INFO, "connect from %s (%s)", 2939f8b0eadSeric RealHostName, anynet_ntoa(&RealHostAddr)); 2942a6bc25bSeric } 2952a6bc25bSeric #endif 2962a6bc25bSeric 297244b09d1Seric (void) close(DaemonSocket); 298335eae58Seric if ((InChannel = fdopen(t, "r")) == NULL || 299335eae58Seric (t = dup(t)) < 0 || 300335eae58Seric (OutChannel = fdopen(t, "w")) == NULL) 301335eae58Seric { 302335eae58Seric syserr("cannot open SMTP server channel, fd=%d", t); 303335eae58Seric exit(0); 304335eae58Seric } 305244b09d1Seric 30629dcf4baSeric /* should we check for illegal connection here? XXX */ 307e17a3a5aSeric #ifdef XLA 308e17a3a5aSeric if (!xla_host_ok(RealHostName)) 309e17a3a5aSeric { 310244b09d1Seric message("421 Too many SMTP sessions for this host"); 311e17a3a5aSeric exit(0); 312e17a3a5aSeric } 313e17a3a5aSeric #endif 314a44d5a5eSeric 31561e4310fSeric if (tTd(15, 2)) 316d0a9e852Seric printf("getreq: returning\n"); 317a8268164Seric return; 318a8268164Seric } 319a8268164Seric 3203c154354Seric /* close the port so that others will hang (for a while) */ 3213c154354Seric (void) close(t); 3228e3e4b17Seric } 3233c154354Seric /*NOTREACHED*/ 3243c154354Seric } 3258e3e4b17Seric /* 326b7d7afcbSeric ** CLRDAEMON -- reset the daemon connection 327b7d7afcbSeric ** 328b7d7afcbSeric ** Parameters: 329b7d7afcbSeric ** none. 330b7d7afcbSeric ** 331b7d7afcbSeric ** Returns: 332b7d7afcbSeric ** none. 333b7d7afcbSeric ** 334b7d7afcbSeric ** Side Effects: 335b7d7afcbSeric ** releases any resources used by the passive daemon. 336b7d7afcbSeric */ 337b7d7afcbSeric 338b7d7afcbSeric clrdaemon() 339b7d7afcbSeric { 340b7d7afcbSeric if (DaemonSocket >= 0) 341b7d7afcbSeric (void) close(DaemonSocket); 342b7d7afcbSeric DaemonSocket = -1; 343b7d7afcbSeric } 344b7d7afcbSeric /* 345bfb80540Seric ** SETDAEMONOPTIONS -- set options for running the daemon 346bfb80540Seric ** 347bfb80540Seric ** Parameters: 348bfb80540Seric ** p -- the options line. 349bfb80540Seric ** 350bfb80540Seric ** Returns: 351bfb80540Seric ** none. 352bfb80540Seric */ 353bfb80540Seric 354bfb80540Seric setdaemonoptions(p) 355bfb80540Seric register char *p; 356bfb80540Seric { 357850144caSeric if (DaemonAddr.sa.sa_family == AF_UNSPEC) 358850144caSeric DaemonAddr.sa.sa_family = AF_INET; 359850144caSeric 360bfb80540Seric while (p != NULL) 361bfb80540Seric { 362bfb80540Seric register char *f; 363bfb80540Seric register char *v; 364bfb80540Seric 365bfb80540Seric while (isascii(*p) && isspace(*p)) 366bfb80540Seric p++; 367bfb80540Seric if (*p == '\0') 368bfb80540Seric break; 369bfb80540Seric f = p; 370bfb80540Seric p = strchr(p, ','); 371bfb80540Seric if (p != NULL) 372bfb80540Seric *p++ = '\0'; 373bfb80540Seric v = strchr(f, '='); 374bfb80540Seric if (v == NULL) 375bfb80540Seric continue; 376bfb80540Seric while (isascii(*++v) && isspace(*v)) 377bfb80540Seric continue; 378bfb80540Seric 379bfb80540Seric switch (*f) 380bfb80540Seric { 381850144caSeric case 'F': /* address family */ 382850144caSeric if (isascii(*v) && isdigit(*v)) 383850144caSeric DaemonAddr.sa.sa_family = atoi(v); 384850144caSeric #ifdef NETINET 385850144caSeric else if (strcasecmp(v, "inet") == 0) 386850144caSeric DaemonAddr.sa.sa_family = AF_INET; 387850144caSeric #endif 388850144caSeric #ifdef NETISO 389850144caSeric else if (strcasecmp(v, "iso") == 0) 390850144caSeric DaemonAddr.sa.sa_family = AF_ISO; 391850144caSeric #endif 392850144caSeric #ifdef NETNS 393850144caSeric else if (strcasecmp(v, "ns") == 0) 394850144caSeric DaemonAddr.sa.sa_family = AF_NS; 395850144caSeric #endif 396850144caSeric #ifdef NETX25 397850144caSeric else if (strcasecmp(v, "x.25") == 0) 398850144caSeric DaemonAddr.sa.sa_family = AF_CCITT; 399850144caSeric #endif 400850144caSeric else 401850144caSeric syserr("554 Unknown address family %s in Family=option", v); 402850144caSeric break; 403850144caSeric 404850144caSeric case 'A': /* address */ 405850144caSeric switch (DaemonAddr.sa.sa_family) 406850144caSeric { 407850144caSeric #ifdef NETINET 408850144caSeric case AF_INET: 409850144caSeric if (isascii(*v) && isdigit(*v)) 410850144caSeric DaemonAddr.sin.sin_addr.s_addr = inet_network(v); 411850144caSeric else 412850144caSeric { 413850144caSeric register struct netent *np; 414850144caSeric 415850144caSeric np = getnetbyname(v); 416850144caSeric if (np == NULL) 417850144caSeric syserr("554 network \"%s\" unknown", v); 418850144caSeric else 419850144caSeric DaemonAddr.sin.sin_addr.s_addr = np->n_net; 420850144caSeric } 421850144caSeric break; 422850144caSeric #endif 423850144caSeric 424850144caSeric default: 425850144caSeric syserr("554 Address= option unsupported for family %d", 426850144caSeric DaemonAddr.sa.sa_family); 427850144caSeric break; 428850144caSeric } 429850144caSeric break; 430850144caSeric 431bfb80540Seric case 'P': /* port */ 432850144caSeric switch (DaemonAddr.sa.sa_family) 433850144caSeric { 434850144caSeric short port; 435850144caSeric 436850144caSeric #ifdef NETINET 437850144caSeric case AF_INET: 438bfb80540Seric if (isascii(*v) && isdigit(*v)) 43976b70c58Seric DaemonAddr.sin.sin_port = htons(atoi(v)); 440bfb80540Seric else 441bfb80540Seric { 442bfb80540Seric register struct servent *sp; 443bfb80540Seric 444bfb80540Seric sp = getservbyname(v, "tcp"); 445bfb80540Seric if (sp == NULL) 446ad977999Seric syserr("554 service \"%s\" unknown", v); 447bfb80540Seric else 448bfb80540Seric DaemonAddr.sin.sin_port = sp->s_port; 449bfb80540Seric } 450bfb80540Seric break; 451850144caSeric #endif 452bfb80540Seric 453850144caSeric #ifdef NETISO 454850144caSeric case AF_ISO: 455850144caSeric /* assume two byte transport selector */ 456bfb80540Seric if (isascii(*v) && isdigit(*v)) 45776b70c58Seric port = htons(atoi(v)); 458bfb80540Seric else 459bfb80540Seric { 460850144caSeric register struct servent *sp; 461bfb80540Seric 462850144caSeric sp = getservbyname(v, "tcp"); 463850144caSeric if (sp == NULL) 464ad977999Seric syserr("554 service \"%s\" unknown", v); 465bfb80540Seric else 466850144caSeric port = sp->s_port; 467850144caSeric } 468850144caSeric bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2); 469850144caSeric break; 470850144caSeric #endif 471850144caSeric 472850144caSeric default: 473850144caSeric syserr("554 Port= option unsupported for family %d", 474850144caSeric DaemonAddr.sa.sa_family); 475850144caSeric break; 476bfb80540Seric } 477bfb80540Seric break; 478bfc1eaf8Seric 479bfc1eaf8Seric case 'L': /* listen queue size */ 480bfc1eaf8Seric ListenQueueSize = atoi(v); 481bfc1eaf8Seric break; 482b35447dbSeric 483b35447dbSeric case 'S': /* send buffer size */ 484b35447dbSeric TcpSndBufferSize = atoi(v); 485b35447dbSeric break; 486b35447dbSeric 487b35447dbSeric case 'R': /* receive buffer size */ 488b35447dbSeric TcpRcvBufferSize = atoi(v); 489b35447dbSeric break; 490bfb80540Seric } 491bfb80540Seric } 492bfb80540Seric } 493bfb80540Seric /* 4947aa493c5Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 4957aa493c5Seric ** 4967aa493c5Seric ** Parameters: 4977aa493c5Seric ** host -- the name of the host. 49848ff0a9dSeric ** port -- the port number to connect to. 499655feedbSeric ** mci -- a pointer to the mail connection information 500655feedbSeric ** structure to be filled in. 501914346b1Seric ** usesecureport -- if set, use a low numbered (reserved) 502914346b1Seric ** port to provide some rudimentary authentication. 5037aa493c5Seric ** 5047aa493c5Seric ** Returns: 5057aa493c5Seric ** An exit code telling whether the connection could be 5067aa493c5Seric ** made and if not why not. 5077aa493c5Seric ** 5087aa493c5Seric ** Side Effects: 5097aa493c5Seric ** none. 5107aa493c5Seric */ 5117aa493c5Seric 512e2f2f828Seric SOCKADDR CurHostAddr; /* address of current host */ 51371ff6caaSeric 514b31e7f2bSeric int 515655feedbSeric makeconnection(host, port, mci, usesecureport) 5167aa493c5Seric char *host; 517210215eaSeric u_short port; 518b31e7f2bSeric register MCI *mci; 519914346b1Seric bool usesecureport; 5207aa493c5Seric { 52104344589Sbloom register int i, s; 52204344589Sbloom register struct hostent *hp = (struct hostent *)NULL; 523e2f2f828Seric SOCKADDR addr; 5246286bb75Sbloom int sav_errno; 525e2f2f828Seric int addrlen; 5269d4a8008Seric #if NAMED_BIND 527134746fbSeric extern int h_errno; 528134746fbSeric #endif 5297aa493c5Seric 5307aa493c5Seric /* 5317aa493c5Seric ** Set up the address for the mailer. 53271096d12Seric ** Accept "[a.b.c.d]" syntax for host name. 5337aa493c5Seric */ 5347aa493c5Seric 5359d4a8008Seric #if NAMED_BIND 536794bdbb9Smiriam h_errno = 0; 537134746fbSeric #endif 538794bdbb9Smiriam errno = 0; 539967778e2Seric bzero(&CurHostAddr, sizeof CurHostAddr); 540c931b82bSeric SmtpPhase = mci->mci_phase = "initial connection"; 541d945ebe8Seric CurHostName = host; 542794bdbb9Smiriam 54371096d12Seric if (host[0] == '[') 54471096d12Seric { 545a44d5a5eSeric long hid; 5466c2c3107Seric register char *p = strchr(host, ']'); 54771096d12Seric 548a44d5a5eSeric if (p != NULL) 54971096d12Seric { 550a44d5a5eSeric *p = '\0'; 5514d9c42c2Seric #ifdef NETINET 552a44d5a5eSeric hid = inet_addr(&host[1]); 553a7e21fe6Seric if (hid == -1) 5544d9c42c2Seric #endif 555a7e21fe6Seric { 556a7e21fe6Seric /* try it as a host name (avoid MX lookup) */ 557a7e21fe6Seric hp = gethostbyname(&host[1]); 558d8984352Seric if (hp == NULL && p[-1] == '.') 559d8984352Seric { 560d8984352Seric p[-1] = '\0'; 561d8984352Seric hp = gethostbyname(&host[1]); 562d8984352Seric p[-1] = '.'; 563d8984352Seric } 564a7e21fe6Seric *p = ']'; 565a7e21fe6Seric goto gothostent; 566a7e21fe6Seric } 567a44d5a5eSeric *p = ']'; 56871096d12Seric } 569a7e21fe6Seric if (p == NULL) 57071096d12Seric { 57108b25121Seric usrerr("553 Invalid numeric domain spec \"%s\"", host); 57271096d12Seric return (EX_NOHOST); 57371096d12Seric } 5744d9c42c2Seric #ifdef NETINET 5754d9c42c2Seric addr.sin.sin_family = AF_INET; /*XXX*/ 57683c1f4bcSeric addr.sin.sin_addr.s_addr = hid; 5774d9c42c2Seric #endif 57871096d12Seric } 5791c71e510Seric else 5801c71e510Seric { 581d8984352Seric register char *p = &host[strlen(host) - 1]; 582d8984352Seric 58304344589Sbloom hp = gethostbyname(host); 584d8984352Seric if (hp == NULL && *p == '.') 585d8984352Seric { 586d8984352Seric *p = '\0'; 587d8984352Seric hp = gethostbyname(host); 588d8984352Seric *p = '.'; 589d8984352Seric } 590a7e21fe6Seric gothostent: 591794bdbb9Smiriam if (hp == NULL) 592794bdbb9Smiriam { 5939d4a8008Seric #if NAMED_BIND 594794bdbb9Smiriam if (errno == ETIMEDOUT || h_errno == TRY_AGAIN) 59552308a50Seric return (EX_TEMPFAIL); 59682e5d8ddSeric 597134746fbSeric /* if name server is specified, assume temp fail */ 598134746fbSeric if (errno == ECONNREFUSED && UseNameServer) 599134746fbSeric return (EX_TEMPFAIL); 600134746fbSeric #endif 6017aa493c5Seric return (EX_NOHOST); 602794bdbb9Smiriam } 60383c1f4bcSeric addr.sa.sa_family = hp->h_addrtype; 60483c1f4bcSeric switch (hp->h_addrtype) 60583c1f4bcSeric { 60683c1f4bcSeric #ifdef NETINET 60783c1f4bcSeric case AF_INET: 608e2f2f828Seric bcopy(hp->h_addr, 60983c1f4bcSeric &addr.sin.sin_addr, 610859d5010Seric sizeof addr.sin.sin_addr); 61183c1f4bcSeric break; 61283c1f4bcSeric #endif 61383c1f4bcSeric 61483c1f4bcSeric default: 615e2f2f828Seric bcopy(hp->h_addr, 61683c1f4bcSeric addr.sa.sa_data, 617e2f2f828Seric hp->h_length); 61883c1f4bcSeric break; 61983c1f4bcSeric } 62004344589Sbloom i = 1; 6211c71e510Seric } 6221c71e510Seric 6231c71e510Seric /* 6241c71e510Seric ** Determine the port number. 6251c71e510Seric */ 6261c71e510Seric 627fd7c0790Seric if (port != 0) 628e2f2f828Seric port = htons(port); 629fd7c0790Seric else 6301c71e510Seric { 6311c71e510Seric register struct servent *sp = getservbyname("smtp", "tcp"); 6321c71e510Seric 6331c71e510Seric if (sp == NULL) 6341c71e510Seric { 635ad977999Seric syserr("554 makeconnection: service \"smtp\" unknown"); 636e5311662Seric port = htons(25); 6371c71e510Seric } 638e5311662Seric else 639e2f2f828Seric port = sp->s_port; 640e2f2f828Seric } 641e2f2f828Seric 64283c1f4bcSeric switch (addr.sa.sa_family) 643e2f2f828Seric { 6444d9c42c2Seric #ifdef NETINET 645e2f2f828Seric case AF_INET: 64683c1f4bcSeric addr.sin.sin_port = port; 647e2f2f828Seric addrlen = sizeof (struct sockaddr_in); 648e2f2f828Seric break; 6494d9c42c2Seric #endif 650e2f2f828Seric 651e2f2f828Seric #ifdef NETISO 652e2f2f828Seric case AF_ISO: 653e2f2f828Seric /* assume two byte transport selector */ 654e2f2f828Seric bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 655e2f2f828Seric addrlen = sizeof (struct sockaddr_iso); 656e2f2f828Seric break; 657e2f2f828Seric #endif 658e2f2f828Seric 659e2f2f828Seric default: 66083c1f4bcSeric syserr("Can't connect to address family %d", addr.sa.sa_family); 661e2f2f828Seric return (EX_NOHOST); 6621c71e510Seric } 6637aa493c5Seric 6647aa493c5Seric /* 6657aa493c5Seric ** Try to actually open the connection. 6667aa493c5Seric */ 6677aa493c5Seric 668e17a3a5aSeric #ifdef XLA 669e17a3a5aSeric /* if too many connections, don't bother trying */ 670e17a3a5aSeric if (!xla_noqueue_ok(host)) 671e17a3a5aSeric return EX_TEMPFAIL; 672e17a3a5aSeric #endif 673e17a3a5aSeric 674aea02ca1Seric for (;;) 675aea02ca1Seric { 67661e4310fSeric if (tTd(16, 1)) 677e2f2f828Seric printf("makeconnection (%s [%s])\n", 678e2f2f828Seric host, anynet_ntoa(&addr)); 6797aa493c5Seric 680226e3022Seric /* save for logging */ 681226e3022Seric CurHostAddr = addr; 682226e3022Seric 683914346b1Seric if (usesecureport) 684914346b1Seric { 685914346b1Seric int rport = IPPORT_RESERVED - 1; 686914346b1Seric 687914346b1Seric s = rresvport(&rport); 688914346b1Seric } 689914346b1Seric else 690914346b1Seric { 691af5e902cSeric s = socket(AF_INET, SOCK_STREAM, 0); 692914346b1Seric } 6937aa493c5Seric if (s < 0) 6947aa493c5Seric { 6956286bb75Sbloom sav_errno = errno; 696914346b1Seric syserr("makeconnection: no socket"); 6977aa493c5Seric goto failure; 6987aa493c5Seric } 6997aa493c5Seric 700b35447dbSeric #ifdef SO_SNDBUF 701b35447dbSeric if (TcpSndBufferSize > 0) 702b35447dbSeric { 703b35447dbSeric if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 704bf217a95Seric (char *) &TcpSndBufferSize, 705b35447dbSeric sizeof(TcpSndBufferSize)) < 0) 706b35447dbSeric syserr("makeconnection: setsockopt(SO_SNDBUF)"); 707b35447dbSeric } 708b35447dbSeric #endif 709b35447dbSeric 71061e4310fSeric if (tTd(16, 1)) 711b31e7f2bSeric printf("makeconnection: fd=%d\n", s); 7121b6e4a15Seric 7131b6e4a15Seric /* turn on network debugging? */ 714a2ef5fa4Seric if (tTd(16, 101)) 71552308a50Seric { 71652308a50Seric int on = 1; 717aea02ca1Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, 718aea02ca1Seric (char *)&on, sizeof on); 71952308a50Seric } 72087d6e633Srick if (CurEnv->e_xfp != NULL) 721877a6142Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 7224bd6a662Seric errno = 0; /* for debugging */ 723e2f2f828Seric if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 724aea02ca1Seric break; 725aea02ca1Seric 726aea02ca1Seric /* couldn't connect.... figure out why */ 7276286bb75Sbloom sav_errno = errno; 7286286bb75Sbloom (void) close(s); 72904344589Sbloom if (hp && hp->h_addr_list[i]) 73004344589Sbloom { 731aea02ca1Seric if (tTd(16, 1)) 732e2f2f828Seric printf("Connect failed (%s); trying new address....\n", 733e2f2f828Seric errstring(sav_errno)); 73483c1f4bcSeric switch (addr.sa.sa_family) 73583c1f4bcSeric { 73683c1f4bcSeric #ifdef NETINET 73783c1f4bcSeric case AF_INET: 738e2f2f828Seric bcopy(hp->h_addr_list[i++], 73983c1f4bcSeric &addr.sin.sin_addr, 740859d5010Seric sizeof addr.sin.sin_addr); 74183c1f4bcSeric break; 74283c1f4bcSeric #endif 74383c1f4bcSeric 74483c1f4bcSeric default: 745e2f2f828Seric bcopy(hp->h_addr_list[i++], 74683c1f4bcSeric addr.sa.sa_data, 747914346b1Seric hp->h_length); 74883c1f4bcSeric break; 74983c1f4bcSeric } 750aea02ca1Seric continue; 75104344589Sbloom } 75204344589Sbloom 7537aa493c5Seric /* failure, decide if temporary or not */ 7547aa493c5Seric failure: 755244b09d1Seric #ifdef XLA 756244b09d1Seric xla_host_end(host); 757244b09d1Seric #endif 758e2de2524Seric if (transienterror(sav_errno)) 759e2de2524Seric return EX_TEMPFAIL; 760e2de2524Seric else 76187d6e633Srick { 76208b25121Seric message("%s", errstring(sav_errno)); 7637aa493c5Seric return (EX_UNAVAILABLE); 7647aa493c5Seric } 7657aa493c5Seric } 7667aa493c5Seric 7677aa493c5Seric /* connection ok, put it into canonical form */ 768335eae58Seric if ((mci->mci_out = fdopen(s, "w")) == NULL || 769335eae58Seric (s = dup(s)) < 0 || 770ab81ee53Seric (mci->mci_in = fdopen(s, "r")) == NULL) 771335eae58Seric { 772335eae58Seric syserr("cannot open SMTP client channel, fd=%d", s); 773335eae58Seric return EX_TEMPFAIL; 774335eae58Seric } 7757aa493c5Seric 776dca8e1f7Seric return (EX_OK); 7777aa493c5Seric } 778444eaf03Seric /* 779444eaf03Seric ** MYHOSTNAME -- return the name of this host. 780444eaf03Seric ** 781444eaf03Seric ** Parameters: 782444eaf03Seric ** hostbuf -- a place to return the name of this host. 783897f1869Seric ** size -- the size of hostbuf. 784444eaf03Seric ** 785444eaf03Seric ** Returns: 786444eaf03Seric ** A list of aliases for this host. 787444eaf03Seric ** 788444eaf03Seric ** Side Effects: 789d8d0a4aeSeric ** Adds numeric codes to $=w. 790444eaf03Seric */ 791444eaf03Seric 792444eaf03Seric char ** 793897f1869Seric myhostname(hostbuf, size) 794444eaf03Seric char hostbuf[]; 795897f1869Seric int size; 796444eaf03Seric { 79738ad259dSeric register struct hostent *hp; 798444eaf03Seric extern struct hostent *gethostbyname(); 799444eaf03Seric 800af5e902cSeric if (gethostname(hostbuf, size) < 0) 801af5e902cSeric { 802af5e902cSeric (void) strcpy(hostbuf, "localhost"); 803af5e902cSeric } 804a44d5a5eSeric hp = gethostbyname(hostbuf); 805a44d5a5eSeric if (hp != NULL) 8067364df9fSeric { 807*747df804Seric #ifdef NAMED_BIND 808*747df804Seric if (strchr(hp->h_name, '.') == NULL) 809*747df804Seric { 810*747df804Seric extern bool getcanonname(); 811*747df804Seric 812*747df804Seric (void) getcanonname(hostbuf, size, TRUE); 813*747df804Seric } 814*747df804Seric else 815*747df804Seric #else 816*747df804Seric { 81738ad259dSeric (void) strncpy(hostbuf, hp->h_name, size - 1); 81838ad259dSeric hostbuf[size - 1] = '\0'; 819*747df804Seric } 820*747df804Seric #endif 82138ad259dSeric 82238ad259dSeric if (hp->h_addrtype == AF_INET && hp->h_length == 4) 82338ad259dSeric { 82438ad259dSeric register int i; 82538ad259dSeric 826d8d0a4aeSeric for (i = 0; hp->h_addr_list[i] != NULL; i++) 82738ad259dSeric { 828d8d0a4aeSeric char ipbuf[100]; 829d8d0a4aeSeric 830d8d0a4aeSeric sprintf(ipbuf, "[%s]", 831d8d0a4aeSeric inet_ntoa(*((struct in_addr *) hp->h_addr_list[i]))); 832d8d0a4aeSeric setclass('w', ipbuf); 83338ad259dSeric } 83438ad259dSeric } 83538ad259dSeric 836a44d5a5eSeric return (hp->h_aliases); 8377364df9fSeric } 838444eaf03Seric else 839444eaf03Seric return (NULL); 840444eaf03Seric } 841cb452edcSeric /* 8429f8b0eadSeric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 8439f8b0eadSeric ** 8449f8b0eadSeric ** Uses RFC1413 protocol to try to get info from the other end. 845320e0d1cSeric ** 846320e0d1cSeric ** Parameters: 847320e0d1cSeric ** fd -- the descriptor 848320e0d1cSeric ** 849320e0d1cSeric ** Returns: 8509f8b0eadSeric ** The user@host information associated with this descriptor. 851320e0d1cSeric */ 852320e0d1cSeric 853c73f2aa4Seric #if IDENTPROTO 8549f8b0eadSeric 8559f8b0eadSeric static jmp_buf CtxAuthTimeout; 8569f8b0eadSeric 8579f8b0eadSeric static 8589f8b0eadSeric authtimeout() 8599f8b0eadSeric { 8609f8b0eadSeric longjmp(CtxAuthTimeout, 1); 8619f8b0eadSeric } 8629f8b0eadSeric 8639f8b0eadSeric #endif 8649f8b0eadSeric 865320e0d1cSeric char * 8669f8b0eadSeric getauthinfo(fd) 867320e0d1cSeric int fd; 868320e0d1cSeric { 8699f8b0eadSeric int falen; 870a5546e24Seric register char *p; 871c73f2aa4Seric #if IDENTPROTO 8729f8b0eadSeric SOCKADDR la; 8739f8b0eadSeric int lalen; 8749f8b0eadSeric register struct servent *sp; 8759f8b0eadSeric int s; 8769f8b0eadSeric int i; 8779f8b0eadSeric EVENT *ev; 8789f8b0eadSeric #endif 8799f8b0eadSeric static char hbuf[MAXNAME * 2 + 2]; 8809f8b0eadSeric extern char *hostnamebyanyaddr(); 8819f8b0eadSeric extern char RealUserName[]; /* main.c */ 882320e0d1cSeric 883e29a76d1Seric falen = sizeof RealHostAddr; 884e29a76d1Seric if (getpeername(fd, &RealHostAddr.sa, &falen) < 0 || falen <= 0 || 885e29a76d1Seric RealHostAddr.sa.sa_family == 0) 8869f8b0eadSeric { 8879f8b0eadSeric (void) sprintf(hbuf, "%s@localhost", RealUserName); 88853853673Seric if (tTd(9, 1)) 8899f8b0eadSeric printf("getauthinfo: %s\n", hbuf); 890320e0d1cSeric return hbuf; 891320e0d1cSeric } 8929f8b0eadSeric 893e29a76d1Seric if (RealHostName == NULL) 894e29a76d1Seric { 895e29a76d1Seric /* translate that to a host name */ 896e29a76d1Seric RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 897e29a76d1Seric } 898e29a76d1Seric 899c73f2aa4Seric #if IDENTPROTO 90093b3215bSeric if (TimeOuts.to_ident == 0) 90193b3215bSeric goto noident; 90293b3215bSeric 9039f8b0eadSeric lalen = sizeof la; 904e29a76d1Seric if (RealHostAddr.sa.sa_family != AF_INET || 9059f8b0eadSeric getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 9069f8b0eadSeric la.sa.sa_family != AF_INET) 9079f8b0eadSeric { 9089f8b0eadSeric /* no ident info */ 9099f8b0eadSeric goto noident; 9109f8b0eadSeric } 9119f8b0eadSeric 9129f8b0eadSeric /* create ident query */ 913f2d880b6Seric (void) sprintf(hbuf, "%d,%d\r\n", 914e29a76d1Seric ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port)); 9159f8b0eadSeric 9169f8b0eadSeric /* create local address */ 917d6af7dadSeric la.sin.sin_port = 0; 9189f8b0eadSeric 9199f8b0eadSeric /* create foreign address */ 9209f8b0eadSeric sp = getservbyname("auth", "tcp"); 9219f8b0eadSeric if (sp != NULL) 922e29a76d1Seric RealHostAddr.sin.sin_port = sp->s_port; 9239f8b0eadSeric else 924e29a76d1Seric RealHostAddr.sin.sin_port = htons(113); 9259f8b0eadSeric 9269f8b0eadSeric s = -1; 9279f8b0eadSeric if (setjmp(CtxAuthTimeout) != 0) 9289f8b0eadSeric { 9299f8b0eadSeric if (s >= 0) 9309f8b0eadSeric (void) close(s); 9319f8b0eadSeric goto noident; 9329f8b0eadSeric } 9339f8b0eadSeric 9349f8b0eadSeric /* put a timeout around the whole thing */ 935a0f780efSeric ev = setevent(TimeOuts.to_ident, authtimeout, 0); 9369f8b0eadSeric 937d6af7dadSeric /* connect to foreign IDENT server using same address as SMTP socket */ 9389f8b0eadSeric s = socket(AF_INET, SOCK_STREAM, 0); 9399f8b0eadSeric if (s < 0) 9409f8b0eadSeric { 9419f8b0eadSeric clrevent(ev); 9429f8b0eadSeric goto noident; 9439f8b0eadSeric } 944d6af7dadSeric if (bind(s, &la.sa, sizeof la.sin) < 0 || 945e29a76d1Seric connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0) 9469f8b0eadSeric { 9477c201575Seric goto closeident; 9489f8b0eadSeric } 9499f8b0eadSeric 95053853673Seric if (tTd(9, 10)) 9519f8b0eadSeric printf("getauthinfo: sent %s", hbuf); 9529f8b0eadSeric 9539f8b0eadSeric /* send query */ 9549f8b0eadSeric if (write(s, hbuf, strlen(hbuf)) < 0) 9559f8b0eadSeric goto closeident; 9569f8b0eadSeric 9579f8b0eadSeric /* get result */ 9589f8b0eadSeric i = read(s, hbuf, sizeof hbuf); 9599f8b0eadSeric (void) close(s); 9609f8b0eadSeric clrevent(ev); 9619f8b0eadSeric if (i <= 0) 9629f8b0eadSeric goto noident; 9639f8b0eadSeric if (hbuf[--i] == '\n' && hbuf[--i] == '\r') 9649f8b0eadSeric i--; 9659f8b0eadSeric hbuf[++i] = '\0'; 9669f8b0eadSeric 96753853673Seric if (tTd(9, 3)) 9689f8b0eadSeric printf("getauthinfo: got %s\n", hbuf); 9699f8b0eadSeric 9709f8b0eadSeric /* parse result */ 9719f8b0eadSeric p = strchr(hbuf, ':'); 9729f8b0eadSeric if (p == NULL) 9739f8b0eadSeric { 9749f8b0eadSeric /* malformed response */ 9759f8b0eadSeric goto noident; 9769f8b0eadSeric } 9779f8b0eadSeric while (isascii(*++p) && isspace(*p)) 9789f8b0eadSeric continue; 9799f8b0eadSeric if (strncasecmp(p, "userid", 6) != 0) 9809f8b0eadSeric { 9819f8b0eadSeric /* presumably an error string */ 9829f8b0eadSeric goto noident; 9839f8b0eadSeric } 9849f8b0eadSeric p += 6; 9859f8b0eadSeric while (isascii(*p) && isspace(*p)) 9869f8b0eadSeric p++; 9879f8b0eadSeric if (*p++ != ':') 9889f8b0eadSeric { 9899f8b0eadSeric /* either useridxx or malformed response */ 9909f8b0eadSeric goto noident; 9919f8b0eadSeric } 9929f8b0eadSeric 9939f8b0eadSeric /* p now points to the OSTYPE field */ 9949f8b0eadSeric p = strchr(p, ':'); 9959f8b0eadSeric if (p == NULL) 9969f8b0eadSeric { 9979f8b0eadSeric /* malformed response */ 9989f8b0eadSeric goto noident; 9999f8b0eadSeric } 100053853673Seric 100153853673Seric /* 1413 says don't do this -- but it's broken otherwise */ 100253853673Seric while (isascii(*++p) && isspace(*p)) 100353853673Seric continue; 10049f8b0eadSeric 10059f8b0eadSeric /* p now points to the authenticated name */ 1006f7869e68Seric (void) sprintf(hbuf, "%s@%s", 1007f7869e68Seric p, RealHostName == NULL ? "localhost" : RealHostName); 100853853673Seric goto finish; 100953853673Seric 10107c201575Seric closeident: 10117c201575Seric (void) close(s); 10127c201575Seric clrevent(ev); 10137c201575Seric 101453853673Seric #endif /* IDENTPROTO */ 101553853673Seric 101653853673Seric noident: 1017f7869e68Seric if (RealHostName == NULL) 1018f7869e68Seric { 1019f7869e68Seric if (tTd(9, 1)) 1020f7869e68Seric printf("getauthinfo: NULL\n"); 1021f7869e68Seric return NULL; 1022f7869e68Seric } 102353853673Seric (void) strcpy(hbuf, RealHostName); 102453853673Seric 102553853673Seric finish: 1026f7869e68Seric if (RealHostName != NULL && RealHostName[0] != '[') 10279f8b0eadSeric { 10289f8b0eadSeric p = &hbuf[strlen(hbuf)]; 10299f8b0eadSeric (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr)); 10309f8b0eadSeric } 103153853673Seric if (tTd(9, 1)) 10329f8b0eadSeric printf("getauthinfo: %s\n", hbuf); 10339f8b0eadSeric return hbuf; 10349f8b0eadSeric } 1035320e0d1cSeric /* 103608de856eSeric ** HOST_MAP_LOOKUP -- turn a hostname into canonical form 103715d084d5Seric ** 103815d084d5Seric ** Parameters: 103905b57da8Seric ** map -- a pointer to this map (unused). 104008de856eSeric ** name -- the (presumably unqualified) hostname. 104100b385a9Seric ** av -- unused -- for compatibility with other mapping 1042d798a1deSeric ** functions. 10432d29d43aSeric ** statp -- an exit status (out parameter) -- set to 10442d29d43aSeric ** EX_TEMPFAIL if the name server is unavailable. 104515d084d5Seric ** 104615d084d5Seric ** Returns: 104715d084d5Seric ** The mapping, if found. 104815d084d5Seric ** NULL if no mapping found. 104915d084d5Seric ** 105015d084d5Seric ** Side Effects: 105115d084d5Seric ** Looks up the host specified in hbuf. If it is not 105215d084d5Seric ** the canonical name for that host, return the canonical 105315d084d5Seric ** name. 1054f36ede03Sbostic */ 1055cb452edcSeric 105615d084d5Seric char * 105700b385a9Seric host_map_lookup(map, name, av, statp) 105805b57da8Seric MAP *map; 105908de856eSeric char *name; 106000b385a9Seric char **av; 10612d29d43aSeric int *statp; 106299f7cf32Seric { 106399f7cf32Seric register struct hostent *hp; 10645f78836eSmiriam u_long in_addr; 106505b57da8Seric char *cp; 106638ad259dSeric int i; 1067eea91d78Seric register STAB *s; 106800b385a9Seric char hbuf[MAXNAME]; 1069eea91d78Seric extern struct hostent *gethostbyaddr(); 10709d4a8008Seric #if NAMED_BIND 1071eea91d78Seric extern int h_errno; 1072c304a798Seric #endif 10735f78836eSmiriam 1074f36ede03Sbostic /* 1075eea91d78Seric ** See if we have already looked up this name. If so, just 1076eea91d78Seric ** return it. 1077eea91d78Seric */ 1078eea91d78Seric 107908de856eSeric s = stab(name, ST_NAMECANON, ST_ENTER); 1080eea91d78Seric if (bitset(NCF_VALID, s->s_namecanon.nc_flags)) 1081eea91d78Seric { 1082f92c3297Seric if (tTd(9, 1)) 108308de856eSeric printf("host_map_lookup(%s) => CACHE %s\n", 108408de856eSeric name, s->s_namecanon.nc_cname); 1085eea91d78Seric errno = s->s_namecanon.nc_errno; 10869d4a8008Seric #if NAMED_BIND 1087eea91d78Seric h_errno = s->s_namecanon.nc_herrno; 1088c304a798Seric #endif 1089eea91d78Seric *statp = s->s_namecanon.nc_stat; 109092270fb3Seric if (CurEnv->e_message == NULL && *statp == EX_TEMPFAIL) 1091ed63aae0Seric { 1092ed63aae0Seric sprintf(hbuf, "%s: Name server timeout", 1093ed63aae0Seric shortenstring(name, 33)); 1094ed63aae0Seric CurEnv->e_message = newstr(hbuf); 1095ed63aae0Seric } 1096eea91d78Seric return s->s_namecanon.nc_cname; 1097eea91d78Seric } 1098eea91d78Seric 1099eea91d78Seric /* 1100eea91d78Seric ** If first character is a bracket, then it is an address 1101eea91d78Seric ** lookup. Address is copied into a temporary buffer to 110208de856eSeric ** strip the brackets and to preserve name if address is 1103eea91d78Seric ** unknown. 1104f36ede03Sbostic */ 110515d084d5Seric 110608de856eSeric if (*name != '[') 110715d084d5Seric { 1108d798a1deSeric extern bool getcanonname(); 1109d798a1deSeric 11108cb4653dSeric if (tTd(9, 1)) 111108de856eSeric printf("host_map_lookup(%s) => ", name); 1112eea91d78Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 111308de856eSeric (void) strcpy(hbuf, name); 11141f2ff1a4Seric if (getcanonname(hbuf, sizeof hbuf - 1, TRUE)) 11159040ec4fSeric { 11169040ec4fSeric if (tTd(9, 1)) 11179040ec4fSeric printf("%s\n", hbuf); 111800b385a9Seric cp = map_rewrite(map, hbuf, strlen(hbuf), av); 111900b385a9Seric s->s_namecanon.nc_cname = newstr(cp); 112000b385a9Seric return cp; 11219040ec4fSeric } 112215d084d5Seric else 11239040ec4fSeric { 11242d29d43aSeric register struct hostent *hp; 11252d29d43aSeric 1126c304a798Seric s->s_namecanon.nc_errno = errno; 11279d4a8008Seric #if NAMED_BIND 1128c304a798Seric s->s_namecanon.nc_herrno = h_errno; 11299040ec4fSeric if (tTd(9, 1)) 11302d29d43aSeric printf("FAIL (%d)\n", h_errno); 11312d29d43aSeric switch (h_errno) 11322d29d43aSeric { 11332d29d43aSeric case TRY_AGAIN: 113489cb2793Seric if (UseNameServer) 11358820d51bSeric { 1136e0326f4fSeric sprintf(hbuf, "%s: Name server timeout", 1137ed63aae0Seric shortenstring(name, 33)); 1138e0326f4fSeric message("%s", hbuf); 11398820d51bSeric if (CurEnv->e_message == NULL) 1140e0326f4fSeric CurEnv->e_message = newstr(hbuf); 11418820d51bSeric } 11422d29d43aSeric *statp = EX_TEMPFAIL; 11432d29d43aSeric break; 11442d29d43aSeric 11452d29d43aSeric case HOST_NOT_FOUND: 11462d29d43aSeric *statp = EX_NOHOST; 11472d29d43aSeric break; 11482d29d43aSeric 11492d29d43aSeric case NO_RECOVERY: 11502d29d43aSeric *statp = EX_SOFTWARE; 11512d29d43aSeric break; 11522d29d43aSeric 11532d29d43aSeric default: 11542d29d43aSeric *statp = EX_UNAVAILABLE; 11552d29d43aSeric break; 11562d29d43aSeric } 1157c304a798Seric #else 1158c304a798Seric if (tTd(9, 1)) 1159c304a798Seric printf("FAIL\n"); 1160c304a798Seric *statp = EX_NOHOST; 1161c304a798Seric #endif 1162eea91d78Seric s->s_namecanon.nc_stat = *statp; 11632d29d43aSeric if (*statp != EX_TEMPFAIL || UseNameServer) 116415d084d5Seric return NULL; 11652d29d43aSeric 11662d29d43aSeric /* 11672d29d43aSeric ** Try to look it up in /etc/hosts 11682d29d43aSeric */ 11692d29d43aSeric 117008de856eSeric hp = gethostbyname(name); 11712d29d43aSeric if (hp == NULL) 11722d29d43aSeric { 11732d29d43aSeric /* no dice there either */ 1174eea91d78Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 11752d29d43aSeric return NULL; 11762d29d43aSeric } 11772d29d43aSeric 1178eea91d78Seric s->s_namecanon.nc_stat = *statp = EX_OK; 117900b385a9Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 118000b385a9Seric s->s_namecanon.nc_cname = newstr(cp); 118100b385a9Seric return cp; 118215d084d5Seric } 11839040ec4fSeric } 118408de856eSeric if ((cp = strchr(name, ']')) == NULL) 118515d084d5Seric return (NULL); 118634e39927Sbostic *cp = '\0'; 118708de856eSeric in_addr = inet_addr(&name[1]); 118838ad259dSeric 118938ad259dSeric /* nope -- ask the name server */ 119031601fa7Seric hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET); 1191eea91d78Seric s->s_namecanon.nc_errno = errno; 11929d4a8008Seric #if NAMED_BIND 1193eea91d78Seric s->s_namecanon.nc_herrno = h_errno; 1194c304a798Seric #endif 1195eea91d78Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 11965f78836eSmiriam if (hp == NULL) 1197eea91d78Seric { 1198eea91d78Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 119915d084d5Seric return (NULL); 1200eea91d78Seric } 120115d084d5Seric 120238ad259dSeric /* found a match -- copy out */ 120300b385a9Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 1204eea91d78Seric s->s_namecanon.nc_stat = *statp = EX_OK; 120500b385a9Seric s->s_namecanon.nc_cname = newstr(cp); 120600b385a9Seric return cp; 120799f7cf32Seric } 1208e2f2f828Seric /* 1209e2f2f828Seric ** ANYNET_NTOA -- convert a network address to printable form. 1210e2f2f828Seric ** 1211e2f2f828Seric ** Parameters: 1212e2f2f828Seric ** sap -- a pointer to a sockaddr structure. 1213e2f2f828Seric ** 1214e2f2f828Seric ** Returns: 1215e2f2f828Seric ** A printable version of that sockaddr. 1216e2f2f828Seric */ 1217e2f2f828Seric 1218e2f2f828Seric char * 1219e2f2f828Seric anynet_ntoa(sap) 1220e2f2f828Seric register SOCKADDR *sap; 1221e2f2f828Seric { 1222e2f2f828Seric register char *bp; 1223e2f2f828Seric register char *ap; 1224e2f2f828Seric int l; 1225e387851eSeric static char buf[100]; 1226e2f2f828Seric 12278cb4653dSeric /* check for null/zero family */ 12288cb4653dSeric if (sap == NULL) 12298cb4653dSeric return "NULLADDR"; 12308cb4653dSeric if (sap->sa.sa_family == 0) 12318cb4653dSeric return "0"; 12328cb4653dSeric 1233e387851eSeric switch (sap->sa.sa_family) 1234e387851eSeric { 1235e387851eSeric #ifdef MAYBENEXTRELEASE /*** UNTESTED *** UNTESTED *** UNTESTED ***/ 1236139b52c8Seric #ifdef NETUNIX 1237e387851eSeric case AF_UNIX: 1238c24cf5a4Seric if (sap->sunix.sun_path[0] != '\0') 1239c24cf5a4Seric sprintf(buf, "[UNIX: %.64s]", sap->sunix.sun_path); 1240e387851eSeric else 1241e387851eSeric sprintf(buf, "[UNIX: localhost]"); 1242e387851eSeric return buf; 1243e387851eSeric #endif 1244139b52c8Seric #endif 1245e387851eSeric 124683c1f4bcSeric #ifdef NETINET 1247e387851eSeric case AF_INET: 1248e2f2f828Seric return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr); 124983c1f4bcSeric #endif 1250e2f2f828Seric 1251e387851eSeric default: 1252e387851eSeric /* this case is only to ensure syntactic correctness */ 1253e387851eSeric break; 1254e387851eSeric } 1255e387851eSeric 1256e2f2f828Seric /* unknown family -- just dump bytes */ 125783c1f4bcSeric (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 1258e2f2f828Seric bp = &buf[strlen(buf)]; 125983c1f4bcSeric ap = sap->sa.sa_data; 126083c1f4bcSeric for (l = sizeof sap->sa.sa_data; --l >= 0; ) 1261e2f2f828Seric { 1262e2f2f828Seric (void) sprintf(bp, "%02x:", *ap++ & 0377); 1263e2f2f828Seric bp += 3; 1264e2f2f828Seric } 1265e2f2f828Seric *--bp = '\0'; 1266e2f2f828Seric return buf; 1267e2f2f828Seric } 12689f8b0eadSeric /* 12699f8b0eadSeric ** HOSTNAMEBYANYADDR -- return name of host based on address 12709f8b0eadSeric ** 12719f8b0eadSeric ** Parameters: 12729f8b0eadSeric ** sap -- SOCKADDR pointer 12739f8b0eadSeric ** 12749f8b0eadSeric ** Returns: 12759f8b0eadSeric ** text representation of host name. 12769f8b0eadSeric ** 12779f8b0eadSeric ** Side Effects: 12789f8b0eadSeric ** none. 12799f8b0eadSeric */ 12809f8b0eadSeric 12819f8b0eadSeric char * 12829f8b0eadSeric hostnamebyanyaddr(sap) 12839f8b0eadSeric register SOCKADDR *sap; 12849f8b0eadSeric { 12859f8b0eadSeric register struct hostent *hp; 12863490b9dfSeric int saveretry; 12873490b9dfSeric 12889d4a8008Seric #if NAMED_BIND 12893490b9dfSeric /* shorten name server timeout to avoid higher level timeouts */ 12903490b9dfSeric saveretry = _res.retry; 12913490b9dfSeric _res.retry = 3; 12923490b9dfSeric #endif /* NAMED_BIND */ 12933490b9dfSeric 12949f8b0eadSeric switch (sap->sa.sa_family) 12959f8b0eadSeric { 12969f8b0eadSeric #ifdef NETINET 12979f8b0eadSeric case AF_INET: 12989f8b0eadSeric hp = gethostbyaddr((char *) &sap->sin.sin_addr, 12999f8b0eadSeric sizeof sap->sin.sin_addr, 13009f8b0eadSeric AF_INET); 13019f8b0eadSeric break; 13029f8b0eadSeric #endif 13039f8b0eadSeric 13049f8b0eadSeric #ifdef NETISO 13059f8b0eadSeric case AF_ISO: 13069f8b0eadSeric hp = gethostbyaddr((char *) &sap->siso.siso_addr, 13079f8b0eadSeric sizeof sap->siso.siso_addr, 13089f8b0eadSeric AF_ISO); 13099f8b0eadSeric break; 13109f8b0eadSeric #endif 13119f8b0eadSeric 1312e387851eSeric #ifdef MAYBENEXTRELEASE /*** UNTESTED *** UNTESTED *** UNTESTED ***/ 1313e387851eSeric case AF_UNIX: 1314e387851eSeric hp = NULL; 1315e387851eSeric break; 1316e387851eSeric #endif 1317e387851eSeric 13189f8b0eadSeric default: 13199f8b0eadSeric hp = gethostbyaddr(sap->sa.sa_data, 13209f8b0eadSeric sizeof sap->sa.sa_data, 13219f8b0eadSeric sap->sa.sa_family); 13229f8b0eadSeric break; 13239f8b0eadSeric } 13249f8b0eadSeric 13259d4a8008Seric #if NAMED_BIND 13263490b9dfSeric _res.retry = saveretry; 13273490b9dfSeric #endif /* NAMED_BIND */ 13283490b9dfSeric 13299f8b0eadSeric if (hp != NULL) 13309f8b0eadSeric return hp->h_name; 13319f8b0eadSeric else 13329f8b0eadSeric { 13339f8b0eadSeric /* produce a dotted quad */ 13349f8b0eadSeric static char buf[512]; 13359f8b0eadSeric 13369f8b0eadSeric (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 13379f8b0eadSeric return buf; 13389f8b0eadSeric } 13399f8b0eadSeric } 1340f36ede03Sbostic 13416c2c3107Seric # else /* DAEMON */ 134299f7cf32Seric /* code for systems without sophisticated networking */ 1343444eaf03Seric 1344444eaf03Seric /* 1345444eaf03Seric ** MYHOSTNAME -- stub version for case of no daemon code. 134621e9914dSeric ** 134721e9914dSeric ** Can't convert to upper case here because might be a UUCP name. 1348897f1869Seric ** 1349897f1869Seric ** Mark, you can change this to be anything you want...... 1350444eaf03Seric */ 1351444eaf03Seric 1352444eaf03Seric char ** 1353897f1869Seric myhostname(hostbuf, size) 1354444eaf03Seric char hostbuf[]; 1355897f1869Seric int size; 1356444eaf03Seric { 1357444eaf03Seric register FILE *f; 1358444eaf03Seric 1359444eaf03Seric hostbuf[0] = '\0'; 1360444eaf03Seric f = fopen("/usr/include/whoami", "r"); 1361444eaf03Seric if (f != NULL) 1362444eaf03Seric { 1363897f1869Seric (void) fgets(hostbuf, size, f); 1364444eaf03Seric fixcrlf(hostbuf, TRUE); 1365444eaf03Seric (void) fclose(f); 1366444eaf03Seric } 1367444eaf03Seric return (NULL); 1368444eaf03Seric } 136999f7cf32Seric /* 13709f8b0eadSeric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 1371320e0d1cSeric ** 1372320e0d1cSeric ** Parameters: 1373320e0d1cSeric ** fd -- the descriptor 1374320e0d1cSeric ** 1375320e0d1cSeric ** Returns: 1376320e0d1cSeric ** The host name associated with this descriptor, if it can 1377320e0d1cSeric ** be determined. 1378320e0d1cSeric ** NULL otherwise. 1379320e0d1cSeric ** 1380320e0d1cSeric ** Side Effects: 1381320e0d1cSeric ** none 1382320e0d1cSeric */ 1383320e0d1cSeric 1384320e0d1cSeric char * 13859f8b0eadSeric getauthinfo(fd) 1386320e0d1cSeric int fd; 1387320e0d1cSeric { 1388320e0d1cSeric return NULL; 1389320e0d1cSeric } 1390320e0d1cSeric /* 139199f7cf32Seric ** MAPHOSTNAME -- turn a hostname into canonical form 139299f7cf32Seric ** 139399f7cf32Seric ** Parameters: 139405b57da8Seric ** map -- a pointer to the database map. 139508de856eSeric ** name -- a buffer containing a hostname. 139615d084d5Seric ** avp -- a pointer to a (cf file defined) argument vector. 13972d29d43aSeric ** statp -- an exit status (out parameter). 139899f7cf32Seric ** 139999f7cf32Seric ** Returns: 140015d084d5Seric ** mapped host name 1401cb452edcSeric ** FALSE otherwise. 140299f7cf32Seric ** 140399f7cf32Seric ** Side Effects: 140408de856eSeric ** Looks up the host specified in name. If it is not 140599f7cf32Seric ** the canonical name for that host, replace it with 140699f7cf32Seric ** the canonical name. If the name is unknown, or it 140799f7cf32Seric ** is already the canonical name, leave it unchanged. 140899f7cf32Seric */ 140999f7cf32Seric 141099f7cf32Seric /*ARGSUSED*/ 141115d084d5Seric char * 141208de856eSeric host_map_lookup(map, name, avp, statp) 141305b57da8Seric MAP *map; 141408de856eSeric char *name; 141515d084d5Seric char **avp; 14162d29d43aSeric char *statp; 141799f7cf32Seric { 14182d29d43aSeric register struct hostent *hp; 14192d29d43aSeric 142008de856eSeric hp = gethostbyname(name); 14212d29d43aSeric if (hp != NULL) 14222d29d43aSeric return hp->h_name; 14232d29d43aSeric *statp = EX_NOHOST; 142415d084d5Seric return NULL; 142599f7cf32Seric } 142699f7cf32Seric 14276c2c3107Seric #endif /* DAEMON */ 1428