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*b26156f6Seric static char sccsid[] = "@(#)daemon.c 8.72 (Berkeley) 03/14/95 (with daemon mode)"; 15d0a9e852Seric #else 16*b26156f6Seric static char sccsid[] = "@(#)daemon.c 8.72 (Berkeley) 03/14/95 (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 <resolv.h> 273490b9dfSeric #endif 283490b9dfSeric 297fa39d90Seric /* 307fa39d90Seric ** DAEMON.C -- routines to use when running as a daemon. 3147b12ae1Seric ** 3247b12ae1Seric ** This entire file is highly dependent on the 4.2 BSD 3347b12ae1Seric ** interprocess communication primitives. No attempt has 3447b12ae1Seric ** been made to make this file portable to Version 7, 3547b12ae1Seric ** Version 6, MPX files, etc. If you should try such a 3647b12ae1Seric ** thing yourself, I recommend chucking the entire file 3747b12ae1Seric ** and starting from scratch. Basic semantics are: 3847b12ae1Seric ** 3947b12ae1Seric ** getrequests() 4047b12ae1Seric ** Opens a port and initiates a connection. 4147b12ae1Seric ** Returns in a child. Must set InChannel and 4247b12ae1Seric ** OutChannel appropriately. 43b7d7afcbSeric ** clrdaemon() 44b7d7afcbSeric ** Close any open files associated with getting 45b7d7afcbSeric ** the connection; this is used when running the queue, 46b7d7afcbSeric ** etc., to avoid having extra file descriptors during 47b7d7afcbSeric ** the queue run and to avoid confusing the network 48b7d7afcbSeric ** code (if it cares). 49914346b1Seric ** makeconnection(host, port, outfile, infile, usesecureport) 5047b12ae1Seric ** Make a connection to the named host on the given 5147b12ae1Seric ** port. Set *outfile and *infile to the files 5247b12ae1Seric ** appropriate for communication. Returns zero on 5347b12ae1Seric ** success, else an exit status describing the 5447b12ae1Seric ** error. 5508de856eSeric ** host_map_lookup(map, hbuf, avp, pstat) 5605b57da8Seric ** Convert the entry in hbuf into a canonical form. 577fa39d90Seric */ 587fa39d90Seric /* 597fa39d90Seric ** GETREQUESTS -- open mail IPC port and get requests. 607fa39d90Seric ** 617fa39d90Seric ** Parameters: 627fa39d90Seric ** none. 637fa39d90Seric ** 647fa39d90Seric ** Returns: 657fa39d90Seric ** none. 667fa39d90Seric ** 677fa39d90Seric ** Side Effects: 687fa39d90Seric ** Waits until some interesting activity occurs. When 697fa39d90Seric ** it does, a child is created to process it, and the 707fa39d90Seric ** parent waits for completion. Return from this 71147303b1Seric ** routine is always in the child. The file pointers 72147303b1Seric ** "InChannel" and "OutChannel" should be set to point 73147303b1Seric ** to the communication channel. 747fa39d90Seric */ 757fa39d90Seric 76b7d7afcbSeric int DaemonSocket = -1; /* fd describing socket */ 77bfb80540Seric SOCKADDR DaemonAddr; /* socket for incoming */ 78bfc1eaf8Seric int ListenQueueSize = 10; /* size of listen queue */ 79b35447dbSeric int TcpRcvBufferSize = 0; /* size of TCP receive buffer */ 80b35447dbSeric int TcpSndBufferSize = 0; /* size of TCP send buffer */ 811c71e510Seric 82*b26156f6Seric void 837fa39d90Seric getrequests() 847fa39d90Seric { 851c71e510Seric int t; 8615d084d5Seric bool refusingconnections = TRUE; 870aae1086Seric FILE *pidf; 88dadb8687Seric int socksize; 89dfe840b2Seric #ifdef XDEBUG 90dfe840b2Seric bool j_has_dot; 91dfe840b2Seric #endif 929b100374Sbostic extern void reapchild(); 93eb889047Seric 94a8268164Seric /* 951c71e510Seric ** Set up the address for the mailer. 96eb889047Seric */ 97eb889047Seric 98bfb80540Seric if (DaemonAddr.sin.sin_family == 0) 99bfb80540Seric DaemonAddr.sin.sin_family = AF_INET; 100bfb80540Seric if (DaemonAddr.sin.sin_addr.s_addr == 0) 101bfb80540Seric DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY; 102bfb80540Seric if (DaemonAddr.sin.sin_port == 0) 103bfb80540Seric { 104e5311662Seric register struct servent *sp; 105e5311662Seric 1061c71e510Seric sp = getservbyname("smtp", "tcp"); 1071c71e510Seric if (sp == NULL) 108d0a9e852Seric { 109ad977999Seric syserr("554 service \"smtp\" unknown"); 110e5311662Seric DaemonAddr.sin.sin_port = htons(25); 1111c71e510Seric } 112e5311662Seric else 113bfb80540Seric DaemonAddr.sin.sin_port = sp->s_port; 114bfb80540Seric } 1151c71e510Seric 1161c71e510Seric /* 1171c71e510Seric ** Try to actually open the connection. 1181c71e510Seric */ 1191c71e510Seric 1201c71e510Seric if (tTd(15, 1)) 121bfb80540Seric printf("getrequests: port 0x%x\n", DaemonAddr.sin.sin_port); 1221c71e510Seric 1231c71e510Seric /* get a socket for the SMTP connection */ 12488ea5609Seric socksize = opendaemonsocket(TRUE); 1251c71e510Seric 1262b9178d3Seric (void) setsignal(SIGCHLD, reapchild); 12752308a50Seric 1280aae1086Seric /* write the pid to the log file for posterity */ 1290aae1086Seric pidf = fopen(PidFile, "w"); 1300aae1086Seric if (pidf != NULL) 1310aae1086Seric { 13237950f67Seric extern char *CommandLineArgs; 13337950f67Seric 13437950f67Seric /* write the process id on line 1 */ 1350aae1086Seric fprintf(pidf, "%d\n", getpid()); 13637950f67Seric 13737950f67Seric /* line 2 contains all command line flags */ 13837950f67Seric fprintf(pidf, "%s\n", CommandLineArgs); 13937950f67Seric 14037950f67Seric /* flush and close */ 1410aae1086Seric fclose(pidf); 1420aae1086Seric } 1430aae1086Seric 144dfe840b2Seric #ifdef XDEBUG 145dfe840b2Seric { 14635852b23Seric char jbuf[MAXHOSTNAMELEN]; 147dfe840b2Seric 14835852b23Seric expand("\201j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv); 14935852b23Seric j_has_dot = strchr(jbuf, '.') != NULL; 150dfe840b2Seric } 151dfe840b2Seric #endif 1520aae1086Seric 1531c71e510Seric if (tTd(15, 1)) 154b7d7afcbSeric printf("getrequests: %d\n", DaemonSocket); 1551c71e510Seric 1561c71e510Seric for (;;) 1571c71e510Seric { 1583a099713Seric register int pid; 159a44d5a5eSeric auto int lotherend; 16015d084d5Seric extern bool refuseconnections(); 161*b26156f6Seric extern int getla(); 1623a099713Seric 1633a099713Seric /* see if we are rejecting connections */ 16415d084d5Seric CurrentLA = getla(); 16515d084d5Seric if (refuseconnections()) 1666775ec03Sbostic { 1670084e6f6Seric if (DaemonSocket >= 0) 16815d084d5Seric { 1690084e6f6Seric /* close socket so peer will fail quickly */ 1700084e6f6Seric (void) close(DaemonSocket); 1710084e6f6Seric DaemonSocket = -1; 17215d084d5Seric } 1730084e6f6Seric refusingconnections = TRUE; 17471e5e267Seric setproctitle("rejecting connections: load average: %d", 17571e5e267Seric CurrentLA); 1760084e6f6Seric sleep(15); 17715d084d5Seric continue; 17815d084d5Seric } 17915d084d5Seric 180*b26156f6Seric /* arrange to (re)open the socket if necessary */ 18115d084d5Seric if (refusingconnections) 18215d084d5Seric { 1838a0cb579Seric (void) opendaemonsocket(FALSE); 18415d084d5Seric setproctitle("accepting connections"); 18515d084d5Seric refusingconnections = FALSE; 1866775ec03Sbostic } 187a44d5a5eSeric 188dfe840b2Seric #ifdef XDEBUG 189dfe840b2Seric /* check for disaster */ 190dfe840b2Seric { 19135852b23Seric char jbuf[MAXHOSTNAMELEN]; 192dfe840b2Seric 19335852b23Seric expand("\201j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv); 194*b26156f6Seric if (!wordinclass(jbuf, 'w')) 195dfe840b2Seric { 196dfe840b2Seric dumpstate("daemon lost $j"); 197dfe840b2Seric syslog(LOG_ALERT, "daemon process doesn't have $j in $=w; see syslog"); 198dfe840b2Seric abort(); 199dfe840b2Seric } 20035852b23Seric else if (j_has_dot && strchr(jbuf, '.') == NULL) 201dfe840b2Seric { 202dfe840b2Seric dumpstate("daemon $j lost dot"); 203dfe840b2Seric syslog(LOG_ALERT, "daemon process $j lost dot; see syslog"); 204dfe840b2Seric abort(); 205dfe840b2Seric } 206dfe840b2Seric } 207dfe840b2Seric #endif 208dfe840b2Seric 2091c71e510Seric /* wait for a connection */ 2101c71e510Seric do 2111c71e510Seric { 2121c71e510Seric errno = 0; 213dadb8687Seric lotherend = socksize; 2149b100374Sbostic t = accept(DaemonSocket, 2159b100374Sbostic (struct sockaddr *)&RealHostAddr, &lotherend); 2161c71e510Seric } while (t < 0 && errno == EINTR); 2171c71e510Seric if (t < 0) 2181c71e510Seric { 2191c71e510Seric syserr("getrequests: accept"); 220*b26156f6Seric 221*b26156f6Seric /* arrange to re-open the socket next time around */ 222*b26156f6Seric (void) close(DaemonSocket); 223*b26156f6Seric DaemonSocket = -1; 2241c71e510Seric sleep(5); 2251c71e510Seric continue; 2261c71e510Seric } 227d0a9e852Seric 228d0a9e852Seric /* 229d0a9e852Seric ** Create a subprocess to process the mail. 230d0a9e852Seric */ 231d0a9e852Seric 23261e4310fSeric if (tTd(15, 2)) 2331c71e510Seric printf("getrequests: forking (fd = %d)\n", t); 234eb889047Seric 235a8268164Seric pid = fork(); 236a8268164Seric if (pid < 0) 237a8268164Seric { 238a8268164Seric syserr("daemon: cannot fork"); 239a8268164Seric sleep(10); 2401c71e510Seric (void) close(t); 241a8268164Seric continue; 242a8268164Seric } 243a8268164Seric 244a8268164Seric if (pid == 0) 245a8268164Seric { 246da662164Seric char *p; 2479f8b0eadSeric extern char *hostnamebyanyaddr(); 248*b26156f6Seric extern void intsig(); 249a44d5a5eSeric 250a8268164Seric /* 251a8268164Seric ** CHILD -- return to caller. 252a44d5a5eSeric ** Collect verified idea of sending host. 253a8268164Seric ** Verify calling user id if possible here. 254a8268164Seric */ 255a8268164Seric 2562b9178d3Seric (void) setsignal(SIGCHLD, SIG_DFL); 257*b26156f6Seric (void) setsignal(SIGHUP, intsig); 258*b26156f6Seric (void) close(DaemonSocket); 2599f9b003eSeric DisConnected = FALSE; 260779ac194Seric 2614dd09a90Seric setproctitle("startup with %s", 2624dd09a90Seric anynet_ntoa(&RealHostAddr)); 2634dd09a90Seric 264a44d5a5eSeric /* determine host name */ 265da662164Seric p = hostnamebyanyaddr(&RealHostAddr); 266da662164Seric RealHostName = newstr(p); 2674dd09a90Seric setproctitle("startup with %s", p); 26829dcf4baSeric 2692a6bc25bSeric #ifdef LOG 2701f2ff1a4Seric if (LogLevel > 11) 2712a6bc25bSeric { 2722a6bc25bSeric /* log connection information */ 2732a6bc25bSeric syslog(LOG_INFO, "connect from %s (%s)", 2749f8b0eadSeric RealHostName, anynet_ntoa(&RealHostAddr)); 2752a6bc25bSeric } 2762a6bc25bSeric #endif 2772a6bc25bSeric 278335eae58Seric if ((InChannel = fdopen(t, "r")) == NULL || 279335eae58Seric (t = dup(t)) < 0 || 280335eae58Seric (OutChannel = fdopen(t, "w")) == NULL) 281335eae58Seric { 282335eae58Seric syserr("cannot open SMTP server channel, fd=%d", t); 283335eae58Seric exit(0); 284335eae58Seric } 285244b09d1Seric 28629dcf4baSeric /* should we check for illegal connection here? XXX */ 287e17a3a5aSeric #ifdef XLA 288e17a3a5aSeric if (!xla_host_ok(RealHostName)) 289e17a3a5aSeric { 290244b09d1Seric message("421 Too many SMTP sessions for this host"); 291e17a3a5aSeric exit(0); 292e17a3a5aSeric } 293e17a3a5aSeric #endif 294a44d5a5eSeric 29561e4310fSeric if (tTd(15, 2)) 296d0a9e852Seric printf("getreq: returning\n"); 297a8268164Seric return; 298a8268164Seric } 299a8268164Seric 3003c154354Seric /* close the port so that others will hang (for a while) */ 3013c154354Seric (void) close(t); 3028e3e4b17Seric } 3033c154354Seric /*NOTREACHED*/ 3043c154354Seric } 3058e3e4b17Seric /* 3060084e6f6Seric ** OPENDAEMONSOCKET -- open the SMTP socket 3070084e6f6Seric ** 3080084e6f6Seric ** Deals with setting all appropriate options. DaemonAddr must 3090084e6f6Seric ** be set up in advance. 3100084e6f6Seric ** 3110084e6f6Seric ** Parameters: 31288ea5609Seric ** firsttime -- set if this is the initial open. 3130084e6f6Seric ** 3140084e6f6Seric ** Returns: 3150084e6f6Seric ** Size in bytes of the daemon socket addr. 3160084e6f6Seric ** 3170084e6f6Seric ** Side Effects: 3180084e6f6Seric ** Leaves DaemonSocket set to the open socket. 3190084e6f6Seric ** Exits if the socket cannot be created. 3200084e6f6Seric */ 3210084e6f6Seric 3226173568dSeric #define MAXOPENTRIES 10 /* maximum number of tries to open connection */ 3236173568dSeric 3240084e6f6Seric int 32588ea5609Seric opendaemonsocket(firsttime) 32688ea5609Seric bool firsttime; 3270084e6f6Seric { 3280084e6f6Seric int on = 1; 329*b26156f6Seric int socksize = 0; 3306173568dSeric int ntries = 0; 3316173568dSeric int saveerrno; 3320084e6f6Seric 3330084e6f6Seric if (tTd(15, 2)) 3340084e6f6Seric printf("opendaemonsocket()\n"); 3350084e6f6Seric 3366173568dSeric do 3376173568dSeric { 338254b93c3Seric if (ntries > 0) 339254b93c3Seric sleep(5); 34088ea5609Seric if (firsttime || DaemonSocket < 0) 34188ea5609Seric { 3420084e6f6Seric DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0); 3430084e6f6Seric if (DaemonSocket < 0) 3440084e6f6Seric { 3450084e6f6Seric /* probably another daemon already */ 3466173568dSeric saveerrno = errno; 3470084e6f6Seric syserr("opendaemonsocket: can't create server SMTP socket"); 3480084e6f6Seric severe: 3490084e6f6Seric # ifdef LOG 3500084e6f6Seric if (LogLevel > 0) 3510084e6f6Seric syslog(LOG_ALERT, "problem creating SMTP socket"); 3520084e6f6Seric # endif /* LOG */ 3536173568dSeric DaemonSocket = -1; 3546173568dSeric continue; 3550084e6f6Seric } 3560084e6f6Seric 3570084e6f6Seric /* turn on network debugging? */ 3580084e6f6Seric if (tTd(15, 101)) 3596173568dSeric (void) setsockopt(DaemonSocket, SOL_SOCKET, 3606173568dSeric SO_DEBUG, (char *)&on, 3616173568dSeric sizeof on); 3620084e6f6Seric 3636173568dSeric (void) setsockopt(DaemonSocket, SOL_SOCKET, 3646173568dSeric SO_REUSEADDR, (char *)&on, sizeof on); 3656173568dSeric (void) setsockopt(DaemonSocket, SOL_SOCKET, 3666173568dSeric SO_KEEPALIVE, (char *)&on, sizeof on); 3670084e6f6Seric 3680084e6f6Seric #ifdef SO_RCVBUF 3690084e6f6Seric if (TcpRcvBufferSize > 0) 3700084e6f6Seric { 3716173568dSeric if (setsockopt(DaemonSocket, SOL_SOCKET, 3726173568dSeric SO_RCVBUF, 3730084e6f6Seric (char *) &TcpRcvBufferSize, 3740084e6f6Seric sizeof(TcpRcvBufferSize)) < 0) 3750084e6f6Seric syserr("getrequests: setsockopt(SO_RCVBUF)"); 3760084e6f6Seric } 3770084e6f6Seric #endif 3780084e6f6Seric 3790084e6f6Seric switch (DaemonAddr.sa.sa_family) 3800084e6f6Seric { 3810084e6f6Seric # ifdef NETINET 3820084e6f6Seric case AF_INET: 3830084e6f6Seric socksize = sizeof DaemonAddr.sin; 3840084e6f6Seric break; 3850084e6f6Seric # endif 3860084e6f6Seric 3870084e6f6Seric # ifdef NETISO 3880084e6f6Seric case AF_ISO: 3890084e6f6Seric socksize = sizeof DaemonAddr.siso; 3900084e6f6Seric break; 3910084e6f6Seric # endif 3920084e6f6Seric 3930084e6f6Seric default: 3940084e6f6Seric socksize = sizeof DaemonAddr; 3950084e6f6Seric break; 3960084e6f6Seric } 3970084e6f6Seric 3980084e6f6Seric if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0) 3990084e6f6Seric { 4006173568dSeric saveerrno = errno; 4010084e6f6Seric syserr("getrequests: cannot bind"); 4020084e6f6Seric (void) close(DaemonSocket); 4030084e6f6Seric goto severe; 4040084e6f6Seric } 40588ea5609Seric } 40688ea5609Seric if (!firsttime && listen(DaemonSocket, ListenQueueSize) < 0) 4070084e6f6Seric { 4086173568dSeric saveerrno = errno; 4090084e6f6Seric syserr("getrequests: cannot listen"); 4100084e6f6Seric (void) close(DaemonSocket); 4110084e6f6Seric goto severe; 4120084e6f6Seric } 4130084e6f6Seric return socksize; 4146173568dSeric } while (ntries++ < MAXOPENTRIES && transienterror(saveerrno)); 415*b26156f6Seric syserr("!opendaemonsocket: server SMTP socket wedged: exiting"); 4166173568dSeric finis(); 4170084e6f6Seric } 4180084e6f6Seric /* 419b7d7afcbSeric ** CLRDAEMON -- reset the daemon connection 420b7d7afcbSeric ** 421b7d7afcbSeric ** Parameters: 422b7d7afcbSeric ** none. 423b7d7afcbSeric ** 424b7d7afcbSeric ** Returns: 425b7d7afcbSeric ** none. 426b7d7afcbSeric ** 427b7d7afcbSeric ** Side Effects: 428b7d7afcbSeric ** releases any resources used by the passive daemon. 429b7d7afcbSeric */ 430b7d7afcbSeric 431*b26156f6Seric void 432b7d7afcbSeric clrdaemon() 433b7d7afcbSeric { 434b7d7afcbSeric if (DaemonSocket >= 0) 435b7d7afcbSeric (void) close(DaemonSocket); 436b7d7afcbSeric DaemonSocket = -1; 437b7d7afcbSeric } 438b7d7afcbSeric /* 439bfb80540Seric ** SETDAEMONOPTIONS -- set options for running the daemon 440bfb80540Seric ** 441bfb80540Seric ** Parameters: 442bfb80540Seric ** p -- the options line. 443bfb80540Seric ** 444bfb80540Seric ** Returns: 445bfb80540Seric ** none. 446bfb80540Seric */ 447bfb80540Seric 448*b26156f6Seric void 449bfb80540Seric setdaemonoptions(p) 450bfb80540Seric register char *p; 451bfb80540Seric { 452850144caSeric if (DaemonAddr.sa.sa_family == AF_UNSPEC) 453850144caSeric DaemonAddr.sa.sa_family = AF_INET; 454850144caSeric 455bfb80540Seric while (p != NULL) 456bfb80540Seric { 457bfb80540Seric register char *f; 458bfb80540Seric register char *v; 459bfb80540Seric 460bfb80540Seric while (isascii(*p) && isspace(*p)) 461bfb80540Seric p++; 462bfb80540Seric if (*p == '\0') 463bfb80540Seric break; 464bfb80540Seric f = p; 465bfb80540Seric p = strchr(p, ','); 466bfb80540Seric if (p != NULL) 467bfb80540Seric *p++ = '\0'; 468bfb80540Seric v = strchr(f, '='); 469bfb80540Seric if (v == NULL) 470bfb80540Seric continue; 471bfb80540Seric while (isascii(*++v) && isspace(*v)) 472bfb80540Seric continue; 473bfb80540Seric 474bfb80540Seric switch (*f) 475bfb80540Seric { 476850144caSeric case 'F': /* address family */ 477850144caSeric if (isascii(*v) && isdigit(*v)) 478850144caSeric DaemonAddr.sa.sa_family = atoi(v); 479850144caSeric #ifdef NETINET 480850144caSeric else if (strcasecmp(v, "inet") == 0) 481850144caSeric DaemonAddr.sa.sa_family = AF_INET; 482850144caSeric #endif 483850144caSeric #ifdef NETISO 484850144caSeric else if (strcasecmp(v, "iso") == 0) 485850144caSeric DaemonAddr.sa.sa_family = AF_ISO; 486850144caSeric #endif 487850144caSeric #ifdef NETNS 488850144caSeric else if (strcasecmp(v, "ns") == 0) 489850144caSeric DaemonAddr.sa.sa_family = AF_NS; 490850144caSeric #endif 491850144caSeric #ifdef NETX25 492850144caSeric else if (strcasecmp(v, "x.25") == 0) 493850144caSeric DaemonAddr.sa.sa_family = AF_CCITT; 494850144caSeric #endif 495850144caSeric else 496850144caSeric syserr("554 Unknown address family %s in Family=option", v); 497850144caSeric break; 498850144caSeric 499850144caSeric case 'A': /* address */ 500850144caSeric switch (DaemonAddr.sa.sa_family) 501850144caSeric { 502850144caSeric #ifdef NETINET 503850144caSeric case AF_INET: 504850144caSeric if (isascii(*v) && isdigit(*v)) 505*b26156f6Seric DaemonAddr.sin.sin_addr.s_addr = htonl(inet_network(v)); 506850144caSeric else 507850144caSeric { 508850144caSeric register struct netent *np; 509850144caSeric 510850144caSeric np = getnetbyname(v); 511850144caSeric if (np == NULL) 512850144caSeric syserr("554 network \"%s\" unknown", v); 513850144caSeric else 514850144caSeric DaemonAddr.sin.sin_addr.s_addr = np->n_net; 515850144caSeric } 516850144caSeric break; 517850144caSeric #endif 518850144caSeric 519850144caSeric default: 520850144caSeric syserr("554 Address= option unsupported for family %d", 521850144caSeric DaemonAddr.sa.sa_family); 522850144caSeric break; 523850144caSeric } 524850144caSeric break; 525850144caSeric 526bfb80540Seric case 'P': /* port */ 527850144caSeric switch (DaemonAddr.sa.sa_family) 528850144caSeric { 529850144caSeric short port; 530850144caSeric 531850144caSeric #ifdef NETINET 532850144caSeric case AF_INET: 533bfb80540Seric if (isascii(*v) && isdigit(*v)) 53476b70c58Seric DaemonAddr.sin.sin_port = htons(atoi(v)); 535bfb80540Seric else 536bfb80540Seric { 537bfb80540Seric register struct servent *sp; 538bfb80540Seric 539bfb80540Seric sp = getservbyname(v, "tcp"); 540bfb80540Seric if (sp == NULL) 541ad977999Seric syserr("554 service \"%s\" unknown", v); 542bfb80540Seric else 543bfb80540Seric DaemonAddr.sin.sin_port = sp->s_port; 544bfb80540Seric } 545bfb80540Seric break; 546850144caSeric #endif 547bfb80540Seric 548850144caSeric #ifdef NETISO 549850144caSeric case AF_ISO: 550850144caSeric /* assume two byte transport selector */ 551bfb80540Seric if (isascii(*v) && isdigit(*v)) 55276b70c58Seric port = htons(atoi(v)); 553bfb80540Seric else 554bfb80540Seric { 555850144caSeric register struct servent *sp; 556bfb80540Seric 557850144caSeric sp = getservbyname(v, "tcp"); 558850144caSeric if (sp == NULL) 559ad977999Seric syserr("554 service \"%s\" unknown", v); 560bfb80540Seric else 561850144caSeric port = sp->s_port; 562850144caSeric } 563850144caSeric bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2); 564850144caSeric break; 565850144caSeric #endif 566850144caSeric 567850144caSeric default: 568850144caSeric syserr("554 Port= option unsupported for family %d", 569850144caSeric DaemonAddr.sa.sa_family); 570850144caSeric break; 571bfb80540Seric } 572bfb80540Seric break; 573bfc1eaf8Seric 574bfc1eaf8Seric case 'L': /* listen queue size */ 575bfc1eaf8Seric ListenQueueSize = atoi(v); 576bfc1eaf8Seric break; 577b35447dbSeric 578b35447dbSeric case 'S': /* send buffer size */ 579b35447dbSeric TcpSndBufferSize = atoi(v); 580b35447dbSeric break; 581b35447dbSeric 582b35447dbSeric case 'R': /* receive buffer size */ 583b35447dbSeric TcpRcvBufferSize = atoi(v); 584b35447dbSeric break; 585bfb80540Seric } 586bfb80540Seric } 587bfb80540Seric } 588bfb80540Seric /* 5897aa493c5Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 5907aa493c5Seric ** 5917aa493c5Seric ** Parameters: 5927aa493c5Seric ** host -- the name of the host. 59348ff0a9dSeric ** port -- the port number to connect to. 594655feedbSeric ** mci -- a pointer to the mail connection information 595655feedbSeric ** structure to be filled in. 596914346b1Seric ** usesecureport -- if set, use a low numbered (reserved) 597914346b1Seric ** port to provide some rudimentary authentication. 5987aa493c5Seric ** 5997aa493c5Seric ** Returns: 6007aa493c5Seric ** An exit code telling whether the connection could be 6017aa493c5Seric ** made and if not why not. 6027aa493c5Seric ** 6037aa493c5Seric ** Side Effects: 6047aa493c5Seric ** none. 6057aa493c5Seric */ 6067aa493c5Seric 607e2f2f828Seric SOCKADDR CurHostAddr; /* address of current host */ 60871ff6caaSeric 609b31e7f2bSeric int 610655feedbSeric makeconnection(host, port, mci, usesecureport) 6117aa493c5Seric char *host; 612210215eaSeric u_short port; 613b31e7f2bSeric register MCI *mci; 614914346b1Seric bool usesecureport; 6157aa493c5Seric { 616*b26156f6Seric register int i = 0; 617*b26156f6Seric register int s; 61804344589Sbloom register struct hostent *hp = (struct hostent *)NULL; 619e2f2f828Seric SOCKADDR addr; 6206286bb75Sbloom int sav_errno; 621e2f2f828Seric int addrlen; 622*b26156f6Seric bool firstconnect; 6239d4a8008Seric #if NAMED_BIND 624134746fbSeric extern int h_errno; 625134746fbSeric #endif 6267aa493c5Seric 6277aa493c5Seric /* 6287aa493c5Seric ** Set up the address for the mailer. 62971096d12Seric ** Accept "[a.b.c.d]" syntax for host name. 6307aa493c5Seric */ 6317aa493c5Seric 6329d4a8008Seric #if NAMED_BIND 633794bdbb9Smiriam h_errno = 0; 634134746fbSeric #endif 635794bdbb9Smiriam errno = 0; 636967778e2Seric bzero(&CurHostAddr, sizeof CurHostAddr); 637c931b82bSeric SmtpPhase = mci->mci_phase = "initial connection"; 638d945ebe8Seric CurHostName = host; 639794bdbb9Smiriam 64071096d12Seric if (host[0] == '[') 64171096d12Seric { 642a44d5a5eSeric long hid; 6436c2c3107Seric register char *p = strchr(host, ']'); 64471096d12Seric 645a44d5a5eSeric if (p != NULL) 64671096d12Seric { 647a44d5a5eSeric *p = '\0'; 6484d9c42c2Seric #ifdef NETINET 649a44d5a5eSeric hid = inet_addr(&host[1]); 650a7e21fe6Seric if (hid == -1) 6514d9c42c2Seric #endif 652a7e21fe6Seric { 653a7e21fe6Seric /* try it as a host name (avoid MX lookup) */ 654a7e21fe6Seric hp = gethostbyname(&host[1]); 655d8984352Seric if (hp == NULL && p[-1] == '.') 656d8984352Seric { 657*b26156f6Seric #if NAMED_BIND 658*b26156f6Seric int oldopts = _res.options; 659*b26156f6Seric 660*b26156f6Seric _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 661*b26156f6Seric #endif 662d8984352Seric p[-1] = '\0'; 663d8984352Seric hp = gethostbyname(&host[1]); 664d8984352Seric p[-1] = '.'; 665*b26156f6Seric #if NAMED_BIND 666*b26156f6Seric _res.options = oldopts; 667*b26156f6Seric #endif 668d8984352Seric } 669a7e21fe6Seric *p = ']'; 670a7e21fe6Seric goto gothostent; 671a7e21fe6Seric } 672a44d5a5eSeric *p = ']'; 67371096d12Seric } 674a7e21fe6Seric if (p == NULL) 67571096d12Seric { 67608b25121Seric usrerr("553 Invalid numeric domain spec \"%s\"", host); 67771096d12Seric return (EX_NOHOST); 67871096d12Seric } 6794d9c42c2Seric #ifdef NETINET 6804d9c42c2Seric addr.sin.sin_family = AF_INET; /*XXX*/ 68183c1f4bcSeric addr.sin.sin_addr.s_addr = hid; 6824d9c42c2Seric #endif 68371096d12Seric } 6841c71e510Seric else 6851c71e510Seric { 686d8984352Seric register char *p = &host[strlen(host) - 1]; 687d8984352Seric 68804344589Sbloom hp = gethostbyname(host); 689d8984352Seric if (hp == NULL && *p == '.') 690d8984352Seric { 691*b26156f6Seric #if NAMED_BIND 692*b26156f6Seric int oldopts = _res.options; 693*b26156f6Seric 694*b26156f6Seric _res.options &= ~(RES_DEFNAMES|RES_DNSRCH); 695*b26156f6Seric #endif 696d8984352Seric *p = '\0'; 697d8984352Seric hp = gethostbyname(host); 698d8984352Seric *p = '.'; 699*b26156f6Seric #if NAMED_BIND 700*b26156f6Seric _res.options = oldopts; 701*b26156f6Seric #endif 702d8984352Seric } 703a7e21fe6Seric gothostent: 704794bdbb9Smiriam if (hp == NULL) 705794bdbb9Smiriam { 7069d4a8008Seric #if NAMED_BIND 707*b26156f6Seric /* check for name server timeouts */ 708*b26156f6Seric if (errno == ETIMEDOUT || h_errno == TRY_AGAIN || 709*b26156f6Seric (errno == ECONNREFUSED && UseNameServer)) 710*b26156f6Seric { 711*b26156f6Seric mci->mci_status = "4.4.3"; 71252308a50Seric return (EX_TEMPFAIL); 713*b26156f6Seric } 714134746fbSeric #endif 7157aa493c5Seric return (EX_NOHOST); 716794bdbb9Smiriam } 71783c1f4bcSeric addr.sa.sa_family = hp->h_addrtype; 71883c1f4bcSeric switch (hp->h_addrtype) 71983c1f4bcSeric { 72083c1f4bcSeric #ifdef NETINET 72183c1f4bcSeric case AF_INET: 722e2f2f828Seric bcopy(hp->h_addr, 72383c1f4bcSeric &addr.sin.sin_addr, 724*b26156f6Seric INADDRSZ); 72583c1f4bcSeric break; 72683c1f4bcSeric #endif 72783c1f4bcSeric 72883c1f4bcSeric default: 729e2f2f828Seric bcopy(hp->h_addr, 73083c1f4bcSeric addr.sa.sa_data, 731e2f2f828Seric hp->h_length); 73283c1f4bcSeric break; 73383c1f4bcSeric } 73404344589Sbloom i = 1; 7351c71e510Seric } 7361c71e510Seric 7371c71e510Seric /* 7381c71e510Seric ** Determine the port number. 7391c71e510Seric */ 7401c71e510Seric 741fd7c0790Seric if (port != 0) 742e2f2f828Seric port = htons(port); 743fd7c0790Seric else 7441c71e510Seric { 7451c71e510Seric register struct servent *sp = getservbyname("smtp", "tcp"); 7461c71e510Seric 7471c71e510Seric if (sp == NULL) 7481c71e510Seric { 749ad977999Seric syserr("554 makeconnection: service \"smtp\" unknown"); 750e5311662Seric port = htons(25); 7511c71e510Seric } 752e5311662Seric else 753e2f2f828Seric port = sp->s_port; 754e2f2f828Seric } 755e2f2f828Seric 75683c1f4bcSeric switch (addr.sa.sa_family) 757e2f2f828Seric { 7584d9c42c2Seric #ifdef NETINET 759e2f2f828Seric case AF_INET: 76083c1f4bcSeric addr.sin.sin_port = port; 761e2f2f828Seric addrlen = sizeof (struct sockaddr_in); 762e2f2f828Seric break; 7634d9c42c2Seric #endif 764e2f2f828Seric 765e2f2f828Seric #ifdef NETISO 766e2f2f828Seric case AF_ISO: 767e2f2f828Seric /* assume two byte transport selector */ 768e2f2f828Seric bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 769e2f2f828Seric addrlen = sizeof (struct sockaddr_iso); 770e2f2f828Seric break; 771e2f2f828Seric #endif 772e2f2f828Seric 773e2f2f828Seric default: 77483c1f4bcSeric syserr("Can't connect to address family %d", addr.sa.sa_family); 775e2f2f828Seric return (EX_NOHOST); 7761c71e510Seric } 7777aa493c5Seric 7787aa493c5Seric /* 7797aa493c5Seric ** Try to actually open the connection. 7807aa493c5Seric */ 7817aa493c5Seric 782e17a3a5aSeric #ifdef XLA 783e17a3a5aSeric /* if too many connections, don't bother trying */ 784e17a3a5aSeric if (!xla_noqueue_ok(host)) 785e17a3a5aSeric return EX_TEMPFAIL; 786e17a3a5aSeric #endif 787e17a3a5aSeric 788*b26156f6Seric firstconnect = TRUE; 789aea02ca1Seric for (;;) 790aea02ca1Seric { 79161e4310fSeric if (tTd(16, 1)) 792e2f2f828Seric printf("makeconnection (%s [%s])\n", 793e2f2f828Seric host, anynet_ntoa(&addr)); 7947aa493c5Seric 795226e3022Seric /* save for logging */ 796226e3022Seric CurHostAddr = addr; 797226e3022Seric 798914346b1Seric if (usesecureport) 799914346b1Seric { 800914346b1Seric int rport = IPPORT_RESERVED - 1; 801914346b1Seric 802914346b1Seric s = rresvport(&rport); 803914346b1Seric } 804914346b1Seric else 805914346b1Seric { 806af5e902cSeric s = socket(AF_INET, SOCK_STREAM, 0); 807914346b1Seric } 8087aa493c5Seric if (s < 0) 8097aa493c5Seric { 8106286bb75Sbloom sav_errno = errno; 811914346b1Seric syserr("makeconnection: no socket"); 8127aa493c5Seric goto failure; 8137aa493c5Seric } 8147aa493c5Seric 815b35447dbSeric #ifdef SO_SNDBUF 816b35447dbSeric if (TcpSndBufferSize > 0) 817b35447dbSeric { 818b35447dbSeric if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 819bf217a95Seric (char *) &TcpSndBufferSize, 820b35447dbSeric sizeof(TcpSndBufferSize)) < 0) 821b35447dbSeric syserr("makeconnection: setsockopt(SO_SNDBUF)"); 822b35447dbSeric } 823b35447dbSeric #endif 824b35447dbSeric 82561e4310fSeric if (tTd(16, 1)) 826b31e7f2bSeric printf("makeconnection: fd=%d\n", s); 8271b6e4a15Seric 8281b6e4a15Seric /* turn on network debugging? */ 829a2ef5fa4Seric if (tTd(16, 101)) 83052308a50Seric { 83152308a50Seric int on = 1; 8326173568dSeric (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 833aea02ca1Seric (char *)&on, sizeof on); 83452308a50Seric } 83587d6e633Srick if (CurEnv->e_xfp != NULL) 836877a6142Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 8374bd6a662Seric errno = 0; /* for debugging */ 838e2f2f828Seric if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 839aea02ca1Seric break; 840aea02ca1Seric 841*b26156f6Seric /* if running demand-dialed connection, try again */ 842*b26156f6Seric if (DialDelay > 0 && firstconnect) 843*b26156f6Seric { 844*b26156f6Seric if (tTd(16, 1)) 845*b26156f6Seric printf("Connect failed (%s); trying again...\n", 846*b26156f6Seric errstring(sav_errno)); 847*b26156f6Seric firstconnect = FALSE; 848*b26156f6Seric sleep(DialDelay); 849*b26156f6Seric continue; 850*b26156f6Seric } 851*b26156f6Seric 852aea02ca1Seric /* couldn't connect.... figure out why */ 8536286bb75Sbloom sav_errno = errno; 8546286bb75Sbloom (void) close(s); 855*b26156f6Seric if (hp != NULL && hp->h_addr_list[i]) 85604344589Sbloom { 857aea02ca1Seric if (tTd(16, 1)) 858e2f2f828Seric printf("Connect failed (%s); trying new address....\n", 859e2f2f828Seric errstring(sav_errno)); 86083c1f4bcSeric switch (addr.sa.sa_family) 86183c1f4bcSeric { 86283c1f4bcSeric #ifdef NETINET 86383c1f4bcSeric case AF_INET: 864e2f2f828Seric bcopy(hp->h_addr_list[i++], 86583c1f4bcSeric &addr.sin.sin_addr, 866*b26156f6Seric INADDRSZ); 86783c1f4bcSeric break; 86883c1f4bcSeric #endif 86983c1f4bcSeric 87083c1f4bcSeric default: 871e2f2f828Seric bcopy(hp->h_addr_list[i++], 87283c1f4bcSeric addr.sa.sa_data, 873914346b1Seric hp->h_length); 87483c1f4bcSeric break; 87583c1f4bcSeric } 876aea02ca1Seric continue; 87704344589Sbloom } 87804344589Sbloom 8797aa493c5Seric /* failure, decide if temporary or not */ 8807aa493c5Seric failure: 881244b09d1Seric #ifdef XLA 882244b09d1Seric xla_host_end(host); 883244b09d1Seric #endif 884e2de2524Seric if (transienterror(sav_errno)) 885e2de2524Seric return EX_TEMPFAIL; 886e2de2524Seric else 88787d6e633Srick { 88808b25121Seric message("%s", errstring(sav_errno)); 8897aa493c5Seric return (EX_UNAVAILABLE); 8907aa493c5Seric } 8917aa493c5Seric } 8927aa493c5Seric 8937aa493c5Seric /* connection ok, put it into canonical form */ 894335eae58Seric if ((mci->mci_out = fdopen(s, "w")) == NULL || 895335eae58Seric (s = dup(s)) < 0 || 896ab81ee53Seric (mci->mci_in = fdopen(s, "r")) == NULL) 897335eae58Seric { 898335eae58Seric syserr("cannot open SMTP client channel, fd=%d", s); 899335eae58Seric return EX_TEMPFAIL; 900335eae58Seric } 9017aa493c5Seric 902dca8e1f7Seric return (EX_OK); 9037aa493c5Seric } 904444eaf03Seric /* 905444eaf03Seric ** MYHOSTNAME -- return the name of this host. 906444eaf03Seric ** 907444eaf03Seric ** Parameters: 908444eaf03Seric ** hostbuf -- a place to return the name of this host. 909897f1869Seric ** size -- the size of hostbuf. 910444eaf03Seric ** 911444eaf03Seric ** Returns: 912444eaf03Seric ** A list of aliases for this host. 913444eaf03Seric ** 914444eaf03Seric ** Side Effects: 915d8d0a4aeSeric ** Adds numeric codes to $=w. 916444eaf03Seric */ 917444eaf03Seric 918*b26156f6Seric struct hostent * 919897f1869Seric myhostname(hostbuf, size) 920444eaf03Seric char hostbuf[]; 921897f1869Seric int size; 922444eaf03Seric { 92338ad259dSeric register struct hostent *hp; 924444eaf03Seric extern struct hostent *gethostbyname(); 925*b26156f6Seric extern bool getcanonname(); 926*b26156f6Seric extern int h_errno; 927444eaf03Seric 928af5e902cSeric if (gethostname(hostbuf, size) < 0) 929af5e902cSeric { 930af5e902cSeric (void) strcpy(hostbuf, "localhost"); 931af5e902cSeric } 932a44d5a5eSeric hp = gethostbyname(hostbuf); 9334a5c6430Seric if (hp == NULL) 934*b26156f6Seric return NULL; 935*b26156f6Seric if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL) 936423161fbSeric { 93735852b23Seric (void) strncpy(hostbuf, hp->h_name, size - 1); 93835852b23Seric hostbuf[size - 1] = '\0'; 939*b26156f6Seric } 9404a5c6430Seric 9414a5c6430Seric #if NAMED_BIND 942*b26156f6Seric /* 943*b26156f6Seric ** If still no dot, try DNS directly (i.e., avoid NIS problems). 944*b26156f6Seric ** This ought to be driven from the configuration file, but 945*b26156f6Seric ** we are called before the configuration is read. We could 946*b26156f6Seric ** check for an /etc/resolv.conf file, but that isn't required. 947*b26156f6Seric ** All in all, a bit of a mess. 948*b26156f6Seric */ 9498ef91e8aSeric 950*b26156f6Seric if (strchr(hostbuf, '.') == NULL && 951*b26156f6Seric !getcanonname(hostbuf, size, TRUE) && 952*b26156f6Seric h_errno == TRY_AGAIN) 9538ef91e8aSeric { 954*b26156f6Seric /* try twice in case name server not yet started up */ 955*b26156f6Seric message("My unqualifed host name (%s) unknown to DNS; sleeping for retry", 9568ef91e8aSeric hostbuf); 957*b26156f6Seric sleep(60); 958*b26156f6Seric if (!getcanonname(hostbuf, size, TRUE)) 959*b26156f6Seric errno = h_errno + E_DNSBASE; 960747df804Seric } 961747df804Seric #endif 962*b26156f6Seric return (hp); 9637364df9fSeric } 964cb452edcSeric /* 9659f8b0eadSeric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 9669f8b0eadSeric ** 9679f8b0eadSeric ** Uses RFC1413 protocol to try to get info from the other end. 968320e0d1cSeric ** 969320e0d1cSeric ** Parameters: 970320e0d1cSeric ** fd -- the descriptor 971320e0d1cSeric ** 972320e0d1cSeric ** Returns: 9739f8b0eadSeric ** The user@host information associated with this descriptor. 974320e0d1cSeric */ 975320e0d1cSeric 9769f8b0eadSeric static jmp_buf CtxAuthTimeout; 9779f8b0eadSeric 978*b26156f6Seric static void 9799f8b0eadSeric authtimeout() 9809f8b0eadSeric { 9819f8b0eadSeric longjmp(CtxAuthTimeout, 1); 9829f8b0eadSeric } 9839f8b0eadSeric 984320e0d1cSeric char * 9859f8b0eadSeric getauthinfo(fd) 986320e0d1cSeric int fd; 987320e0d1cSeric { 9889f8b0eadSeric int falen; 989a5546e24Seric register char *p; 9909f8b0eadSeric SOCKADDR la; 9919f8b0eadSeric int lalen; 9929f8b0eadSeric register struct servent *sp; 9939f8b0eadSeric int s; 9949f8b0eadSeric int i; 9959f8b0eadSeric EVENT *ev; 996579270a3Seric int nleft; 997f036c8d7Seric char ibuf[MAXNAME + 1]; 9989f8b0eadSeric static char hbuf[MAXNAME * 2 + 2]; 9999f8b0eadSeric extern char *hostnamebyanyaddr(); 10009f8b0eadSeric extern char RealUserName[]; /* main.c */ 1001320e0d1cSeric 1002e29a76d1Seric falen = sizeof RealHostAddr; 1003*b26156f6Seric if (isatty(fd) || getpeername(fd, &RealHostAddr.sa, &falen) < 0 || 1004*b26156f6Seric falen <= 0 || RealHostAddr.sa.sa_family == 0) 10059f8b0eadSeric { 10069f8b0eadSeric (void) sprintf(hbuf, "%s@localhost", RealUserName); 100753853673Seric if (tTd(9, 1)) 10089f8b0eadSeric printf("getauthinfo: %s\n", hbuf); 1009320e0d1cSeric return hbuf; 1010320e0d1cSeric } 10119f8b0eadSeric 1012e29a76d1Seric if (RealHostName == NULL) 1013e29a76d1Seric { 1014e29a76d1Seric /* translate that to a host name */ 1015e29a76d1Seric RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 1016e29a76d1Seric } 1017e29a76d1Seric 101893b3215bSeric if (TimeOuts.to_ident == 0) 101993b3215bSeric goto noident; 102093b3215bSeric 10219f8b0eadSeric lalen = sizeof la; 1022e29a76d1Seric if (RealHostAddr.sa.sa_family != AF_INET || 10239f8b0eadSeric getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 10249f8b0eadSeric la.sa.sa_family != AF_INET) 10259f8b0eadSeric { 10269f8b0eadSeric /* no ident info */ 10279f8b0eadSeric goto noident; 10289f8b0eadSeric } 10299f8b0eadSeric 10309f8b0eadSeric /* create ident query */ 103181d2944fSeric (void) sprintf(ibuf, "%d,%d\r\n", 1032e29a76d1Seric ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port)); 10339f8b0eadSeric 10349f8b0eadSeric /* create local address */ 1035d6af7dadSeric la.sin.sin_port = 0; 10369f8b0eadSeric 10379f8b0eadSeric /* create foreign address */ 10389f8b0eadSeric sp = getservbyname("auth", "tcp"); 10399f8b0eadSeric if (sp != NULL) 1040e29a76d1Seric RealHostAddr.sin.sin_port = sp->s_port; 10419f8b0eadSeric else 1042e29a76d1Seric RealHostAddr.sin.sin_port = htons(113); 10439f8b0eadSeric 10449f8b0eadSeric s = -1; 10459f8b0eadSeric if (setjmp(CtxAuthTimeout) != 0) 10469f8b0eadSeric { 10479f8b0eadSeric if (s >= 0) 10489f8b0eadSeric (void) close(s); 10499f8b0eadSeric goto noident; 10509f8b0eadSeric } 10519f8b0eadSeric 10529f8b0eadSeric /* put a timeout around the whole thing */ 1053a0f780efSeric ev = setevent(TimeOuts.to_ident, authtimeout, 0); 10549f8b0eadSeric 1055d6af7dadSeric /* connect to foreign IDENT server using same address as SMTP socket */ 10569f8b0eadSeric s = socket(AF_INET, SOCK_STREAM, 0); 10579f8b0eadSeric if (s < 0) 10589f8b0eadSeric { 10599f8b0eadSeric clrevent(ev); 10609f8b0eadSeric goto noident; 10619f8b0eadSeric } 1062d6af7dadSeric if (bind(s, &la.sa, sizeof la.sin) < 0 || 1063e29a76d1Seric connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0) 10649f8b0eadSeric { 10657c201575Seric goto closeident; 10669f8b0eadSeric } 10679f8b0eadSeric 106853853673Seric if (tTd(9, 10)) 106981d2944fSeric printf("getauthinfo: sent %s", ibuf); 10709f8b0eadSeric 10719f8b0eadSeric /* send query */ 107281d2944fSeric if (write(s, ibuf, strlen(ibuf)) < 0) 10739f8b0eadSeric goto closeident; 10749f8b0eadSeric 10759f8b0eadSeric /* get result */ 107681d2944fSeric p = &ibuf[0]; 1077*b26156f6Seric nleft = sizeof ibuf - 1; 1078579270a3Seric while ((i = read(s, p, nleft)) > 0) 1079579270a3Seric { 1080579270a3Seric p += i; 1081579270a3Seric nleft -= i; 1082579270a3Seric } 10839f8b0eadSeric (void) close(s); 10849f8b0eadSeric clrevent(ev); 108581d2944fSeric if (i < 0 || p == &ibuf[0]) 10869f8b0eadSeric goto noident; 1087579270a3Seric 1088579270a3Seric if (*--p == '\n' && *--p == '\r') 1089579270a3Seric p--; 1090579270a3Seric *++p = '\0'; 10919f8b0eadSeric 109253853673Seric if (tTd(9, 3)) 109381d2944fSeric printf("getauthinfo: got %s\n", ibuf); 10949f8b0eadSeric 10959f8b0eadSeric /* parse result */ 109681d2944fSeric p = strchr(ibuf, ':'); 10979f8b0eadSeric if (p == NULL) 10989f8b0eadSeric { 10999f8b0eadSeric /* malformed response */ 11009f8b0eadSeric goto noident; 11019f8b0eadSeric } 11029f8b0eadSeric while (isascii(*++p) && isspace(*p)) 11039f8b0eadSeric continue; 11049f8b0eadSeric if (strncasecmp(p, "userid", 6) != 0) 11059f8b0eadSeric { 11069f8b0eadSeric /* presumably an error string */ 11079f8b0eadSeric goto noident; 11089f8b0eadSeric } 11099f8b0eadSeric p += 6; 11109f8b0eadSeric while (isascii(*p) && isspace(*p)) 11119f8b0eadSeric p++; 11129f8b0eadSeric if (*p++ != ':') 11139f8b0eadSeric { 11149f8b0eadSeric /* either useridxx or malformed response */ 11159f8b0eadSeric goto noident; 11169f8b0eadSeric } 11179f8b0eadSeric 11189f8b0eadSeric /* p now points to the OSTYPE field */ 11199f8b0eadSeric p = strchr(p, ':'); 11209f8b0eadSeric if (p == NULL) 11219f8b0eadSeric { 11229f8b0eadSeric /* malformed response */ 11239f8b0eadSeric goto noident; 11249f8b0eadSeric } 112553853673Seric 112653853673Seric /* 1413 says don't do this -- but it's broken otherwise */ 112753853673Seric while (isascii(*++p) && isspace(*p)) 112853853673Seric continue; 11299f8b0eadSeric 1130a7763879Seric /* p now points to the authenticated name -- copy carefully */ 113181d2944fSeric cleanstrcpy(hbuf, p, MAXNAME); 1132a7763879Seric hbuf[i++] = '@'; 1133a7763879Seric strcpy(&hbuf[i], RealHostName == NULL ? "localhost" : RealHostName); 113453853673Seric goto finish; 113553853673Seric 11367c201575Seric closeident: 11377c201575Seric (void) close(s); 11387c201575Seric clrevent(ev); 11397c201575Seric 114053853673Seric noident: 1141f7869e68Seric if (RealHostName == NULL) 1142f7869e68Seric { 1143f7869e68Seric if (tTd(9, 1)) 1144f7869e68Seric printf("getauthinfo: NULL\n"); 1145f7869e68Seric return NULL; 1146f7869e68Seric } 114753853673Seric (void) strcpy(hbuf, RealHostName); 114853853673Seric 114953853673Seric finish: 1150f7869e68Seric if (RealHostName != NULL && RealHostName[0] != '[') 11519f8b0eadSeric { 11529f8b0eadSeric p = &hbuf[strlen(hbuf)]; 11539f8b0eadSeric (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr)); 11549f8b0eadSeric } 115553853673Seric if (tTd(9, 1)) 11569f8b0eadSeric printf("getauthinfo: %s\n", hbuf); 11579f8b0eadSeric return hbuf; 11589f8b0eadSeric } 1159320e0d1cSeric /* 116008de856eSeric ** HOST_MAP_LOOKUP -- turn a hostname into canonical form 116115d084d5Seric ** 116215d084d5Seric ** Parameters: 116305b57da8Seric ** map -- a pointer to this map (unused). 116408de856eSeric ** name -- the (presumably unqualified) hostname. 116500b385a9Seric ** av -- unused -- for compatibility with other mapping 1166d798a1deSeric ** functions. 11672d29d43aSeric ** statp -- an exit status (out parameter) -- set to 11682d29d43aSeric ** EX_TEMPFAIL if the name server is unavailable. 116915d084d5Seric ** 117015d084d5Seric ** Returns: 117115d084d5Seric ** The mapping, if found. 117215d084d5Seric ** NULL if no mapping found. 117315d084d5Seric ** 117415d084d5Seric ** Side Effects: 117515d084d5Seric ** Looks up the host specified in hbuf. If it is not 117615d084d5Seric ** the canonical name for that host, return the canonical 117715d084d5Seric ** name. 1178f36ede03Sbostic */ 1179cb452edcSeric 118015d084d5Seric char * 118100b385a9Seric host_map_lookup(map, name, av, statp) 118205b57da8Seric MAP *map; 118308de856eSeric char *name; 118400b385a9Seric char **av; 11852d29d43aSeric int *statp; 118699f7cf32Seric { 118799f7cf32Seric register struct hostent *hp; 1188*b26156f6Seric struct in_addr in_addr; 118905b57da8Seric char *cp; 1190eea91d78Seric register STAB *s; 119100b385a9Seric char hbuf[MAXNAME]; 1192eea91d78Seric extern struct hostent *gethostbyaddr(); 11939d4a8008Seric #if NAMED_BIND 1194eea91d78Seric extern int h_errno; 1195c304a798Seric #endif 11965f78836eSmiriam 1197f36ede03Sbostic /* 1198eea91d78Seric ** See if we have already looked up this name. If so, just 1199eea91d78Seric ** return it. 1200eea91d78Seric */ 1201eea91d78Seric 120208de856eSeric s = stab(name, ST_NAMECANON, ST_ENTER); 1203eea91d78Seric if (bitset(NCF_VALID, s->s_namecanon.nc_flags)) 1204eea91d78Seric { 1205f92c3297Seric if (tTd(9, 1)) 120608de856eSeric printf("host_map_lookup(%s) => CACHE %s\n", 120708de856eSeric name, s->s_namecanon.nc_cname); 1208eea91d78Seric errno = s->s_namecanon.nc_errno; 12099d4a8008Seric #if NAMED_BIND 1210eea91d78Seric h_errno = s->s_namecanon.nc_herrno; 1211c304a798Seric #endif 1212eea91d78Seric *statp = s->s_namecanon.nc_stat; 121392270fb3Seric if (CurEnv->e_message == NULL && *statp == EX_TEMPFAIL) 1214ed63aae0Seric { 1215ed63aae0Seric sprintf(hbuf, "%s: Name server timeout", 1216ed63aae0Seric shortenstring(name, 33)); 1217ed63aae0Seric CurEnv->e_message = newstr(hbuf); 1218ed63aae0Seric } 1219eea91d78Seric return s->s_namecanon.nc_cname; 1220eea91d78Seric } 1221eea91d78Seric 1222eea91d78Seric /* 1223eea91d78Seric ** If first character is a bracket, then it is an address 1224eea91d78Seric ** lookup. Address is copied into a temporary buffer to 122508de856eSeric ** strip the brackets and to preserve name if address is 1226eea91d78Seric ** unknown. 1227f36ede03Sbostic */ 122815d084d5Seric 122908de856eSeric if (*name != '[') 123015d084d5Seric { 1231d798a1deSeric extern bool getcanonname(); 1232d798a1deSeric 12338cb4653dSeric if (tTd(9, 1)) 123408de856eSeric printf("host_map_lookup(%s) => ", name); 1235eea91d78Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 123608de856eSeric (void) strcpy(hbuf, name); 12371f2ff1a4Seric if (getcanonname(hbuf, sizeof hbuf - 1, TRUE)) 12389040ec4fSeric { 12399040ec4fSeric if (tTd(9, 1)) 12409040ec4fSeric printf("%s\n", hbuf); 124100b385a9Seric cp = map_rewrite(map, hbuf, strlen(hbuf), av); 124200b385a9Seric s->s_namecanon.nc_cname = newstr(cp); 124300b385a9Seric return cp; 12449040ec4fSeric } 124515d084d5Seric else 12469040ec4fSeric { 12472d29d43aSeric register struct hostent *hp; 12482d29d43aSeric 1249c304a798Seric s->s_namecanon.nc_errno = errno; 12509d4a8008Seric #if NAMED_BIND 1251c304a798Seric s->s_namecanon.nc_herrno = h_errno; 12529040ec4fSeric if (tTd(9, 1)) 12532d29d43aSeric printf("FAIL (%d)\n", h_errno); 12542d29d43aSeric switch (h_errno) 12552d29d43aSeric { 12562d29d43aSeric case TRY_AGAIN: 125789cb2793Seric if (UseNameServer) 12588820d51bSeric { 1259e0326f4fSeric sprintf(hbuf, "%s: Name server timeout", 1260ed63aae0Seric shortenstring(name, 33)); 1261e0326f4fSeric message("%s", hbuf); 12628820d51bSeric if (CurEnv->e_message == NULL) 1263e0326f4fSeric CurEnv->e_message = newstr(hbuf); 12648820d51bSeric } 12652d29d43aSeric *statp = EX_TEMPFAIL; 12662d29d43aSeric break; 12672d29d43aSeric 12682d29d43aSeric case HOST_NOT_FOUND: 12692d29d43aSeric *statp = EX_NOHOST; 12702d29d43aSeric break; 12712d29d43aSeric 12722d29d43aSeric case NO_RECOVERY: 12732d29d43aSeric *statp = EX_SOFTWARE; 12742d29d43aSeric break; 12752d29d43aSeric 12762d29d43aSeric default: 12772d29d43aSeric *statp = EX_UNAVAILABLE; 12782d29d43aSeric break; 12792d29d43aSeric } 1280c304a798Seric #else 1281c304a798Seric if (tTd(9, 1)) 1282c304a798Seric printf("FAIL\n"); 1283c304a798Seric *statp = EX_NOHOST; 1284c304a798Seric #endif 1285eea91d78Seric s->s_namecanon.nc_stat = *statp; 1286*b26156f6Seric if ((*statp != EX_TEMPFAIL && *statp != EX_NOHOST) || 1287*b26156f6Seric UseNameServer) 128815d084d5Seric return NULL; 12892d29d43aSeric 12902d29d43aSeric /* 12912d29d43aSeric ** Try to look it up in /etc/hosts 12922d29d43aSeric */ 12932d29d43aSeric 129408de856eSeric hp = gethostbyname(name); 12952d29d43aSeric if (hp == NULL) 12962d29d43aSeric { 12972d29d43aSeric /* no dice there either */ 1298eea91d78Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 12992d29d43aSeric return NULL; 13002d29d43aSeric } 13012d29d43aSeric 1302eea91d78Seric s->s_namecanon.nc_stat = *statp = EX_OK; 130300b385a9Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 130400b385a9Seric s->s_namecanon.nc_cname = newstr(cp); 130500b385a9Seric return cp; 130615d084d5Seric } 13079040ec4fSeric } 130808de856eSeric if ((cp = strchr(name, ']')) == NULL) 130915d084d5Seric return (NULL); 131034e39927Sbostic *cp = '\0'; 1311*b26156f6Seric in_addr.s_addr = inet_addr(&name[1]); 131238ad259dSeric 131338ad259dSeric /* nope -- ask the name server */ 1314*b26156f6Seric hp = gethostbyaddr((char *)&in_addr, INADDRSZ, AF_INET); 1315eea91d78Seric s->s_namecanon.nc_errno = errno; 13169d4a8008Seric #if NAMED_BIND 1317eea91d78Seric s->s_namecanon.nc_herrno = h_errno; 1318c304a798Seric #endif 1319eea91d78Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 13205f78836eSmiriam if (hp == NULL) 1321eea91d78Seric { 1322eea91d78Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 132315d084d5Seric return (NULL); 1324eea91d78Seric } 132515d084d5Seric 132638ad259dSeric /* found a match -- copy out */ 132700b385a9Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 1328eea91d78Seric s->s_namecanon.nc_stat = *statp = EX_OK; 132900b385a9Seric s->s_namecanon.nc_cname = newstr(cp); 133000b385a9Seric return cp; 133199f7cf32Seric } 1332e2f2f828Seric /* 1333e2f2f828Seric ** ANYNET_NTOA -- convert a network address to printable form. 1334e2f2f828Seric ** 1335e2f2f828Seric ** Parameters: 1336e2f2f828Seric ** sap -- a pointer to a sockaddr structure. 1337e2f2f828Seric ** 1338e2f2f828Seric ** Returns: 1339e2f2f828Seric ** A printable version of that sockaddr. 1340e2f2f828Seric */ 1341e2f2f828Seric 1342e2f2f828Seric char * 1343e2f2f828Seric anynet_ntoa(sap) 1344e2f2f828Seric register SOCKADDR *sap; 1345e2f2f828Seric { 1346e2f2f828Seric register char *bp; 1347e2f2f828Seric register char *ap; 1348e2f2f828Seric int l; 1349e387851eSeric static char buf[100]; 1350e2f2f828Seric 13518cb4653dSeric /* check for null/zero family */ 13528cb4653dSeric if (sap == NULL) 13538cb4653dSeric return "NULLADDR"; 13548cb4653dSeric if (sap->sa.sa_family == 0) 13558cb4653dSeric return "0"; 13568cb4653dSeric 1357e387851eSeric switch (sap->sa.sa_family) 1358e387851eSeric { 1359139b52c8Seric #ifdef NETUNIX 1360e387851eSeric case AF_UNIX: 1361c24cf5a4Seric if (sap->sunix.sun_path[0] != '\0') 1362c24cf5a4Seric sprintf(buf, "[UNIX: %.64s]", sap->sunix.sun_path); 1363e387851eSeric else 1364e387851eSeric sprintf(buf, "[UNIX: localhost]"); 1365e387851eSeric return buf; 1366e387851eSeric #endif 1367e387851eSeric 136883c1f4bcSeric #ifdef NETINET 1369e387851eSeric case AF_INET: 1370e2f2f828Seric return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr); 137183c1f4bcSeric #endif 1372e2f2f828Seric 1373e387851eSeric default: 1374e387851eSeric /* this case is only to ensure syntactic correctness */ 1375e387851eSeric break; 1376e387851eSeric } 1377e387851eSeric 1378e2f2f828Seric /* unknown family -- just dump bytes */ 137983c1f4bcSeric (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 1380e2f2f828Seric bp = &buf[strlen(buf)]; 138183c1f4bcSeric ap = sap->sa.sa_data; 138283c1f4bcSeric for (l = sizeof sap->sa.sa_data; --l >= 0; ) 1383e2f2f828Seric { 1384e2f2f828Seric (void) sprintf(bp, "%02x:", *ap++ & 0377); 1385e2f2f828Seric bp += 3; 1386e2f2f828Seric } 1387e2f2f828Seric *--bp = '\0'; 1388e2f2f828Seric return buf; 1389e2f2f828Seric } 13909f8b0eadSeric /* 13919f8b0eadSeric ** HOSTNAMEBYANYADDR -- return name of host based on address 13929f8b0eadSeric ** 13939f8b0eadSeric ** Parameters: 13949f8b0eadSeric ** sap -- SOCKADDR pointer 13959f8b0eadSeric ** 13969f8b0eadSeric ** Returns: 13979f8b0eadSeric ** text representation of host name. 13989f8b0eadSeric ** 13999f8b0eadSeric ** Side Effects: 14009f8b0eadSeric ** none. 14019f8b0eadSeric */ 14029f8b0eadSeric 14039f8b0eadSeric char * 14049f8b0eadSeric hostnamebyanyaddr(sap) 14059f8b0eadSeric register SOCKADDR *sap; 14069f8b0eadSeric { 14079f8b0eadSeric register struct hostent *hp; 14083490b9dfSeric int saveretry; 14093490b9dfSeric 14109d4a8008Seric #if NAMED_BIND 14113490b9dfSeric /* shorten name server timeout to avoid higher level timeouts */ 14123490b9dfSeric saveretry = _res.retry; 14133490b9dfSeric _res.retry = 3; 14143490b9dfSeric #endif /* NAMED_BIND */ 14153490b9dfSeric 14169f8b0eadSeric switch (sap->sa.sa_family) 14179f8b0eadSeric { 14189f8b0eadSeric #ifdef NETINET 14199f8b0eadSeric case AF_INET: 14209f8b0eadSeric hp = gethostbyaddr((char *) &sap->sin.sin_addr, 1421*b26156f6Seric INADDRSZ, 14229f8b0eadSeric AF_INET); 14239f8b0eadSeric break; 14249f8b0eadSeric #endif 14259f8b0eadSeric 14269f8b0eadSeric #ifdef NETISO 14279f8b0eadSeric case AF_ISO: 14289f8b0eadSeric hp = gethostbyaddr((char *) &sap->siso.siso_addr, 14299f8b0eadSeric sizeof sap->siso.siso_addr, 14309f8b0eadSeric AF_ISO); 14319f8b0eadSeric break; 14329f8b0eadSeric #endif 14339f8b0eadSeric 1434e387851eSeric case AF_UNIX: 1435e387851eSeric hp = NULL; 1436e387851eSeric break; 1437e387851eSeric 14389f8b0eadSeric default: 14399f8b0eadSeric hp = gethostbyaddr(sap->sa.sa_data, 14409f8b0eadSeric sizeof sap->sa.sa_data, 14419f8b0eadSeric sap->sa.sa_family); 14429f8b0eadSeric break; 14439f8b0eadSeric } 14449f8b0eadSeric 14459d4a8008Seric #if NAMED_BIND 14463490b9dfSeric _res.retry = saveretry; 14473490b9dfSeric #endif /* NAMED_BIND */ 14483490b9dfSeric 14499f8b0eadSeric if (hp != NULL) 14509f8b0eadSeric return hp->h_name; 14519f8b0eadSeric else 14529f8b0eadSeric { 14539f8b0eadSeric /* produce a dotted quad */ 14549f8b0eadSeric static char buf[512]; 14559f8b0eadSeric 14569f8b0eadSeric (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 14579f8b0eadSeric return buf; 14589f8b0eadSeric } 14599f8b0eadSeric } 1460f36ede03Sbostic 14616c2c3107Seric # else /* DAEMON */ 146299f7cf32Seric /* code for systems without sophisticated networking */ 1463444eaf03Seric 1464444eaf03Seric /* 1465444eaf03Seric ** MYHOSTNAME -- stub version for case of no daemon code. 146621e9914dSeric ** 146721e9914dSeric ** Can't convert to upper case here because might be a UUCP name. 1468897f1869Seric ** 1469897f1869Seric ** Mark, you can change this to be anything you want...... 1470444eaf03Seric */ 1471444eaf03Seric 1472444eaf03Seric char ** 1473897f1869Seric myhostname(hostbuf, size) 1474444eaf03Seric char hostbuf[]; 1475897f1869Seric int size; 1476444eaf03Seric { 1477444eaf03Seric register FILE *f; 1478444eaf03Seric 1479444eaf03Seric hostbuf[0] = '\0'; 1480444eaf03Seric f = fopen("/usr/include/whoami", "r"); 1481444eaf03Seric if (f != NULL) 1482444eaf03Seric { 1483897f1869Seric (void) fgets(hostbuf, size, f); 1484444eaf03Seric fixcrlf(hostbuf, TRUE); 1485444eaf03Seric (void) fclose(f); 1486444eaf03Seric } 1487444eaf03Seric return (NULL); 1488444eaf03Seric } 148999f7cf32Seric /* 14909f8b0eadSeric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 1491320e0d1cSeric ** 1492320e0d1cSeric ** Parameters: 1493320e0d1cSeric ** fd -- the descriptor 1494320e0d1cSeric ** 1495320e0d1cSeric ** Returns: 1496320e0d1cSeric ** The host name associated with this descriptor, if it can 1497320e0d1cSeric ** be determined. 1498320e0d1cSeric ** NULL otherwise. 1499320e0d1cSeric ** 1500320e0d1cSeric ** Side Effects: 1501320e0d1cSeric ** none 1502320e0d1cSeric */ 1503320e0d1cSeric 1504320e0d1cSeric char * 15059f8b0eadSeric getauthinfo(fd) 1506320e0d1cSeric int fd; 1507320e0d1cSeric { 1508320e0d1cSeric return NULL; 1509320e0d1cSeric } 1510320e0d1cSeric /* 151199f7cf32Seric ** MAPHOSTNAME -- turn a hostname into canonical form 151299f7cf32Seric ** 151399f7cf32Seric ** Parameters: 151405b57da8Seric ** map -- a pointer to the database map. 151508de856eSeric ** name -- a buffer containing a hostname. 151615d084d5Seric ** avp -- a pointer to a (cf file defined) argument vector. 15172d29d43aSeric ** statp -- an exit status (out parameter). 151899f7cf32Seric ** 151999f7cf32Seric ** Returns: 152015d084d5Seric ** mapped host name 1521cb452edcSeric ** FALSE otherwise. 152299f7cf32Seric ** 152399f7cf32Seric ** Side Effects: 152408de856eSeric ** Looks up the host specified in name. If it is not 152599f7cf32Seric ** the canonical name for that host, replace it with 152699f7cf32Seric ** the canonical name. If the name is unknown, or it 152799f7cf32Seric ** is already the canonical name, leave it unchanged. 152899f7cf32Seric */ 152999f7cf32Seric 153099f7cf32Seric /*ARGSUSED*/ 153115d084d5Seric char * 153208de856eSeric host_map_lookup(map, name, avp, statp) 153305b57da8Seric MAP *map; 153408de856eSeric char *name; 153515d084d5Seric char **avp; 15362d29d43aSeric char *statp; 153799f7cf32Seric { 15382d29d43aSeric register struct hostent *hp; 15392d29d43aSeric 154008de856eSeric hp = gethostbyname(name); 15412d29d43aSeric if (hp != NULL) 15422d29d43aSeric return hp->h_name; 15432d29d43aSeric *statp = EX_NOHOST; 154415d084d5Seric return NULL; 154599f7cf32Seric } 154699f7cf32Seric 15476c2c3107Seric #endif /* DAEMON */ 1548