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*81d2944fSeric static char sccsid[] = "@(#)daemon.c 8.48.1.3 (Berkeley) 02/28/95 (with daemon mode)"; 15d0a9e852Seric #else 16*81d2944fSeric static char sccsid[] = "@(#)daemon.c 8.48.1.3 (Berkeley) 02/28/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 26*81d2944fSeric # 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; 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(); 1613a099713Seric 1623a099713Seric /* see if we are rejecting connections */ 16315d084d5Seric CurrentLA = getla(); 16415d084d5Seric if (refuseconnections()) 1656775ec03Sbostic { 1660084e6f6Seric if (DaemonSocket >= 0) 16715d084d5Seric { 1680084e6f6Seric /* close socket so peer will fail quickly */ 1690084e6f6Seric (void) close(DaemonSocket); 1700084e6f6Seric DaemonSocket = -1; 17115d084d5Seric } 1720084e6f6Seric refusingconnections = TRUE; 17371e5e267Seric setproctitle("rejecting connections: load average: %d", 17471e5e267Seric CurrentLA); 1750084e6f6Seric sleep(15); 17615d084d5Seric continue; 17715d084d5Seric } 17815d084d5Seric 17915d084d5Seric if (refusingconnections) 18015d084d5Seric { 181*81d2944fSeric /* start listening again */ 1828a0cb579Seric (void) opendaemonsocket(FALSE); 18315d084d5Seric setproctitle("accepting connections"); 18415d084d5Seric refusingconnections = FALSE; 1856775ec03Sbostic } 186a44d5a5eSeric 187dfe840b2Seric #ifdef XDEBUG 188dfe840b2Seric /* check for disaster */ 189dfe840b2Seric { 190*81d2944fSeric register STAB *s; 19135852b23Seric char jbuf[MAXHOSTNAMELEN]; 192dfe840b2Seric 19335852b23Seric expand("\201j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv); 194*81d2944fSeric if ((s = stab(jbuf, ST_CLASS, ST_FIND)) == NULL || 195*81d2944fSeric !bitnset('w', s->s_class)) 196dfe840b2Seric { 197dfe840b2Seric dumpstate("daemon lost $j"); 198dfe840b2Seric syslog(LOG_ALERT, "daemon process doesn't have $j in $=w; see syslog"); 199dfe840b2Seric abort(); 200dfe840b2Seric } 20135852b23Seric else if (j_has_dot && strchr(jbuf, '.') == NULL) 202dfe840b2Seric { 203dfe840b2Seric dumpstate("daemon $j lost dot"); 204dfe840b2Seric syslog(LOG_ALERT, "daemon process $j lost dot; see syslog"); 205dfe840b2Seric abort(); 206dfe840b2Seric } 207dfe840b2Seric } 208dfe840b2Seric #endif 209dfe840b2Seric 2101c71e510Seric /* wait for a connection */ 2111c71e510Seric do 2121c71e510Seric { 2131c71e510Seric errno = 0; 214dadb8687Seric lotherend = socksize; 2159b100374Sbostic t = accept(DaemonSocket, 2169b100374Sbostic (struct sockaddr *)&RealHostAddr, &lotherend); 2171c71e510Seric } while (t < 0 && errno == EINTR); 2181c71e510Seric if (t < 0) 2191c71e510Seric { 2201c71e510Seric syserr("getrequests: accept"); 2211c71e510Seric sleep(5); 2221c71e510Seric continue; 2231c71e510Seric } 224d0a9e852Seric 225d0a9e852Seric /* 226d0a9e852Seric ** Create a subprocess to process the mail. 227d0a9e852Seric */ 228d0a9e852Seric 22961e4310fSeric if (tTd(15, 2)) 2301c71e510Seric printf("getrequests: forking (fd = %d)\n", t); 231eb889047Seric 232a8268164Seric pid = fork(); 233a8268164Seric if (pid < 0) 234a8268164Seric { 235a8268164Seric syserr("daemon: cannot fork"); 236a8268164Seric sleep(10); 2371c71e510Seric (void) close(t); 238a8268164Seric continue; 239a8268164Seric } 240a8268164Seric 241a8268164Seric if (pid == 0) 242a8268164Seric { 243da662164Seric char *p; 2449f8b0eadSeric extern char *hostnamebyanyaddr(); 245a44d5a5eSeric 246a8268164Seric /* 247a8268164Seric ** CHILD -- return to caller. 248a44d5a5eSeric ** Collect verified idea of sending host. 249a8268164Seric ** Verify calling user id if possible here. 250a8268164Seric */ 251a8268164Seric 2522b9178d3Seric (void) setsignal(SIGCHLD, SIG_DFL); 2539f9b003eSeric DisConnected = FALSE; 254779ac194Seric 2554dd09a90Seric setproctitle("startup with %s", 2564dd09a90Seric anynet_ntoa(&RealHostAddr)); 2574dd09a90Seric 258a44d5a5eSeric /* determine host name */ 259da662164Seric p = hostnamebyanyaddr(&RealHostAddr); 260da662164Seric RealHostName = newstr(p); 2614dd09a90Seric setproctitle("startup with %s", p); 26229dcf4baSeric 2632a6bc25bSeric #ifdef LOG 2641f2ff1a4Seric if (LogLevel > 11) 2652a6bc25bSeric { 2662a6bc25bSeric /* log connection information */ 2672a6bc25bSeric syslog(LOG_INFO, "connect from %s (%s)", 2689f8b0eadSeric RealHostName, anynet_ntoa(&RealHostAddr)); 2692a6bc25bSeric } 2702a6bc25bSeric #endif 2712a6bc25bSeric 272*81d2944fSeric (void) close(DaemonSocket); 273335eae58Seric if ((InChannel = fdopen(t, "r")) == NULL || 274335eae58Seric (t = dup(t)) < 0 || 275335eae58Seric (OutChannel = fdopen(t, "w")) == NULL) 276335eae58Seric { 277335eae58Seric syserr("cannot open SMTP server channel, fd=%d", t); 278335eae58Seric exit(0); 279335eae58Seric } 280244b09d1Seric 28129dcf4baSeric /* should we check for illegal connection here? XXX */ 282e17a3a5aSeric #ifdef XLA 283e17a3a5aSeric if (!xla_host_ok(RealHostName)) 284e17a3a5aSeric { 285244b09d1Seric message("421 Too many SMTP sessions for this host"); 286e17a3a5aSeric exit(0); 287e17a3a5aSeric } 288e17a3a5aSeric #endif 289a44d5a5eSeric 29061e4310fSeric if (tTd(15, 2)) 291d0a9e852Seric printf("getreq: returning\n"); 292a8268164Seric return; 293a8268164Seric } 294a8268164Seric 2953c154354Seric /* close the port so that others will hang (for a while) */ 2963c154354Seric (void) close(t); 2978e3e4b17Seric } 2983c154354Seric /*NOTREACHED*/ 2993c154354Seric } 3008e3e4b17Seric /* 3010084e6f6Seric ** OPENDAEMONSOCKET -- open the SMTP socket 3020084e6f6Seric ** 3030084e6f6Seric ** Deals with setting all appropriate options. DaemonAddr must 3040084e6f6Seric ** be set up in advance. 3050084e6f6Seric ** 3060084e6f6Seric ** Parameters: 30788ea5609Seric ** firsttime -- set if this is the initial open. 3080084e6f6Seric ** 3090084e6f6Seric ** Returns: 3100084e6f6Seric ** Size in bytes of the daemon socket addr. 3110084e6f6Seric ** 3120084e6f6Seric ** Side Effects: 3130084e6f6Seric ** Leaves DaemonSocket set to the open socket. 3140084e6f6Seric ** Exits if the socket cannot be created. 3150084e6f6Seric */ 3160084e6f6Seric 3176173568dSeric #define MAXOPENTRIES 10 /* maximum number of tries to open connection */ 3186173568dSeric 3190084e6f6Seric int 32088ea5609Seric opendaemonsocket(firsttime) 32188ea5609Seric bool firsttime; 3220084e6f6Seric { 3230084e6f6Seric int on = 1; 324*81d2944fSeric int socksize; 3256173568dSeric int ntries = 0; 3266173568dSeric int saveerrno; 3270084e6f6Seric 3280084e6f6Seric if (tTd(15, 2)) 3290084e6f6Seric printf("opendaemonsocket()\n"); 3300084e6f6Seric 3316173568dSeric do 3326173568dSeric { 333254b93c3Seric if (ntries > 0) 334254b93c3Seric sleep(5); 33588ea5609Seric if (firsttime || DaemonSocket < 0) 33688ea5609Seric { 3370084e6f6Seric DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0); 3380084e6f6Seric if (DaemonSocket < 0) 3390084e6f6Seric { 3400084e6f6Seric /* probably another daemon already */ 3416173568dSeric saveerrno = errno; 3420084e6f6Seric syserr("opendaemonsocket: can't create server SMTP socket"); 3430084e6f6Seric severe: 3440084e6f6Seric # ifdef LOG 3450084e6f6Seric if (LogLevel > 0) 3460084e6f6Seric syslog(LOG_ALERT, "problem creating SMTP socket"); 3470084e6f6Seric # endif /* LOG */ 3486173568dSeric DaemonSocket = -1; 3496173568dSeric continue; 3500084e6f6Seric } 3510084e6f6Seric 3520084e6f6Seric /* turn on network debugging? */ 3530084e6f6Seric if (tTd(15, 101)) 3546173568dSeric (void) setsockopt(DaemonSocket, SOL_SOCKET, 3556173568dSeric SO_DEBUG, (char *)&on, 3566173568dSeric sizeof on); 3570084e6f6Seric 3586173568dSeric (void) setsockopt(DaemonSocket, SOL_SOCKET, 3596173568dSeric SO_REUSEADDR, (char *)&on, sizeof on); 3606173568dSeric (void) setsockopt(DaemonSocket, SOL_SOCKET, 3616173568dSeric SO_KEEPALIVE, (char *)&on, sizeof on); 3620084e6f6Seric 3630084e6f6Seric #ifdef SO_RCVBUF 3640084e6f6Seric if (TcpRcvBufferSize > 0) 3650084e6f6Seric { 3666173568dSeric if (setsockopt(DaemonSocket, SOL_SOCKET, 3676173568dSeric SO_RCVBUF, 3680084e6f6Seric (char *) &TcpRcvBufferSize, 3690084e6f6Seric sizeof(TcpRcvBufferSize)) < 0) 3700084e6f6Seric syserr("getrequests: setsockopt(SO_RCVBUF)"); 3710084e6f6Seric } 3720084e6f6Seric #endif 3730084e6f6Seric 3740084e6f6Seric switch (DaemonAddr.sa.sa_family) 3750084e6f6Seric { 3760084e6f6Seric # ifdef NETINET 3770084e6f6Seric case AF_INET: 3780084e6f6Seric socksize = sizeof DaemonAddr.sin; 3790084e6f6Seric break; 3800084e6f6Seric # endif 3810084e6f6Seric 3820084e6f6Seric # ifdef NETISO 3830084e6f6Seric case AF_ISO: 3840084e6f6Seric socksize = sizeof DaemonAddr.siso; 3850084e6f6Seric break; 3860084e6f6Seric # endif 3870084e6f6Seric 3880084e6f6Seric default: 3890084e6f6Seric socksize = sizeof DaemonAddr; 3900084e6f6Seric break; 3910084e6f6Seric } 3920084e6f6Seric 3930084e6f6Seric if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0) 3940084e6f6Seric { 3956173568dSeric saveerrno = errno; 3960084e6f6Seric syserr("getrequests: cannot bind"); 3970084e6f6Seric (void) close(DaemonSocket); 3980084e6f6Seric goto severe; 3990084e6f6Seric } 40088ea5609Seric } 40188ea5609Seric if (!firsttime && listen(DaemonSocket, ListenQueueSize) < 0) 4020084e6f6Seric { 4036173568dSeric saveerrno = errno; 4040084e6f6Seric syserr("getrequests: cannot listen"); 4050084e6f6Seric (void) close(DaemonSocket); 4060084e6f6Seric goto severe; 4070084e6f6Seric } 4080084e6f6Seric return socksize; 4096173568dSeric } while (ntries++ < MAXOPENTRIES && transienterror(saveerrno)); 4106173568dSeric finis(); 4110084e6f6Seric } 4120084e6f6Seric /* 413b7d7afcbSeric ** CLRDAEMON -- reset the daemon connection 414b7d7afcbSeric ** 415b7d7afcbSeric ** Parameters: 416b7d7afcbSeric ** none. 417b7d7afcbSeric ** 418b7d7afcbSeric ** Returns: 419b7d7afcbSeric ** none. 420b7d7afcbSeric ** 421b7d7afcbSeric ** Side Effects: 422b7d7afcbSeric ** releases any resources used by the passive daemon. 423b7d7afcbSeric */ 424b7d7afcbSeric 425b7d7afcbSeric clrdaemon() 426b7d7afcbSeric { 427b7d7afcbSeric if (DaemonSocket >= 0) 428b7d7afcbSeric (void) close(DaemonSocket); 429b7d7afcbSeric DaemonSocket = -1; 430b7d7afcbSeric } 431b7d7afcbSeric /* 432bfb80540Seric ** SETDAEMONOPTIONS -- set options for running the daemon 433bfb80540Seric ** 434bfb80540Seric ** Parameters: 435bfb80540Seric ** p -- the options line. 436bfb80540Seric ** 437bfb80540Seric ** Returns: 438bfb80540Seric ** none. 439bfb80540Seric */ 440bfb80540Seric 441bfb80540Seric setdaemonoptions(p) 442bfb80540Seric register char *p; 443bfb80540Seric { 444850144caSeric if (DaemonAddr.sa.sa_family == AF_UNSPEC) 445850144caSeric DaemonAddr.sa.sa_family = AF_INET; 446850144caSeric 447bfb80540Seric while (p != NULL) 448bfb80540Seric { 449bfb80540Seric register char *f; 450bfb80540Seric register char *v; 451bfb80540Seric 452bfb80540Seric while (isascii(*p) && isspace(*p)) 453bfb80540Seric p++; 454bfb80540Seric if (*p == '\0') 455bfb80540Seric break; 456bfb80540Seric f = p; 457bfb80540Seric p = strchr(p, ','); 458bfb80540Seric if (p != NULL) 459bfb80540Seric *p++ = '\0'; 460bfb80540Seric v = strchr(f, '='); 461bfb80540Seric if (v == NULL) 462bfb80540Seric continue; 463bfb80540Seric while (isascii(*++v) && isspace(*v)) 464bfb80540Seric continue; 465bfb80540Seric 466bfb80540Seric switch (*f) 467bfb80540Seric { 468850144caSeric case 'F': /* address family */ 469850144caSeric if (isascii(*v) && isdigit(*v)) 470850144caSeric DaemonAddr.sa.sa_family = atoi(v); 471850144caSeric #ifdef NETINET 472850144caSeric else if (strcasecmp(v, "inet") == 0) 473850144caSeric DaemonAddr.sa.sa_family = AF_INET; 474850144caSeric #endif 475850144caSeric #ifdef NETISO 476850144caSeric else if (strcasecmp(v, "iso") == 0) 477850144caSeric DaemonAddr.sa.sa_family = AF_ISO; 478850144caSeric #endif 479850144caSeric #ifdef NETNS 480850144caSeric else if (strcasecmp(v, "ns") == 0) 481850144caSeric DaemonAddr.sa.sa_family = AF_NS; 482850144caSeric #endif 483850144caSeric #ifdef NETX25 484850144caSeric else if (strcasecmp(v, "x.25") == 0) 485850144caSeric DaemonAddr.sa.sa_family = AF_CCITT; 486850144caSeric #endif 487850144caSeric else 488850144caSeric syserr("554 Unknown address family %s in Family=option", v); 489850144caSeric break; 490850144caSeric 491850144caSeric case 'A': /* address */ 492850144caSeric switch (DaemonAddr.sa.sa_family) 493850144caSeric { 494850144caSeric #ifdef NETINET 495850144caSeric case AF_INET: 496850144caSeric if (isascii(*v) && isdigit(*v)) 497*81d2944fSeric DaemonAddr.sin.sin_addr.s_addr = inet_network(v); 498850144caSeric else 499850144caSeric { 500850144caSeric register struct netent *np; 501850144caSeric 502850144caSeric np = getnetbyname(v); 503850144caSeric if (np == NULL) 504850144caSeric syserr("554 network \"%s\" unknown", v); 505850144caSeric else 506850144caSeric DaemonAddr.sin.sin_addr.s_addr = np->n_net; 507850144caSeric } 508850144caSeric break; 509850144caSeric #endif 510850144caSeric 511850144caSeric default: 512850144caSeric syserr("554 Address= option unsupported for family %d", 513850144caSeric DaemonAddr.sa.sa_family); 514850144caSeric break; 515850144caSeric } 516850144caSeric break; 517850144caSeric 518bfb80540Seric case 'P': /* port */ 519850144caSeric switch (DaemonAddr.sa.sa_family) 520850144caSeric { 521850144caSeric short port; 522850144caSeric 523850144caSeric #ifdef NETINET 524850144caSeric case AF_INET: 525bfb80540Seric if (isascii(*v) && isdigit(*v)) 52676b70c58Seric DaemonAddr.sin.sin_port = htons(atoi(v)); 527bfb80540Seric else 528bfb80540Seric { 529bfb80540Seric register struct servent *sp; 530bfb80540Seric 531bfb80540Seric sp = getservbyname(v, "tcp"); 532bfb80540Seric if (sp == NULL) 533ad977999Seric syserr("554 service \"%s\" unknown", v); 534bfb80540Seric else 535bfb80540Seric DaemonAddr.sin.sin_port = sp->s_port; 536bfb80540Seric } 537bfb80540Seric break; 538850144caSeric #endif 539bfb80540Seric 540850144caSeric #ifdef NETISO 541850144caSeric case AF_ISO: 542850144caSeric /* assume two byte transport selector */ 543bfb80540Seric if (isascii(*v) && isdigit(*v)) 54476b70c58Seric port = htons(atoi(v)); 545bfb80540Seric else 546bfb80540Seric { 547850144caSeric register struct servent *sp; 548bfb80540Seric 549850144caSeric sp = getservbyname(v, "tcp"); 550850144caSeric if (sp == NULL) 551ad977999Seric syserr("554 service \"%s\" unknown", v); 552bfb80540Seric else 553850144caSeric port = sp->s_port; 554850144caSeric } 555850144caSeric bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2); 556850144caSeric break; 557850144caSeric #endif 558850144caSeric 559850144caSeric default: 560850144caSeric syserr("554 Port= option unsupported for family %d", 561850144caSeric DaemonAddr.sa.sa_family); 562850144caSeric break; 563bfb80540Seric } 564bfb80540Seric break; 565bfc1eaf8Seric 566bfc1eaf8Seric case 'L': /* listen queue size */ 567bfc1eaf8Seric ListenQueueSize = atoi(v); 568bfc1eaf8Seric break; 569b35447dbSeric 570b35447dbSeric case 'S': /* send buffer size */ 571b35447dbSeric TcpSndBufferSize = atoi(v); 572b35447dbSeric break; 573b35447dbSeric 574b35447dbSeric case 'R': /* receive buffer size */ 575b35447dbSeric TcpRcvBufferSize = atoi(v); 576b35447dbSeric break; 577bfb80540Seric } 578bfb80540Seric } 579bfb80540Seric } 580bfb80540Seric /* 5817aa493c5Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 5827aa493c5Seric ** 5837aa493c5Seric ** Parameters: 5847aa493c5Seric ** host -- the name of the host. 58548ff0a9dSeric ** port -- the port number to connect to. 586655feedbSeric ** mci -- a pointer to the mail connection information 587655feedbSeric ** structure to be filled in. 588914346b1Seric ** usesecureport -- if set, use a low numbered (reserved) 589914346b1Seric ** port to provide some rudimentary authentication. 5907aa493c5Seric ** 5917aa493c5Seric ** Returns: 5927aa493c5Seric ** An exit code telling whether the connection could be 5937aa493c5Seric ** made and if not why not. 5947aa493c5Seric ** 5957aa493c5Seric ** Side Effects: 5967aa493c5Seric ** none. 5977aa493c5Seric */ 5987aa493c5Seric 599e2f2f828Seric SOCKADDR CurHostAddr; /* address of current host */ 60071ff6caaSeric 601b31e7f2bSeric int 602655feedbSeric makeconnection(host, port, mci, usesecureport) 6037aa493c5Seric char *host; 604210215eaSeric u_short port; 605b31e7f2bSeric register MCI *mci; 606914346b1Seric bool usesecureport; 6077aa493c5Seric { 608*81d2944fSeric register int i, s; 60904344589Sbloom register struct hostent *hp = (struct hostent *)NULL; 610e2f2f828Seric SOCKADDR addr; 6116286bb75Sbloom int sav_errno; 612e2f2f828Seric int addrlen; 6139d4a8008Seric #if NAMED_BIND 614134746fbSeric extern int h_errno; 615134746fbSeric #endif 6167aa493c5Seric 6177aa493c5Seric /* 6187aa493c5Seric ** Set up the address for the mailer. 61971096d12Seric ** Accept "[a.b.c.d]" syntax for host name. 6207aa493c5Seric */ 6217aa493c5Seric 6229d4a8008Seric #if NAMED_BIND 623794bdbb9Smiriam h_errno = 0; 624134746fbSeric #endif 625794bdbb9Smiriam errno = 0; 626967778e2Seric bzero(&CurHostAddr, sizeof CurHostAddr); 627c931b82bSeric SmtpPhase = mci->mci_phase = "initial connection"; 628d945ebe8Seric CurHostName = host; 629794bdbb9Smiriam 63071096d12Seric if (host[0] == '[') 63171096d12Seric { 632a44d5a5eSeric long hid; 6336c2c3107Seric register char *p = strchr(host, ']'); 63471096d12Seric 635a44d5a5eSeric if (p != NULL) 63671096d12Seric { 637a44d5a5eSeric *p = '\0'; 6384d9c42c2Seric #ifdef NETINET 639a44d5a5eSeric hid = inet_addr(&host[1]); 640a7e21fe6Seric if (hid == -1) 6414d9c42c2Seric #endif 642a7e21fe6Seric { 643a7e21fe6Seric /* try it as a host name (avoid MX lookup) */ 644a7e21fe6Seric hp = gethostbyname(&host[1]); 645d8984352Seric if (hp == NULL && p[-1] == '.') 646d8984352Seric { 647d8984352Seric p[-1] = '\0'; 648d8984352Seric hp = gethostbyname(&host[1]); 649d8984352Seric p[-1] = '.'; 650d8984352Seric } 651a7e21fe6Seric *p = ']'; 652a7e21fe6Seric goto gothostent; 653a7e21fe6Seric } 654a44d5a5eSeric *p = ']'; 65571096d12Seric } 656a7e21fe6Seric if (p == NULL) 65771096d12Seric { 65808b25121Seric usrerr("553 Invalid numeric domain spec \"%s\"", host); 65971096d12Seric return (EX_NOHOST); 66071096d12Seric } 6614d9c42c2Seric #ifdef NETINET 6624d9c42c2Seric addr.sin.sin_family = AF_INET; /*XXX*/ 66383c1f4bcSeric addr.sin.sin_addr.s_addr = hid; 6644d9c42c2Seric #endif 66571096d12Seric } 6661c71e510Seric else 6671c71e510Seric { 668d8984352Seric register char *p = &host[strlen(host) - 1]; 669d8984352Seric 67004344589Sbloom hp = gethostbyname(host); 671d8984352Seric if (hp == NULL && *p == '.') 672d8984352Seric { 673d8984352Seric *p = '\0'; 674d8984352Seric hp = gethostbyname(host); 675d8984352Seric *p = '.'; 676d8984352Seric } 677a7e21fe6Seric gothostent: 678794bdbb9Smiriam if (hp == NULL) 679794bdbb9Smiriam { 6809d4a8008Seric #if NAMED_BIND 681*81d2944fSeric if (errno == ETIMEDOUT || h_errno == TRY_AGAIN) 68252308a50Seric return (EX_TEMPFAIL); 683*81d2944fSeric 684*81d2944fSeric /* if name server is specified, assume temp fail */ 685*81d2944fSeric if (errno == ECONNREFUSED && UseNameServer) 686*81d2944fSeric return (EX_TEMPFAIL); 687134746fbSeric #endif 6887aa493c5Seric return (EX_NOHOST); 689794bdbb9Smiriam } 69083c1f4bcSeric addr.sa.sa_family = hp->h_addrtype; 69183c1f4bcSeric switch (hp->h_addrtype) 69283c1f4bcSeric { 69383c1f4bcSeric #ifdef NETINET 69483c1f4bcSeric case AF_INET: 695e2f2f828Seric bcopy(hp->h_addr, 69683c1f4bcSeric &addr.sin.sin_addr, 697*81d2944fSeric sizeof addr.sin.sin_addr); 69883c1f4bcSeric break; 69983c1f4bcSeric #endif 70083c1f4bcSeric 70183c1f4bcSeric default: 702e2f2f828Seric bcopy(hp->h_addr, 70383c1f4bcSeric addr.sa.sa_data, 704e2f2f828Seric hp->h_length); 70583c1f4bcSeric break; 70683c1f4bcSeric } 70704344589Sbloom i = 1; 7081c71e510Seric } 7091c71e510Seric 7101c71e510Seric /* 7111c71e510Seric ** Determine the port number. 7121c71e510Seric */ 7131c71e510Seric 714fd7c0790Seric if (port != 0) 715e2f2f828Seric port = htons(port); 716fd7c0790Seric else 7171c71e510Seric { 7181c71e510Seric register struct servent *sp = getservbyname("smtp", "tcp"); 7191c71e510Seric 7201c71e510Seric if (sp == NULL) 7211c71e510Seric { 722ad977999Seric syserr("554 makeconnection: service \"smtp\" unknown"); 723e5311662Seric port = htons(25); 7241c71e510Seric } 725e5311662Seric else 726e2f2f828Seric port = sp->s_port; 727e2f2f828Seric } 728e2f2f828Seric 72983c1f4bcSeric switch (addr.sa.sa_family) 730e2f2f828Seric { 7314d9c42c2Seric #ifdef NETINET 732e2f2f828Seric case AF_INET: 73383c1f4bcSeric addr.sin.sin_port = port; 734e2f2f828Seric addrlen = sizeof (struct sockaddr_in); 735e2f2f828Seric break; 7364d9c42c2Seric #endif 737e2f2f828Seric 738e2f2f828Seric #ifdef NETISO 739e2f2f828Seric case AF_ISO: 740e2f2f828Seric /* assume two byte transport selector */ 741e2f2f828Seric bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 742e2f2f828Seric addrlen = sizeof (struct sockaddr_iso); 743e2f2f828Seric break; 744e2f2f828Seric #endif 745e2f2f828Seric 746e2f2f828Seric default: 74783c1f4bcSeric syserr("Can't connect to address family %d", addr.sa.sa_family); 748e2f2f828Seric return (EX_NOHOST); 7491c71e510Seric } 7507aa493c5Seric 7517aa493c5Seric /* 7527aa493c5Seric ** Try to actually open the connection. 7537aa493c5Seric */ 7547aa493c5Seric 755e17a3a5aSeric #ifdef XLA 756e17a3a5aSeric /* if too many connections, don't bother trying */ 757e17a3a5aSeric if (!xla_noqueue_ok(host)) 758e17a3a5aSeric return EX_TEMPFAIL; 759e17a3a5aSeric #endif 760e17a3a5aSeric 761aea02ca1Seric for (;;) 762aea02ca1Seric { 76361e4310fSeric if (tTd(16, 1)) 764e2f2f828Seric printf("makeconnection (%s [%s])\n", 765e2f2f828Seric host, anynet_ntoa(&addr)); 7667aa493c5Seric 767226e3022Seric /* save for logging */ 768226e3022Seric CurHostAddr = addr; 769226e3022Seric 770914346b1Seric if (usesecureport) 771914346b1Seric { 772914346b1Seric int rport = IPPORT_RESERVED - 1; 773914346b1Seric 774914346b1Seric s = rresvport(&rport); 775914346b1Seric } 776914346b1Seric else 777914346b1Seric { 778af5e902cSeric s = socket(AF_INET, SOCK_STREAM, 0); 779914346b1Seric } 7807aa493c5Seric if (s < 0) 7817aa493c5Seric { 7826286bb75Sbloom sav_errno = errno; 783914346b1Seric syserr("makeconnection: no socket"); 7847aa493c5Seric goto failure; 7857aa493c5Seric } 7867aa493c5Seric 787b35447dbSeric #ifdef SO_SNDBUF 788b35447dbSeric if (TcpSndBufferSize > 0) 789b35447dbSeric { 790b35447dbSeric if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 791bf217a95Seric (char *) &TcpSndBufferSize, 792b35447dbSeric sizeof(TcpSndBufferSize)) < 0) 793b35447dbSeric syserr("makeconnection: setsockopt(SO_SNDBUF)"); 794b35447dbSeric } 795b35447dbSeric #endif 796b35447dbSeric 79761e4310fSeric if (tTd(16, 1)) 798b31e7f2bSeric printf("makeconnection: fd=%d\n", s); 7991b6e4a15Seric 8001b6e4a15Seric /* turn on network debugging? */ 801a2ef5fa4Seric if (tTd(16, 101)) 80252308a50Seric { 80352308a50Seric int on = 1; 8046173568dSeric (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, 805aea02ca1Seric (char *)&on, sizeof on); 80652308a50Seric } 80787d6e633Srick if (CurEnv->e_xfp != NULL) 808877a6142Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 8094bd6a662Seric errno = 0; /* for debugging */ 810e2f2f828Seric if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 811aea02ca1Seric break; 812aea02ca1Seric 813aea02ca1Seric /* couldn't connect.... figure out why */ 8146286bb75Sbloom sav_errno = errno; 8156286bb75Sbloom (void) close(s); 816*81d2944fSeric if (hp && hp->h_addr_list[i]) 81704344589Sbloom { 818aea02ca1Seric if (tTd(16, 1)) 819e2f2f828Seric printf("Connect failed (%s); trying new address....\n", 820e2f2f828Seric errstring(sav_errno)); 82183c1f4bcSeric switch (addr.sa.sa_family) 82283c1f4bcSeric { 82383c1f4bcSeric #ifdef NETINET 82483c1f4bcSeric case AF_INET: 825e2f2f828Seric bcopy(hp->h_addr_list[i++], 82683c1f4bcSeric &addr.sin.sin_addr, 827*81d2944fSeric sizeof addr.sin.sin_addr); 82883c1f4bcSeric break; 82983c1f4bcSeric #endif 83083c1f4bcSeric 83183c1f4bcSeric default: 832e2f2f828Seric bcopy(hp->h_addr_list[i++], 83383c1f4bcSeric addr.sa.sa_data, 834914346b1Seric hp->h_length); 83583c1f4bcSeric break; 83683c1f4bcSeric } 837aea02ca1Seric continue; 83804344589Sbloom } 83904344589Sbloom 8407aa493c5Seric /* failure, decide if temporary or not */ 8417aa493c5Seric failure: 842244b09d1Seric #ifdef XLA 843244b09d1Seric xla_host_end(host); 844244b09d1Seric #endif 845e2de2524Seric if (transienterror(sav_errno)) 846e2de2524Seric return EX_TEMPFAIL; 847e2de2524Seric else 84887d6e633Srick { 84908b25121Seric message("%s", errstring(sav_errno)); 8507aa493c5Seric return (EX_UNAVAILABLE); 8517aa493c5Seric } 8527aa493c5Seric } 8537aa493c5Seric 8547aa493c5Seric /* connection ok, put it into canonical form */ 855335eae58Seric if ((mci->mci_out = fdopen(s, "w")) == NULL || 856335eae58Seric (s = dup(s)) < 0 || 857ab81ee53Seric (mci->mci_in = fdopen(s, "r")) == NULL) 858335eae58Seric { 859335eae58Seric syserr("cannot open SMTP client channel, fd=%d", s); 860335eae58Seric return EX_TEMPFAIL; 861335eae58Seric } 8627aa493c5Seric 863dca8e1f7Seric return (EX_OK); 8647aa493c5Seric } 865444eaf03Seric /* 866444eaf03Seric ** MYHOSTNAME -- return the name of this host. 867444eaf03Seric ** 868444eaf03Seric ** Parameters: 869444eaf03Seric ** hostbuf -- a place to return the name of this host. 870897f1869Seric ** size -- the size of hostbuf. 871444eaf03Seric ** 872444eaf03Seric ** Returns: 873444eaf03Seric ** A list of aliases for this host. 874444eaf03Seric ** 875444eaf03Seric ** Side Effects: 876d8d0a4aeSeric ** Adds numeric codes to $=w. 877444eaf03Seric */ 878444eaf03Seric 879*81d2944fSeric char ** 880897f1869Seric myhostname(hostbuf, size) 881444eaf03Seric char hostbuf[]; 882897f1869Seric int size; 883444eaf03Seric { 88438ad259dSeric register struct hostent *hp; 885444eaf03Seric extern struct hostent *gethostbyname(); 886444eaf03Seric 887af5e902cSeric if (gethostname(hostbuf, size) < 0) 888af5e902cSeric { 889af5e902cSeric (void) strcpy(hostbuf, "localhost"); 890af5e902cSeric } 891a44d5a5eSeric hp = gethostbyname(hostbuf); 8924a5c6430Seric if (hp == NULL) 893423161fbSeric { 894*81d2944fSeric syserr("!My host name (%s) does not seem to exist!", hostbuf); 895*81d2944fSeric } 89635852b23Seric (void) strncpy(hostbuf, hp->h_name, size - 1); 89735852b23Seric hostbuf[size - 1] = '\0'; 8984a5c6430Seric 8994a5c6430Seric #if NAMED_BIND 900*81d2944fSeric /* if still no dot, try DNS directly (i.e., avoid NIS problems) */ 901*81d2944fSeric if (strchr(hostbuf, '.') == NULL) 902b4fd970eSeric { 903*81d2944fSeric extern bool getcanonname(); 904*81d2944fSeric extern int h_errno; 905*81d2944fSeric 9069491ddb9Seric /* try twice in case name server not yet started up */ 907*81d2944fSeric if (!getcanonname(hostbuf, size, TRUE) && 908*81d2944fSeric UseNameServer && 909*81d2944fSeric (h_errno != TRY_AGAIN || 910*81d2944fSeric (sleep(30), !getcanonname(hostbuf, size, TRUE)))) 911*81d2944fSeric { 9129491ddb9Seric errno = h_errno + E_DNSBASE; 913*81d2944fSeric syserr("!My host name (%s) not known to DNS", 914*81d2944fSeric hostbuf); 915*81d2944fSeric } 916747df804Seric } 917747df804Seric #endif 918*81d2944fSeric 919*81d2944fSeric if (hp->h_addrtype == AF_INET && hp->h_length == 4) 920*81d2944fSeric { 921*81d2944fSeric register int i; 922*81d2944fSeric 923*81d2944fSeric for (i = 0; hp->h_addr_list[i] != NULL; i++) 924*81d2944fSeric { 925*81d2944fSeric char ipbuf[100]; 926*81d2944fSeric 927*81d2944fSeric sprintf(ipbuf, "[%s]", 928*81d2944fSeric inet_ntoa(*((struct in_addr *) hp->h_addr_list[i]))); 929*81d2944fSeric setclass('w', ipbuf); 930*81d2944fSeric } 931*81d2944fSeric } 932*81d2944fSeric 933*81d2944fSeric return (hp->h_aliases); 9347364df9fSeric } 935cb452edcSeric /* 9369f8b0eadSeric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 9379f8b0eadSeric ** 9389f8b0eadSeric ** Uses RFC1413 protocol to try to get info from the other end. 939320e0d1cSeric ** 940320e0d1cSeric ** Parameters: 941320e0d1cSeric ** fd -- the descriptor 942320e0d1cSeric ** 943320e0d1cSeric ** Returns: 9449f8b0eadSeric ** The user@host information associated with this descriptor. 945320e0d1cSeric */ 946320e0d1cSeric 947*81d2944fSeric #if IDENTPROTO 948*81d2944fSeric 9499f8b0eadSeric static jmp_buf CtxAuthTimeout; 9509f8b0eadSeric 951*81d2944fSeric static 9529f8b0eadSeric authtimeout() 9539f8b0eadSeric { 9549f8b0eadSeric longjmp(CtxAuthTimeout, 1); 9559f8b0eadSeric } 9569f8b0eadSeric 957*81d2944fSeric #endif 958*81d2944fSeric 959320e0d1cSeric char * 9609f8b0eadSeric getauthinfo(fd) 961320e0d1cSeric int fd; 962320e0d1cSeric { 9639f8b0eadSeric int falen; 964a5546e24Seric register char *p; 965*81d2944fSeric #if IDENTPROTO 9669f8b0eadSeric SOCKADDR la; 9679f8b0eadSeric int lalen; 9689f8b0eadSeric register struct servent *sp; 9699f8b0eadSeric int s; 9709f8b0eadSeric int i; 9719f8b0eadSeric EVENT *ev; 972579270a3Seric int nleft; 973*81d2944fSeric int ibuf[MAXNAME + 1]; 974*81d2944fSeric #endif 9759f8b0eadSeric static char hbuf[MAXNAME * 2 + 2]; 9769f8b0eadSeric extern char *hostnamebyanyaddr(); 9779f8b0eadSeric extern char RealUserName[]; /* main.c */ 978320e0d1cSeric 979e29a76d1Seric falen = sizeof RealHostAddr; 980*81d2944fSeric if (getpeername(fd, &RealHostAddr.sa, &falen) < 0 || falen <= 0 || 981*81d2944fSeric RealHostAddr.sa.sa_family == 0) 9829f8b0eadSeric { 9839f8b0eadSeric (void) sprintf(hbuf, "%s@localhost", RealUserName); 98453853673Seric if (tTd(9, 1)) 9859f8b0eadSeric printf("getauthinfo: %s\n", hbuf); 986320e0d1cSeric return hbuf; 987320e0d1cSeric } 9889f8b0eadSeric 989e29a76d1Seric if (RealHostName == NULL) 990e29a76d1Seric { 991e29a76d1Seric /* translate that to a host name */ 992e29a76d1Seric RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 993e29a76d1Seric } 994e29a76d1Seric 995*81d2944fSeric #if IDENTPROTO 99693b3215bSeric if (TimeOuts.to_ident == 0) 99793b3215bSeric goto noident; 99893b3215bSeric 9999f8b0eadSeric lalen = sizeof la; 1000e29a76d1Seric if (RealHostAddr.sa.sa_family != AF_INET || 10019f8b0eadSeric getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 10029f8b0eadSeric la.sa.sa_family != AF_INET) 10039f8b0eadSeric { 10049f8b0eadSeric /* no ident info */ 10059f8b0eadSeric goto noident; 10069f8b0eadSeric } 10079f8b0eadSeric 10089f8b0eadSeric /* create ident query */ 1009*81d2944fSeric (void) sprintf(ibuf, "%d,%d\r\n", 1010e29a76d1Seric ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port)); 10119f8b0eadSeric 10129f8b0eadSeric /* create local address */ 1013d6af7dadSeric la.sin.sin_port = 0; 10149f8b0eadSeric 10159f8b0eadSeric /* create foreign address */ 10169f8b0eadSeric sp = getservbyname("auth", "tcp"); 10179f8b0eadSeric if (sp != NULL) 1018e29a76d1Seric RealHostAddr.sin.sin_port = sp->s_port; 10199f8b0eadSeric else 1020e29a76d1Seric RealHostAddr.sin.sin_port = htons(113); 10219f8b0eadSeric 10229f8b0eadSeric s = -1; 10239f8b0eadSeric if (setjmp(CtxAuthTimeout) != 0) 10249f8b0eadSeric { 10259f8b0eadSeric if (s >= 0) 10269f8b0eadSeric (void) close(s); 10279f8b0eadSeric goto noident; 10289f8b0eadSeric } 10299f8b0eadSeric 10309f8b0eadSeric /* put a timeout around the whole thing */ 1031a0f780efSeric ev = setevent(TimeOuts.to_ident, authtimeout, 0); 10329f8b0eadSeric 1033d6af7dadSeric /* connect to foreign IDENT server using same address as SMTP socket */ 10349f8b0eadSeric s = socket(AF_INET, SOCK_STREAM, 0); 10359f8b0eadSeric if (s < 0) 10369f8b0eadSeric { 10379f8b0eadSeric clrevent(ev); 10389f8b0eadSeric goto noident; 10399f8b0eadSeric } 1040d6af7dadSeric if (bind(s, &la.sa, sizeof la.sin) < 0 || 1041e29a76d1Seric connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0) 10429f8b0eadSeric { 10437c201575Seric goto closeident; 10449f8b0eadSeric } 10459f8b0eadSeric 104653853673Seric if (tTd(9, 10)) 1047*81d2944fSeric printf("getauthinfo: sent %s", ibuf); 10489f8b0eadSeric 10499f8b0eadSeric /* send query */ 1050*81d2944fSeric if (write(s, ibuf, strlen(ibuf)) < 0) 10519f8b0eadSeric goto closeident; 10529f8b0eadSeric 10539f8b0eadSeric /* get result */ 1054*81d2944fSeric p = &ibuf[0]; 1055*81d2944fSeric nleft = sizeof(ibuf - 1); 1056579270a3Seric while ((i = read(s, p, nleft)) > 0) 1057579270a3Seric { 1058579270a3Seric p += i; 1059579270a3Seric nleft -= i; 1060579270a3Seric } 10619f8b0eadSeric (void) close(s); 10629f8b0eadSeric clrevent(ev); 1063*81d2944fSeric if (i < 0 || p == &ibuf[0]) 10649f8b0eadSeric goto noident; 1065579270a3Seric 1066579270a3Seric if (*--p == '\n' && *--p == '\r') 1067579270a3Seric p--; 1068579270a3Seric *++p = '\0'; 10699f8b0eadSeric 107053853673Seric if (tTd(9, 3)) 1071*81d2944fSeric printf("getauthinfo: got %s\n", ibuf); 10729f8b0eadSeric 10739f8b0eadSeric /* parse result */ 1074*81d2944fSeric p = strchr(ibuf, ':'); 10759f8b0eadSeric if (p == NULL) 10769f8b0eadSeric { 10779f8b0eadSeric /* malformed response */ 10789f8b0eadSeric goto noident; 10799f8b0eadSeric } 10809f8b0eadSeric while (isascii(*++p) && isspace(*p)) 10819f8b0eadSeric continue; 10829f8b0eadSeric if (strncasecmp(p, "userid", 6) != 0) 10839f8b0eadSeric { 10849f8b0eadSeric /* presumably an error string */ 10859f8b0eadSeric goto noident; 10869f8b0eadSeric } 10879f8b0eadSeric p += 6; 10889f8b0eadSeric while (isascii(*p) && isspace(*p)) 10899f8b0eadSeric p++; 10909f8b0eadSeric if (*p++ != ':') 10919f8b0eadSeric { 10929f8b0eadSeric /* either useridxx or malformed response */ 10939f8b0eadSeric goto noident; 10949f8b0eadSeric } 10959f8b0eadSeric 10969f8b0eadSeric /* p now points to the OSTYPE field */ 10979f8b0eadSeric p = strchr(p, ':'); 10989f8b0eadSeric if (p == NULL) 10999f8b0eadSeric { 11009f8b0eadSeric /* malformed response */ 11019f8b0eadSeric goto noident; 11029f8b0eadSeric } 110353853673Seric 110453853673Seric /* 1413 says don't do this -- but it's broken otherwise */ 110553853673Seric while (isascii(*++p) && isspace(*p)) 110653853673Seric continue; 11079f8b0eadSeric 1108a7763879Seric /* p now points to the authenticated name -- copy carefully */ 1109*81d2944fSeric cleanstrcpy(hbuf, p, MAXNAME); 1110*81d2944fSeric i = strlen(hbuf); 1111a7763879Seric hbuf[i++] = '@'; 1112a7763879Seric strcpy(&hbuf[i], RealHostName == NULL ? "localhost" : RealHostName); 111353853673Seric goto finish; 111453853673Seric 11157c201575Seric closeident: 11167c201575Seric (void) close(s); 11177c201575Seric clrevent(ev); 11187c201575Seric 1119*81d2944fSeric #endif /* IDENTPROTO */ 1120*81d2944fSeric 112153853673Seric noident: 1122f7869e68Seric if (RealHostName == NULL) 1123f7869e68Seric { 1124f7869e68Seric if (tTd(9, 1)) 1125f7869e68Seric printf("getauthinfo: NULL\n"); 1126f7869e68Seric return NULL; 1127f7869e68Seric } 112853853673Seric (void) strcpy(hbuf, RealHostName); 112953853673Seric 113053853673Seric finish: 1131f7869e68Seric if (RealHostName != NULL && RealHostName[0] != '[') 11329f8b0eadSeric { 11339f8b0eadSeric p = &hbuf[strlen(hbuf)]; 11349f8b0eadSeric (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr)); 11359f8b0eadSeric } 113653853673Seric if (tTd(9, 1)) 11379f8b0eadSeric printf("getauthinfo: %s\n", hbuf); 11389f8b0eadSeric return hbuf; 11399f8b0eadSeric } 1140320e0d1cSeric /* 114108de856eSeric ** HOST_MAP_LOOKUP -- turn a hostname into canonical form 114215d084d5Seric ** 114315d084d5Seric ** Parameters: 114405b57da8Seric ** map -- a pointer to this map (unused). 114508de856eSeric ** name -- the (presumably unqualified) hostname. 114600b385a9Seric ** av -- unused -- for compatibility with other mapping 1147d798a1deSeric ** functions. 11482d29d43aSeric ** statp -- an exit status (out parameter) -- set to 11492d29d43aSeric ** EX_TEMPFAIL if the name server is unavailable. 115015d084d5Seric ** 115115d084d5Seric ** Returns: 115215d084d5Seric ** The mapping, if found. 115315d084d5Seric ** NULL if no mapping found. 115415d084d5Seric ** 115515d084d5Seric ** Side Effects: 115615d084d5Seric ** Looks up the host specified in hbuf. If it is not 115715d084d5Seric ** the canonical name for that host, return the canonical 115815d084d5Seric ** name. 1159f36ede03Sbostic */ 1160cb452edcSeric 116115d084d5Seric char * 116200b385a9Seric host_map_lookup(map, name, av, statp) 116305b57da8Seric MAP *map; 116408de856eSeric char *name; 116500b385a9Seric char **av; 11662d29d43aSeric int *statp; 116799f7cf32Seric { 116899f7cf32Seric register struct hostent *hp; 1169*81d2944fSeric u_long in_addr; 117005b57da8Seric char *cp; 1171*81d2944fSeric int i; 1172eea91d78Seric register STAB *s; 117300b385a9Seric char hbuf[MAXNAME]; 1174eea91d78Seric extern struct hostent *gethostbyaddr(); 11759d4a8008Seric #if NAMED_BIND 1176eea91d78Seric extern int h_errno; 1177c304a798Seric #endif 11785f78836eSmiriam 1179f36ede03Sbostic /* 1180eea91d78Seric ** See if we have already looked up this name. If so, just 1181eea91d78Seric ** return it. 1182eea91d78Seric */ 1183eea91d78Seric 118408de856eSeric s = stab(name, ST_NAMECANON, ST_ENTER); 1185eea91d78Seric if (bitset(NCF_VALID, s->s_namecanon.nc_flags)) 1186eea91d78Seric { 1187f92c3297Seric if (tTd(9, 1)) 118808de856eSeric printf("host_map_lookup(%s) => CACHE %s\n", 118908de856eSeric name, s->s_namecanon.nc_cname); 1190eea91d78Seric errno = s->s_namecanon.nc_errno; 11919d4a8008Seric #if NAMED_BIND 1192eea91d78Seric h_errno = s->s_namecanon.nc_herrno; 1193c304a798Seric #endif 1194eea91d78Seric *statp = s->s_namecanon.nc_stat; 119592270fb3Seric if (CurEnv->e_message == NULL && *statp == EX_TEMPFAIL) 1196ed63aae0Seric { 1197ed63aae0Seric sprintf(hbuf, "%s: Name server timeout", 1198ed63aae0Seric shortenstring(name, 33)); 1199ed63aae0Seric CurEnv->e_message = newstr(hbuf); 1200ed63aae0Seric } 1201eea91d78Seric return s->s_namecanon.nc_cname; 1202eea91d78Seric } 1203eea91d78Seric 1204eea91d78Seric /* 1205eea91d78Seric ** If first character is a bracket, then it is an address 1206eea91d78Seric ** lookup. Address is copied into a temporary buffer to 120708de856eSeric ** strip the brackets and to preserve name if address is 1208eea91d78Seric ** unknown. 1209f36ede03Sbostic */ 121015d084d5Seric 121108de856eSeric if (*name != '[') 121215d084d5Seric { 1213d798a1deSeric extern bool getcanonname(); 1214d798a1deSeric 12158cb4653dSeric if (tTd(9, 1)) 121608de856eSeric printf("host_map_lookup(%s) => ", name); 1217eea91d78Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 121808de856eSeric (void) strcpy(hbuf, name); 12191f2ff1a4Seric if (getcanonname(hbuf, sizeof hbuf - 1, TRUE)) 12209040ec4fSeric { 12219040ec4fSeric if (tTd(9, 1)) 12229040ec4fSeric printf("%s\n", hbuf); 122300b385a9Seric cp = map_rewrite(map, hbuf, strlen(hbuf), av); 122400b385a9Seric s->s_namecanon.nc_cname = newstr(cp); 122500b385a9Seric return cp; 12269040ec4fSeric } 122715d084d5Seric else 12289040ec4fSeric { 12292d29d43aSeric register struct hostent *hp; 12302d29d43aSeric 1231c304a798Seric s->s_namecanon.nc_errno = errno; 12329d4a8008Seric #if NAMED_BIND 1233c304a798Seric s->s_namecanon.nc_herrno = h_errno; 12349040ec4fSeric if (tTd(9, 1)) 12352d29d43aSeric printf("FAIL (%d)\n", h_errno); 12362d29d43aSeric switch (h_errno) 12372d29d43aSeric { 12382d29d43aSeric case TRY_AGAIN: 123989cb2793Seric if (UseNameServer) 12408820d51bSeric { 1241e0326f4fSeric sprintf(hbuf, "%s: Name server timeout", 1242ed63aae0Seric shortenstring(name, 33)); 1243e0326f4fSeric message("%s", hbuf); 12448820d51bSeric if (CurEnv->e_message == NULL) 1245e0326f4fSeric CurEnv->e_message = newstr(hbuf); 12468820d51bSeric } 12472d29d43aSeric *statp = EX_TEMPFAIL; 12482d29d43aSeric break; 12492d29d43aSeric 12502d29d43aSeric case HOST_NOT_FOUND: 12512d29d43aSeric *statp = EX_NOHOST; 12522d29d43aSeric break; 12532d29d43aSeric 12542d29d43aSeric case NO_RECOVERY: 12552d29d43aSeric *statp = EX_SOFTWARE; 12562d29d43aSeric break; 12572d29d43aSeric 12582d29d43aSeric default: 12592d29d43aSeric *statp = EX_UNAVAILABLE; 12602d29d43aSeric break; 12612d29d43aSeric } 1262c304a798Seric #else 1263c304a798Seric if (tTd(9, 1)) 1264c304a798Seric printf("FAIL\n"); 1265c304a798Seric *statp = EX_NOHOST; 1266c304a798Seric #endif 1267eea91d78Seric s->s_namecanon.nc_stat = *statp; 1268*81d2944fSeric if (*statp != EX_TEMPFAIL || UseNameServer) 126915d084d5Seric return NULL; 12702d29d43aSeric 12712d29d43aSeric /* 12722d29d43aSeric ** Try to look it up in /etc/hosts 12732d29d43aSeric */ 12742d29d43aSeric 127508de856eSeric hp = gethostbyname(name); 12762d29d43aSeric if (hp == NULL) 12772d29d43aSeric { 12782d29d43aSeric /* no dice there either */ 1279eea91d78Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 12802d29d43aSeric return NULL; 12812d29d43aSeric } 12822d29d43aSeric 1283eea91d78Seric s->s_namecanon.nc_stat = *statp = EX_OK; 128400b385a9Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 128500b385a9Seric s->s_namecanon.nc_cname = newstr(cp); 128600b385a9Seric return cp; 128715d084d5Seric } 12889040ec4fSeric } 128908de856eSeric if ((cp = strchr(name, ']')) == NULL) 129015d084d5Seric return (NULL); 129134e39927Sbostic *cp = '\0'; 1292*81d2944fSeric in_addr = inet_addr(&name[1]); 129338ad259dSeric 129438ad259dSeric /* nope -- ask the name server */ 1295*81d2944fSeric hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET); 1296eea91d78Seric s->s_namecanon.nc_errno = errno; 12979d4a8008Seric #if NAMED_BIND 1298eea91d78Seric s->s_namecanon.nc_herrno = h_errno; 1299c304a798Seric #endif 1300eea91d78Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 13015f78836eSmiriam if (hp == NULL) 1302eea91d78Seric { 1303eea91d78Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 130415d084d5Seric return (NULL); 1305eea91d78Seric } 130615d084d5Seric 130738ad259dSeric /* found a match -- copy out */ 130800b385a9Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 1309eea91d78Seric s->s_namecanon.nc_stat = *statp = EX_OK; 131000b385a9Seric s->s_namecanon.nc_cname = newstr(cp); 131100b385a9Seric return cp; 131299f7cf32Seric } 1313e2f2f828Seric /* 1314e2f2f828Seric ** ANYNET_NTOA -- convert a network address to printable form. 1315e2f2f828Seric ** 1316e2f2f828Seric ** Parameters: 1317e2f2f828Seric ** sap -- a pointer to a sockaddr structure. 1318e2f2f828Seric ** 1319e2f2f828Seric ** Returns: 1320e2f2f828Seric ** A printable version of that sockaddr. 1321e2f2f828Seric */ 1322e2f2f828Seric 1323e2f2f828Seric char * 1324e2f2f828Seric anynet_ntoa(sap) 1325e2f2f828Seric register SOCKADDR *sap; 1326e2f2f828Seric { 1327e2f2f828Seric register char *bp; 1328e2f2f828Seric register char *ap; 1329e2f2f828Seric int l; 1330e387851eSeric static char buf[100]; 1331e2f2f828Seric 13328cb4653dSeric /* check for null/zero family */ 13338cb4653dSeric if (sap == NULL) 13348cb4653dSeric return "NULLADDR"; 13358cb4653dSeric if (sap->sa.sa_family == 0) 13368cb4653dSeric return "0"; 13378cb4653dSeric 1338e387851eSeric switch (sap->sa.sa_family) 1339e387851eSeric { 1340*81d2944fSeric #ifdef MAYBENEXTRELEASE /*** UNTESTED *** UNTESTED *** UNTESTED ***/ 1341139b52c8Seric #ifdef NETUNIX 1342e387851eSeric case AF_UNIX: 1343c24cf5a4Seric if (sap->sunix.sun_path[0] != '\0') 1344c24cf5a4Seric sprintf(buf, "[UNIX: %.64s]", sap->sunix.sun_path); 1345e387851eSeric else 1346e387851eSeric sprintf(buf, "[UNIX: localhost]"); 1347e387851eSeric return buf; 1348e387851eSeric #endif 1349*81d2944fSeric #endif 1350e387851eSeric 135183c1f4bcSeric #ifdef NETINET 1352e387851eSeric case AF_INET: 1353e2f2f828Seric return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr); 135483c1f4bcSeric #endif 1355e2f2f828Seric 1356e387851eSeric default: 1357e387851eSeric /* this case is only to ensure syntactic correctness */ 1358e387851eSeric break; 1359e387851eSeric } 1360e387851eSeric 1361e2f2f828Seric /* unknown family -- just dump bytes */ 136283c1f4bcSeric (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 1363e2f2f828Seric bp = &buf[strlen(buf)]; 136483c1f4bcSeric ap = sap->sa.sa_data; 136583c1f4bcSeric for (l = sizeof sap->sa.sa_data; --l >= 0; ) 1366e2f2f828Seric { 1367e2f2f828Seric (void) sprintf(bp, "%02x:", *ap++ & 0377); 1368e2f2f828Seric bp += 3; 1369e2f2f828Seric } 1370e2f2f828Seric *--bp = '\0'; 1371e2f2f828Seric return buf; 1372e2f2f828Seric } 13739f8b0eadSeric /* 13749f8b0eadSeric ** HOSTNAMEBYANYADDR -- return name of host based on address 13759f8b0eadSeric ** 13769f8b0eadSeric ** Parameters: 13779f8b0eadSeric ** sap -- SOCKADDR pointer 13789f8b0eadSeric ** 13799f8b0eadSeric ** Returns: 13809f8b0eadSeric ** text representation of host name. 13819f8b0eadSeric ** 13829f8b0eadSeric ** Side Effects: 13839f8b0eadSeric ** none. 13849f8b0eadSeric */ 13859f8b0eadSeric 13869f8b0eadSeric char * 13879f8b0eadSeric hostnamebyanyaddr(sap) 13889f8b0eadSeric register SOCKADDR *sap; 13899f8b0eadSeric { 13909f8b0eadSeric register struct hostent *hp; 13913490b9dfSeric int saveretry; 13923490b9dfSeric 13939d4a8008Seric #if NAMED_BIND 13943490b9dfSeric /* shorten name server timeout to avoid higher level timeouts */ 13953490b9dfSeric saveretry = _res.retry; 13963490b9dfSeric _res.retry = 3; 13973490b9dfSeric #endif /* NAMED_BIND */ 13983490b9dfSeric 13999f8b0eadSeric switch (sap->sa.sa_family) 14009f8b0eadSeric { 14019f8b0eadSeric #ifdef NETINET 14029f8b0eadSeric case AF_INET: 14039f8b0eadSeric hp = gethostbyaddr((char *) &sap->sin.sin_addr, 1404*81d2944fSeric sizeof sap->sin.sin_addr, 14059f8b0eadSeric AF_INET); 14069f8b0eadSeric break; 14079f8b0eadSeric #endif 14089f8b0eadSeric 14099f8b0eadSeric #ifdef NETISO 14109f8b0eadSeric case AF_ISO: 14119f8b0eadSeric hp = gethostbyaddr((char *) &sap->siso.siso_addr, 14129f8b0eadSeric sizeof sap->siso.siso_addr, 14139f8b0eadSeric AF_ISO); 14149f8b0eadSeric break; 14159f8b0eadSeric #endif 14169f8b0eadSeric 1417*81d2944fSeric #ifdef MAYBENEXTRELEASE /*** UNTESTED *** UNTESTED *** UNTESTED ***/ 1418e387851eSeric case AF_UNIX: 1419e387851eSeric hp = NULL; 1420e387851eSeric break; 1421*81d2944fSeric #endif 1422e387851eSeric 14239f8b0eadSeric default: 14249f8b0eadSeric hp = gethostbyaddr(sap->sa.sa_data, 14259f8b0eadSeric sizeof sap->sa.sa_data, 14269f8b0eadSeric sap->sa.sa_family); 14279f8b0eadSeric break; 14289f8b0eadSeric } 14299f8b0eadSeric 14309d4a8008Seric #if NAMED_BIND 14313490b9dfSeric _res.retry = saveretry; 14323490b9dfSeric #endif /* NAMED_BIND */ 14333490b9dfSeric 14349f8b0eadSeric if (hp != NULL) 14359f8b0eadSeric return hp->h_name; 14369f8b0eadSeric else 14379f8b0eadSeric { 14389f8b0eadSeric /* produce a dotted quad */ 14399f8b0eadSeric static char buf[512]; 14409f8b0eadSeric 14419f8b0eadSeric (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 14429f8b0eadSeric return buf; 14439f8b0eadSeric } 14449f8b0eadSeric } 1445f36ede03Sbostic 14466c2c3107Seric # else /* DAEMON */ 144799f7cf32Seric /* code for systems without sophisticated networking */ 1448444eaf03Seric 1449444eaf03Seric /* 1450444eaf03Seric ** MYHOSTNAME -- stub version for case of no daemon code. 145121e9914dSeric ** 145221e9914dSeric ** Can't convert to upper case here because might be a UUCP name. 1453897f1869Seric ** 1454897f1869Seric ** Mark, you can change this to be anything you want...... 1455444eaf03Seric */ 1456444eaf03Seric 1457444eaf03Seric char ** 1458897f1869Seric myhostname(hostbuf, size) 1459444eaf03Seric char hostbuf[]; 1460897f1869Seric int size; 1461444eaf03Seric { 1462444eaf03Seric register FILE *f; 1463444eaf03Seric 1464444eaf03Seric hostbuf[0] = '\0'; 1465444eaf03Seric f = fopen("/usr/include/whoami", "r"); 1466444eaf03Seric if (f != NULL) 1467444eaf03Seric { 1468897f1869Seric (void) fgets(hostbuf, size, f); 1469444eaf03Seric fixcrlf(hostbuf, TRUE); 1470444eaf03Seric (void) fclose(f); 1471444eaf03Seric } 1472444eaf03Seric return (NULL); 1473444eaf03Seric } 147499f7cf32Seric /* 14759f8b0eadSeric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 1476320e0d1cSeric ** 1477320e0d1cSeric ** Parameters: 1478320e0d1cSeric ** fd -- the descriptor 1479320e0d1cSeric ** 1480320e0d1cSeric ** Returns: 1481320e0d1cSeric ** The host name associated with this descriptor, if it can 1482320e0d1cSeric ** be determined. 1483320e0d1cSeric ** NULL otherwise. 1484320e0d1cSeric ** 1485320e0d1cSeric ** Side Effects: 1486320e0d1cSeric ** none 1487320e0d1cSeric */ 1488320e0d1cSeric 1489320e0d1cSeric char * 14909f8b0eadSeric getauthinfo(fd) 1491320e0d1cSeric int fd; 1492320e0d1cSeric { 1493320e0d1cSeric return NULL; 1494320e0d1cSeric } 1495320e0d1cSeric /* 149699f7cf32Seric ** MAPHOSTNAME -- turn a hostname into canonical form 149799f7cf32Seric ** 149899f7cf32Seric ** Parameters: 149905b57da8Seric ** map -- a pointer to the database map. 150008de856eSeric ** name -- a buffer containing a hostname. 150115d084d5Seric ** avp -- a pointer to a (cf file defined) argument vector. 15022d29d43aSeric ** statp -- an exit status (out parameter). 150399f7cf32Seric ** 150499f7cf32Seric ** Returns: 150515d084d5Seric ** mapped host name 1506cb452edcSeric ** FALSE otherwise. 150799f7cf32Seric ** 150899f7cf32Seric ** Side Effects: 150908de856eSeric ** Looks up the host specified in name. If it is not 151099f7cf32Seric ** the canonical name for that host, replace it with 151199f7cf32Seric ** the canonical name. If the name is unknown, or it 151299f7cf32Seric ** is already the canonical name, leave it unchanged. 151399f7cf32Seric */ 151499f7cf32Seric 151599f7cf32Seric /*ARGSUSED*/ 151615d084d5Seric char * 151708de856eSeric host_map_lookup(map, name, avp, statp) 151805b57da8Seric MAP *map; 151908de856eSeric char *name; 152015d084d5Seric char **avp; 15212d29d43aSeric char *statp; 152299f7cf32Seric { 15232d29d43aSeric register struct hostent *hp; 15242d29d43aSeric 152508de856eSeric hp = gethostbyname(name); 15262d29d43aSeric if (hp != NULL) 15272d29d43aSeric return hp->h_name; 15282d29d43aSeric *statp = EX_NOHOST; 152915d084d5Seric return NULL; 153099f7cf32Seric } 153199f7cf32Seric 15326c2c3107Seric #endif /* DAEMON */ 1533