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*4a5c6430Seric static char sccsid[] = "@(#)daemon.c 8.45 (Berkeley) 04/17/94 (with daemon mode)"; 15d0a9e852Seric #else 16*4a5c6430Seric static char sccsid[] = "@(#)daemon.c 8.45 (Berkeley) 04/17/94 (without daemon mode)"; 17da1c6175Sbostic #endif 18da1c6175Sbostic #endif /* not lint */ 19da1c6175Sbostic 20da1c6175Sbostic #ifdef DAEMON 21d0a9e852Seric 221c71e510Seric # include <netdb.h> 23d8d0a4aeSeric # include <arpa/inet.h> 24d0a9e852Seric 259d4a8008Seric #if NAMED_BIND 263490b9dfSeric # include <arpa/nameser.h> 273490b9dfSeric # include <resolv.h> 283490b9dfSeric #endif 293490b9dfSeric 307fa39d90Seric /* 317fa39d90Seric ** DAEMON.C -- routines to use when running as a daemon. 3247b12ae1Seric ** 3347b12ae1Seric ** This entire file is highly dependent on the 4.2 BSD 3447b12ae1Seric ** interprocess communication primitives. No attempt has 3547b12ae1Seric ** been made to make this file portable to Version 7, 3647b12ae1Seric ** Version 6, MPX files, etc. If you should try such a 3747b12ae1Seric ** thing yourself, I recommend chucking the entire file 3847b12ae1Seric ** and starting from scratch. Basic semantics are: 3947b12ae1Seric ** 4047b12ae1Seric ** getrequests() 4147b12ae1Seric ** Opens a port and initiates a connection. 4247b12ae1Seric ** Returns in a child. Must set InChannel and 4347b12ae1Seric ** OutChannel appropriately. 44b7d7afcbSeric ** clrdaemon() 45b7d7afcbSeric ** Close any open files associated with getting 46b7d7afcbSeric ** the connection; this is used when running the queue, 47b7d7afcbSeric ** etc., to avoid having extra file descriptors during 48b7d7afcbSeric ** the queue run and to avoid confusing the network 49b7d7afcbSeric ** code (if it cares). 50914346b1Seric ** makeconnection(host, port, outfile, infile, usesecureport) 5147b12ae1Seric ** Make a connection to the named host on the given 5247b12ae1Seric ** port. Set *outfile and *infile to the files 5347b12ae1Seric ** appropriate for communication. Returns zero on 5447b12ae1Seric ** success, else an exit status describing the 5547b12ae1Seric ** error. 5608de856eSeric ** host_map_lookup(map, hbuf, avp, pstat) 5705b57da8Seric ** Convert the entry in hbuf into a canonical form. 587fa39d90Seric */ 597fa39d90Seric /* 607fa39d90Seric ** GETREQUESTS -- open mail IPC port and get requests. 617fa39d90Seric ** 627fa39d90Seric ** Parameters: 637fa39d90Seric ** none. 647fa39d90Seric ** 657fa39d90Seric ** Returns: 667fa39d90Seric ** none. 677fa39d90Seric ** 687fa39d90Seric ** Side Effects: 697fa39d90Seric ** Waits until some interesting activity occurs. When 707fa39d90Seric ** it does, a child is created to process it, and the 717fa39d90Seric ** parent waits for completion. Return from this 72147303b1Seric ** routine is always in the child. The file pointers 73147303b1Seric ** "InChannel" and "OutChannel" should be set to point 74147303b1Seric ** to the communication channel. 757fa39d90Seric */ 767fa39d90Seric 77b7d7afcbSeric int DaemonSocket = -1; /* fd describing socket */ 78bfb80540Seric SOCKADDR DaemonAddr; /* socket for incoming */ 79bfc1eaf8Seric int ListenQueueSize = 10; /* size of listen queue */ 80b35447dbSeric int TcpRcvBufferSize = 0; /* size of TCP receive buffer */ 81b35447dbSeric int TcpSndBufferSize = 0; /* size of TCP send buffer */ 821c71e510Seric 837fa39d90Seric getrequests() 847fa39d90Seric { 851c71e510Seric int t; 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 */ 1240084e6f6Seric socksize = opendaemonsocket(); 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 { 18115d084d5Seric /* start listening again */ 1820084e6f6Seric if (DaemonSocket < 0) 1830084e6f6Seric (void) opendaemonsocket(); 18415d084d5Seric setproctitle("accepting connections"); 18515d084d5Seric refusingconnections = FALSE; 1866775ec03Sbostic } 187a44d5a5eSeric 188dfe840b2Seric #ifdef XDEBUG 189dfe840b2Seric /* check for disaster */ 190dfe840b2Seric { 191dfe840b2Seric register STAB *s; 19235852b23Seric char jbuf[MAXHOSTNAMELEN]; 193dfe840b2Seric 19435852b23Seric expand("\201j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv); 19535852b23Seric if ((s = stab(jbuf, ST_CLASS, ST_FIND)) == NULL || 196dfe840b2Seric !bitnset('w', s->s_class)) 197dfe840b2Seric { 198dfe840b2Seric dumpstate("daemon lost $j"); 199dfe840b2Seric syslog(LOG_ALERT, "daemon process doesn't have $j in $=w; see syslog"); 200dfe840b2Seric abort(); 201dfe840b2Seric } 20235852b23Seric else if (j_has_dot && strchr(jbuf, '.') == NULL) 203dfe840b2Seric { 204dfe840b2Seric dumpstate("daemon $j lost dot"); 205dfe840b2Seric syslog(LOG_ALERT, "daemon process $j lost dot; see syslog"); 206dfe840b2Seric abort(); 207dfe840b2Seric } 208dfe840b2Seric } 209dfe840b2Seric #endif 210dfe840b2Seric 2111c71e510Seric /* wait for a connection */ 2121c71e510Seric do 2131c71e510Seric { 2141c71e510Seric errno = 0; 215dadb8687Seric lotherend = socksize; 2169b100374Sbostic t = accept(DaemonSocket, 2179b100374Sbostic (struct sockaddr *)&RealHostAddr, &lotherend); 2181c71e510Seric } while (t < 0 && errno == EINTR); 2191c71e510Seric if (t < 0) 2201c71e510Seric { 2211c71e510Seric syserr("getrequests: accept"); 2221c71e510Seric sleep(5); 2231c71e510Seric continue; 2241c71e510Seric } 225d0a9e852Seric 226d0a9e852Seric /* 227d0a9e852Seric ** Create a subprocess to process the mail. 228d0a9e852Seric */ 229d0a9e852Seric 23061e4310fSeric if (tTd(15, 2)) 2311c71e510Seric printf("getrequests: forking (fd = %d)\n", t); 232eb889047Seric 233a8268164Seric pid = fork(); 234a8268164Seric if (pid < 0) 235a8268164Seric { 236a8268164Seric syserr("daemon: cannot fork"); 237a8268164Seric sleep(10); 2381c71e510Seric (void) close(t); 239a8268164Seric continue; 240a8268164Seric } 241a8268164Seric 242a8268164Seric if (pid == 0) 243a8268164Seric { 244da662164Seric char *p; 2459f8b0eadSeric extern char *hostnamebyanyaddr(); 246a44d5a5eSeric 247a8268164Seric /* 248a8268164Seric ** CHILD -- return to caller. 249a44d5a5eSeric ** Collect verified idea of sending host. 250a8268164Seric ** Verify calling user id if possible here. 251a8268164Seric */ 252a8268164Seric 2532b9178d3Seric (void) setsignal(SIGCHLD, SIG_DFL); 2549f9b003eSeric DisConnected = FALSE; 255779ac194Seric 2564dd09a90Seric setproctitle("startup with %s", 2574dd09a90Seric anynet_ntoa(&RealHostAddr)); 2584dd09a90Seric 259a44d5a5eSeric /* determine host name */ 260da662164Seric p = hostnamebyanyaddr(&RealHostAddr); 261da662164Seric RealHostName = newstr(p); 2624dd09a90Seric setproctitle("startup with %s", p); 26329dcf4baSeric 2642a6bc25bSeric #ifdef LOG 2651f2ff1a4Seric if (LogLevel > 11) 2662a6bc25bSeric { 2672a6bc25bSeric /* log connection information */ 2682a6bc25bSeric syslog(LOG_INFO, "connect from %s (%s)", 2699f8b0eadSeric RealHostName, anynet_ntoa(&RealHostAddr)); 2702a6bc25bSeric } 2712a6bc25bSeric #endif 2722a6bc25bSeric 273244b09d1Seric (void) close(DaemonSocket); 274335eae58Seric if ((InChannel = fdopen(t, "r")) == NULL || 275335eae58Seric (t = dup(t)) < 0 || 276335eae58Seric (OutChannel = fdopen(t, "w")) == NULL) 277335eae58Seric { 278335eae58Seric syserr("cannot open SMTP server channel, fd=%d", t); 279335eae58Seric exit(0); 280335eae58Seric } 281244b09d1Seric 28229dcf4baSeric /* should we check for illegal connection here? XXX */ 283e17a3a5aSeric #ifdef XLA 284e17a3a5aSeric if (!xla_host_ok(RealHostName)) 285e17a3a5aSeric { 286244b09d1Seric message("421 Too many SMTP sessions for this host"); 287e17a3a5aSeric exit(0); 288e17a3a5aSeric } 289e17a3a5aSeric #endif 290a44d5a5eSeric 29161e4310fSeric if (tTd(15, 2)) 292d0a9e852Seric printf("getreq: returning\n"); 293a8268164Seric return; 294a8268164Seric } 295a8268164Seric 2963c154354Seric /* close the port so that others will hang (for a while) */ 2973c154354Seric (void) close(t); 2988e3e4b17Seric } 2993c154354Seric /*NOTREACHED*/ 3003c154354Seric } 3018e3e4b17Seric /* 3020084e6f6Seric ** OPENDAEMONSOCKET -- open the SMTP socket 3030084e6f6Seric ** 3040084e6f6Seric ** Deals with setting all appropriate options. DaemonAddr must 3050084e6f6Seric ** be set up in advance. 3060084e6f6Seric ** 3070084e6f6Seric ** Parameters: 3080084e6f6Seric ** none 3090084e6f6Seric ** 3100084e6f6Seric ** Returns: 3110084e6f6Seric ** Size in bytes of the daemon socket addr. 3120084e6f6Seric ** 3130084e6f6Seric ** Side Effects: 3140084e6f6Seric ** Leaves DaemonSocket set to the open socket. 3150084e6f6Seric ** Exits if the socket cannot be created. 3160084e6f6Seric */ 3170084e6f6Seric 3180084e6f6Seric int 3190084e6f6Seric opendaemonsocket() 3200084e6f6Seric { 3210084e6f6Seric int on = 1; 3220084e6f6Seric int socksize; 3230084e6f6Seric 3240084e6f6Seric if (tTd(15, 2)) 3250084e6f6Seric printf("opendaemonsocket()\n"); 3260084e6f6Seric 3270084e6f6Seric DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0); 3280084e6f6Seric if (DaemonSocket < 0) 3290084e6f6Seric { 3300084e6f6Seric /* probably another daemon already */ 3310084e6f6Seric syserr("opendaemonsocket: can't create server SMTP socket"); 3320084e6f6Seric severe: 3330084e6f6Seric # ifdef LOG 3340084e6f6Seric if (LogLevel > 0) 3350084e6f6Seric syslog(LOG_ALERT, "problem creating SMTP socket"); 3360084e6f6Seric # endif /* LOG */ 3370084e6f6Seric finis(); 3380084e6f6Seric } 3390084e6f6Seric 3400084e6f6Seric /* turn on network debugging? */ 3410084e6f6Seric if (tTd(15, 101)) 3420084e6f6Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof on); 3430084e6f6Seric 3440084e6f6Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof on); 3450084e6f6Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof on); 3460084e6f6Seric 3470084e6f6Seric #ifdef SO_RCVBUF 3480084e6f6Seric if (TcpRcvBufferSize > 0) 3490084e6f6Seric { 3500084e6f6Seric if (setsockopt(DaemonSocket, SOL_SOCKET, SO_RCVBUF, 3510084e6f6Seric (char *) &TcpRcvBufferSize, 3520084e6f6Seric sizeof(TcpRcvBufferSize)) < 0) 3530084e6f6Seric syserr("getrequests: setsockopt(SO_RCVBUF)"); 3540084e6f6Seric } 3550084e6f6Seric #endif 3560084e6f6Seric 3570084e6f6Seric switch (DaemonAddr.sa.sa_family) 3580084e6f6Seric { 3590084e6f6Seric # ifdef NETINET 3600084e6f6Seric case AF_INET: 3610084e6f6Seric socksize = sizeof DaemonAddr.sin; 3620084e6f6Seric break; 3630084e6f6Seric # endif 3640084e6f6Seric 3650084e6f6Seric # ifdef NETISO 3660084e6f6Seric case AF_ISO: 3670084e6f6Seric socksize = sizeof DaemonAddr.siso; 3680084e6f6Seric break; 3690084e6f6Seric # endif 3700084e6f6Seric 3710084e6f6Seric default: 3720084e6f6Seric socksize = sizeof DaemonAddr; 3730084e6f6Seric break; 3740084e6f6Seric } 3750084e6f6Seric 3760084e6f6Seric if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0) 3770084e6f6Seric { 3780084e6f6Seric syserr("getrequests: cannot bind"); 3790084e6f6Seric (void) close(DaemonSocket); 3800084e6f6Seric goto severe; 3810084e6f6Seric } 3820084e6f6Seric if (listen(DaemonSocket, ListenQueueSize) < 0) 3830084e6f6Seric { 3840084e6f6Seric syserr("getrequests: cannot listen"); 3850084e6f6Seric (void) close(DaemonSocket); 3860084e6f6Seric goto severe; 3870084e6f6Seric } 3880084e6f6Seric return socksize; 3890084e6f6Seric } 3900084e6f6Seric /* 391b7d7afcbSeric ** CLRDAEMON -- reset the daemon connection 392b7d7afcbSeric ** 393b7d7afcbSeric ** Parameters: 394b7d7afcbSeric ** none. 395b7d7afcbSeric ** 396b7d7afcbSeric ** Returns: 397b7d7afcbSeric ** none. 398b7d7afcbSeric ** 399b7d7afcbSeric ** Side Effects: 400b7d7afcbSeric ** releases any resources used by the passive daemon. 401b7d7afcbSeric */ 402b7d7afcbSeric 403b7d7afcbSeric clrdaemon() 404b7d7afcbSeric { 405b7d7afcbSeric if (DaemonSocket >= 0) 406b7d7afcbSeric (void) close(DaemonSocket); 407b7d7afcbSeric DaemonSocket = -1; 408b7d7afcbSeric } 409b7d7afcbSeric /* 410bfb80540Seric ** SETDAEMONOPTIONS -- set options for running the daemon 411bfb80540Seric ** 412bfb80540Seric ** Parameters: 413bfb80540Seric ** p -- the options line. 414bfb80540Seric ** 415bfb80540Seric ** Returns: 416bfb80540Seric ** none. 417bfb80540Seric */ 418bfb80540Seric 419bfb80540Seric setdaemonoptions(p) 420bfb80540Seric register char *p; 421bfb80540Seric { 422850144caSeric if (DaemonAddr.sa.sa_family == AF_UNSPEC) 423850144caSeric DaemonAddr.sa.sa_family = AF_INET; 424850144caSeric 425bfb80540Seric while (p != NULL) 426bfb80540Seric { 427bfb80540Seric register char *f; 428bfb80540Seric register char *v; 429bfb80540Seric 430bfb80540Seric while (isascii(*p) && isspace(*p)) 431bfb80540Seric p++; 432bfb80540Seric if (*p == '\0') 433bfb80540Seric break; 434bfb80540Seric f = p; 435bfb80540Seric p = strchr(p, ','); 436bfb80540Seric if (p != NULL) 437bfb80540Seric *p++ = '\0'; 438bfb80540Seric v = strchr(f, '='); 439bfb80540Seric if (v == NULL) 440bfb80540Seric continue; 441bfb80540Seric while (isascii(*++v) && isspace(*v)) 442bfb80540Seric continue; 443bfb80540Seric 444bfb80540Seric switch (*f) 445bfb80540Seric { 446850144caSeric case 'F': /* address family */ 447850144caSeric if (isascii(*v) && isdigit(*v)) 448850144caSeric DaemonAddr.sa.sa_family = atoi(v); 449850144caSeric #ifdef NETINET 450850144caSeric else if (strcasecmp(v, "inet") == 0) 451850144caSeric DaemonAddr.sa.sa_family = AF_INET; 452850144caSeric #endif 453850144caSeric #ifdef NETISO 454850144caSeric else if (strcasecmp(v, "iso") == 0) 455850144caSeric DaemonAddr.sa.sa_family = AF_ISO; 456850144caSeric #endif 457850144caSeric #ifdef NETNS 458850144caSeric else if (strcasecmp(v, "ns") == 0) 459850144caSeric DaemonAddr.sa.sa_family = AF_NS; 460850144caSeric #endif 461850144caSeric #ifdef NETX25 462850144caSeric else if (strcasecmp(v, "x.25") == 0) 463850144caSeric DaemonAddr.sa.sa_family = AF_CCITT; 464850144caSeric #endif 465850144caSeric else 466850144caSeric syserr("554 Unknown address family %s in Family=option", v); 467850144caSeric break; 468850144caSeric 469850144caSeric case 'A': /* address */ 470850144caSeric switch (DaemonAddr.sa.sa_family) 471850144caSeric { 472850144caSeric #ifdef NETINET 473850144caSeric case AF_INET: 474850144caSeric if (isascii(*v) && isdigit(*v)) 475850144caSeric DaemonAddr.sin.sin_addr.s_addr = inet_network(v); 476850144caSeric else 477850144caSeric { 478850144caSeric register struct netent *np; 479850144caSeric 480850144caSeric np = getnetbyname(v); 481850144caSeric if (np == NULL) 482850144caSeric syserr("554 network \"%s\" unknown", v); 483850144caSeric else 484850144caSeric DaemonAddr.sin.sin_addr.s_addr = np->n_net; 485850144caSeric } 486850144caSeric break; 487850144caSeric #endif 488850144caSeric 489850144caSeric default: 490850144caSeric syserr("554 Address= option unsupported for family %d", 491850144caSeric DaemonAddr.sa.sa_family); 492850144caSeric break; 493850144caSeric } 494850144caSeric break; 495850144caSeric 496bfb80540Seric case 'P': /* port */ 497850144caSeric switch (DaemonAddr.sa.sa_family) 498850144caSeric { 499850144caSeric short port; 500850144caSeric 501850144caSeric #ifdef NETINET 502850144caSeric case AF_INET: 503bfb80540Seric if (isascii(*v) && isdigit(*v)) 50476b70c58Seric DaemonAddr.sin.sin_port = htons(atoi(v)); 505bfb80540Seric else 506bfb80540Seric { 507bfb80540Seric register struct servent *sp; 508bfb80540Seric 509bfb80540Seric sp = getservbyname(v, "tcp"); 510bfb80540Seric if (sp == NULL) 511ad977999Seric syserr("554 service \"%s\" unknown", v); 512bfb80540Seric else 513bfb80540Seric DaemonAddr.sin.sin_port = sp->s_port; 514bfb80540Seric } 515bfb80540Seric break; 516850144caSeric #endif 517bfb80540Seric 518850144caSeric #ifdef NETISO 519850144caSeric case AF_ISO: 520850144caSeric /* assume two byte transport selector */ 521bfb80540Seric if (isascii(*v) && isdigit(*v)) 52276b70c58Seric port = htons(atoi(v)); 523bfb80540Seric else 524bfb80540Seric { 525850144caSeric register struct servent *sp; 526bfb80540Seric 527850144caSeric sp = getservbyname(v, "tcp"); 528850144caSeric if (sp == NULL) 529ad977999Seric syserr("554 service \"%s\" unknown", v); 530bfb80540Seric else 531850144caSeric port = sp->s_port; 532850144caSeric } 533850144caSeric bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2); 534850144caSeric break; 535850144caSeric #endif 536850144caSeric 537850144caSeric default: 538850144caSeric syserr("554 Port= option unsupported for family %d", 539850144caSeric DaemonAddr.sa.sa_family); 540850144caSeric break; 541bfb80540Seric } 542bfb80540Seric break; 543bfc1eaf8Seric 544bfc1eaf8Seric case 'L': /* listen queue size */ 545bfc1eaf8Seric ListenQueueSize = atoi(v); 546bfc1eaf8Seric break; 547b35447dbSeric 548b35447dbSeric case 'S': /* send buffer size */ 549b35447dbSeric TcpSndBufferSize = atoi(v); 550b35447dbSeric break; 551b35447dbSeric 552b35447dbSeric case 'R': /* receive buffer size */ 553b35447dbSeric TcpRcvBufferSize = atoi(v); 554b35447dbSeric break; 555bfb80540Seric } 556bfb80540Seric } 557bfb80540Seric } 558bfb80540Seric /* 5597aa493c5Seric ** MAKECONNECTION -- make a connection to an SMTP socket on another machine. 5607aa493c5Seric ** 5617aa493c5Seric ** Parameters: 5627aa493c5Seric ** host -- the name of the host. 56348ff0a9dSeric ** port -- the port number to connect to. 564655feedbSeric ** mci -- a pointer to the mail connection information 565655feedbSeric ** structure to be filled in. 566914346b1Seric ** usesecureport -- if set, use a low numbered (reserved) 567914346b1Seric ** port to provide some rudimentary authentication. 5687aa493c5Seric ** 5697aa493c5Seric ** Returns: 5707aa493c5Seric ** An exit code telling whether the connection could be 5717aa493c5Seric ** made and if not why not. 5727aa493c5Seric ** 5737aa493c5Seric ** Side Effects: 5747aa493c5Seric ** none. 5757aa493c5Seric */ 5767aa493c5Seric 577e2f2f828Seric SOCKADDR CurHostAddr; /* address of current host */ 57871ff6caaSeric 579b31e7f2bSeric int 580655feedbSeric makeconnection(host, port, mci, usesecureport) 5817aa493c5Seric char *host; 582210215eaSeric u_short port; 583b31e7f2bSeric register MCI *mci; 584914346b1Seric bool usesecureport; 5857aa493c5Seric { 58604344589Sbloom register int i, s; 58704344589Sbloom register struct hostent *hp = (struct hostent *)NULL; 588e2f2f828Seric SOCKADDR addr; 5896286bb75Sbloom int sav_errno; 590e2f2f828Seric int addrlen; 5919d4a8008Seric #if NAMED_BIND 592134746fbSeric extern int h_errno; 593134746fbSeric #endif 5947aa493c5Seric 5957aa493c5Seric /* 5967aa493c5Seric ** Set up the address for the mailer. 59771096d12Seric ** Accept "[a.b.c.d]" syntax for host name. 5987aa493c5Seric */ 5997aa493c5Seric 6009d4a8008Seric #if NAMED_BIND 601794bdbb9Smiriam h_errno = 0; 602134746fbSeric #endif 603794bdbb9Smiriam errno = 0; 604967778e2Seric bzero(&CurHostAddr, sizeof CurHostAddr); 605c931b82bSeric SmtpPhase = mci->mci_phase = "initial connection"; 606d945ebe8Seric CurHostName = host; 607794bdbb9Smiriam 60871096d12Seric if (host[0] == '[') 60971096d12Seric { 610a44d5a5eSeric long hid; 6116c2c3107Seric register char *p = strchr(host, ']'); 61271096d12Seric 613a44d5a5eSeric if (p != NULL) 61471096d12Seric { 615a44d5a5eSeric *p = '\0'; 6164d9c42c2Seric #ifdef NETINET 617a44d5a5eSeric hid = inet_addr(&host[1]); 618a7e21fe6Seric if (hid == -1) 6194d9c42c2Seric #endif 620a7e21fe6Seric { 621a7e21fe6Seric /* try it as a host name (avoid MX lookup) */ 622a7e21fe6Seric hp = gethostbyname(&host[1]); 623d8984352Seric if (hp == NULL && p[-1] == '.') 624d8984352Seric { 625d8984352Seric p[-1] = '\0'; 626d8984352Seric hp = gethostbyname(&host[1]); 627d8984352Seric p[-1] = '.'; 628d8984352Seric } 629a7e21fe6Seric *p = ']'; 630a7e21fe6Seric goto gothostent; 631a7e21fe6Seric } 632a44d5a5eSeric *p = ']'; 63371096d12Seric } 634a7e21fe6Seric if (p == NULL) 63571096d12Seric { 63608b25121Seric usrerr("553 Invalid numeric domain spec \"%s\"", host); 63771096d12Seric return (EX_NOHOST); 63871096d12Seric } 6394d9c42c2Seric #ifdef NETINET 6404d9c42c2Seric addr.sin.sin_family = AF_INET; /*XXX*/ 64183c1f4bcSeric addr.sin.sin_addr.s_addr = hid; 6424d9c42c2Seric #endif 64371096d12Seric } 6441c71e510Seric else 6451c71e510Seric { 646d8984352Seric register char *p = &host[strlen(host) - 1]; 647d8984352Seric 64804344589Sbloom hp = gethostbyname(host); 649d8984352Seric if (hp == NULL && *p == '.') 650d8984352Seric { 651d8984352Seric *p = '\0'; 652d8984352Seric hp = gethostbyname(host); 653d8984352Seric *p = '.'; 654d8984352Seric } 655a7e21fe6Seric gothostent: 656794bdbb9Smiriam if (hp == NULL) 657794bdbb9Smiriam { 6589d4a8008Seric #if NAMED_BIND 659794bdbb9Smiriam if (errno == ETIMEDOUT || h_errno == TRY_AGAIN) 66052308a50Seric return (EX_TEMPFAIL); 66182e5d8ddSeric 662134746fbSeric /* if name server is specified, assume temp fail */ 663134746fbSeric if (errno == ECONNREFUSED && UseNameServer) 664134746fbSeric return (EX_TEMPFAIL); 665134746fbSeric #endif 6667aa493c5Seric return (EX_NOHOST); 667794bdbb9Smiriam } 66883c1f4bcSeric addr.sa.sa_family = hp->h_addrtype; 66983c1f4bcSeric switch (hp->h_addrtype) 67083c1f4bcSeric { 67183c1f4bcSeric #ifdef NETINET 67283c1f4bcSeric case AF_INET: 673e2f2f828Seric bcopy(hp->h_addr, 67483c1f4bcSeric &addr.sin.sin_addr, 675859d5010Seric sizeof addr.sin.sin_addr); 67683c1f4bcSeric break; 67783c1f4bcSeric #endif 67883c1f4bcSeric 67983c1f4bcSeric default: 680e2f2f828Seric bcopy(hp->h_addr, 68183c1f4bcSeric addr.sa.sa_data, 682e2f2f828Seric hp->h_length); 68383c1f4bcSeric break; 68483c1f4bcSeric } 68504344589Sbloom i = 1; 6861c71e510Seric } 6871c71e510Seric 6881c71e510Seric /* 6891c71e510Seric ** Determine the port number. 6901c71e510Seric */ 6911c71e510Seric 692fd7c0790Seric if (port != 0) 693e2f2f828Seric port = htons(port); 694fd7c0790Seric else 6951c71e510Seric { 6961c71e510Seric register struct servent *sp = getservbyname("smtp", "tcp"); 6971c71e510Seric 6981c71e510Seric if (sp == NULL) 6991c71e510Seric { 700ad977999Seric syserr("554 makeconnection: service \"smtp\" unknown"); 701e5311662Seric port = htons(25); 7021c71e510Seric } 703e5311662Seric else 704e2f2f828Seric port = sp->s_port; 705e2f2f828Seric } 706e2f2f828Seric 70783c1f4bcSeric switch (addr.sa.sa_family) 708e2f2f828Seric { 7094d9c42c2Seric #ifdef NETINET 710e2f2f828Seric case AF_INET: 71183c1f4bcSeric addr.sin.sin_port = port; 712e2f2f828Seric addrlen = sizeof (struct sockaddr_in); 713e2f2f828Seric break; 7144d9c42c2Seric #endif 715e2f2f828Seric 716e2f2f828Seric #ifdef NETISO 717e2f2f828Seric case AF_ISO: 718e2f2f828Seric /* assume two byte transport selector */ 719e2f2f828Seric bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2); 720e2f2f828Seric addrlen = sizeof (struct sockaddr_iso); 721e2f2f828Seric break; 722e2f2f828Seric #endif 723e2f2f828Seric 724e2f2f828Seric default: 72583c1f4bcSeric syserr("Can't connect to address family %d", addr.sa.sa_family); 726e2f2f828Seric return (EX_NOHOST); 7271c71e510Seric } 7287aa493c5Seric 7297aa493c5Seric /* 7307aa493c5Seric ** Try to actually open the connection. 7317aa493c5Seric */ 7327aa493c5Seric 733e17a3a5aSeric #ifdef XLA 734e17a3a5aSeric /* if too many connections, don't bother trying */ 735e17a3a5aSeric if (!xla_noqueue_ok(host)) 736e17a3a5aSeric return EX_TEMPFAIL; 737e17a3a5aSeric #endif 738e17a3a5aSeric 739aea02ca1Seric for (;;) 740aea02ca1Seric { 74161e4310fSeric if (tTd(16, 1)) 742e2f2f828Seric printf("makeconnection (%s [%s])\n", 743e2f2f828Seric host, anynet_ntoa(&addr)); 7447aa493c5Seric 745226e3022Seric /* save for logging */ 746226e3022Seric CurHostAddr = addr; 747226e3022Seric 748914346b1Seric if (usesecureport) 749914346b1Seric { 750914346b1Seric int rport = IPPORT_RESERVED - 1; 751914346b1Seric 752914346b1Seric s = rresvport(&rport); 753914346b1Seric } 754914346b1Seric else 755914346b1Seric { 756af5e902cSeric s = socket(AF_INET, SOCK_STREAM, 0); 757914346b1Seric } 7587aa493c5Seric if (s < 0) 7597aa493c5Seric { 7606286bb75Sbloom sav_errno = errno; 761914346b1Seric syserr("makeconnection: no socket"); 7627aa493c5Seric goto failure; 7637aa493c5Seric } 7647aa493c5Seric 765b35447dbSeric #ifdef SO_SNDBUF 766b35447dbSeric if (TcpSndBufferSize > 0) 767b35447dbSeric { 768b35447dbSeric if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, 769bf217a95Seric (char *) &TcpSndBufferSize, 770b35447dbSeric sizeof(TcpSndBufferSize)) < 0) 771b35447dbSeric syserr("makeconnection: setsockopt(SO_SNDBUF)"); 772b35447dbSeric } 773b35447dbSeric #endif 774b35447dbSeric 77561e4310fSeric if (tTd(16, 1)) 776b31e7f2bSeric printf("makeconnection: fd=%d\n", s); 7771b6e4a15Seric 7781b6e4a15Seric /* turn on network debugging? */ 779a2ef5fa4Seric if (tTd(16, 101)) 78052308a50Seric { 78152308a50Seric int on = 1; 782aea02ca1Seric (void) setsockopt(DaemonSocket, SOL_SOCKET, SO_DEBUG, 783aea02ca1Seric (char *)&on, sizeof on); 78452308a50Seric } 78587d6e633Srick if (CurEnv->e_xfp != NULL) 786877a6142Seric (void) fflush(CurEnv->e_xfp); /* for debugging */ 7874bd6a662Seric errno = 0; /* for debugging */ 788e2f2f828Seric if (connect(s, (struct sockaddr *) &addr, addrlen) >= 0) 789aea02ca1Seric break; 790aea02ca1Seric 791aea02ca1Seric /* couldn't connect.... figure out why */ 7926286bb75Sbloom sav_errno = errno; 7936286bb75Sbloom (void) close(s); 79404344589Sbloom if (hp && hp->h_addr_list[i]) 79504344589Sbloom { 796aea02ca1Seric if (tTd(16, 1)) 797e2f2f828Seric printf("Connect failed (%s); trying new address....\n", 798e2f2f828Seric errstring(sav_errno)); 79983c1f4bcSeric switch (addr.sa.sa_family) 80083c1f4bcSeric { 80183c1f4bcSeric #ifdef NETINET 80283c1f4bcSeric case AF_INET: 803e2f2f828Seric bcopy(hp->h_addr_list[i++], 80483c1f4bcSeric &addr.sin.sin_addr, 805859d5010Seric sizeof addr.sin.sin_addr); 80683c1f4bcSeric break; 80783c1f4bcSeric #endif 80883c1f4bcSeric 80983c1f4bcSeric default: 810e2f2f828Seric bcopy(hp->h_addr_list[i++], 81183c1f4bcSeric addr.sa.sa_data, 812914346b1Seric hp->h_length); 81383c1f4bcSeric break; 81483c1f4bcSeric } 815aea02ca1Seric continue; 81604344589Sbloom } 81704344589Sbloom 8187aa493c5Seric /* failure, decide if temporary or not */ 8197aa493c5Seric failure: 820244b09d1Seric #ifdef XLA 821244b09d1Seric xla_host_end(host); 822244b09d1Seric #endif 823e2de2524Seric if (transienterror(sav_errno)) 824e2de2524Seric return EX_TEMPFAIL; 825e2de2524Seric else 82687d6e633Srick { 82708b25121Seric message("%s", errstring(sav_errno)); 8287aa493c5Seric return (EX_UNAVAILABLE); 8297aa493c5Seric } 8307aa493c5Seric } 8317aa493c5Seric 8327aa493c5Seric /* connection ok, put it into canonical form */ 833335eae58Seric if ((mci->mci_out = fdopen(s, "w")) == NULL || 834335eae58Seric (s = dup(s)) < 0 || 835ab81ee53Seric (mci->mci_in = fdopen(s, "r")) == NULL) 836335eae58Seric { 837335eae58Seric syserr("cannot open SMTP client channel, fd=%d", s); 838335eae58Seric return EX_TEMPFAIL; 839335eae58Seric } 8407aa493c5Seric 841dca8e1f7Seric return (EX_OK); 8427aa493c5Seric } 843444eaf03Seric /* 844444eaf03Seric ** MYHOSTNAME -- return the name of this host. 845444eaf03Seric ** 846444eaf03Seric ** Parameters: 847444eaf03Seric ** hostbuf -- a place to return the name of this host. 848897f1869Seric ** size -- the size of hostbuf. 849444eaf03Seric ** 850444eaf03Seric ** Returns: 851444eaf03Seric ** A list of aliases for this host. 852444eaf03Seric ** 853444eaf03Seric ** Side Effects: 854d8d0a4aeSeric ** Adds numeric codes to $=w. 855444eaf03Seric */ 856444eaf03Seric 857444eaf03Seric char ** 858897f1869Seric myhostname(hostbuf, size) 859444eaf03Seric char hostbuf[]; 860897f1869Seric int size; 861444eaf03Seric { 86238ad259dSeric register struct hostent *hp; 863444eaf03Seric extern struct hostent *gethostbyname(); 864444eaf03Seric 865af5e902cSeric if (gethostname(hostbuf, size) < 0) 866af5e902cSeric { 867af5e902cSeric (void) strcpy(hostbuf, "localhost"); 868af5e902cSeric } 869a44d5a5eSeric hp = gethostbyname(hostbuf); 870*4a5c6430Seric if (hp == NULL) 8717364df9fSeric { 872*4a5c6430Seric syserr("!My host name (%s) does not seem to exist!", hostbuf); 873*4a5c6430Seric } 87435852b23Seric (void) strncpy(hostbuf, hp->h_name, size - 1); 87535852b23Seric hostbuf[size - 1] = '\0'; 876*4a5c6430Seric 877*4a5c6430Seric #if NAMED_BIND 878*4a5c6430Seric /* if still no dot, try DNS directly (i.e., avoid NIS problems) */ 87935852b23Seric if (strchr(hostbuf, '.') == NULL) 880747df804Seric { 881747df804Seric extern bool getcanonname(); 882*4a5c6430Seric extern int h_errno; 883747df804Seric 884*4a5c6430Seric /* try twice in case name server not yet started up */ 885*4a5c6430Seric if (!getcanonname(hostbuf, size, TRUE) && 886*4a5c6430Seric UseNameServer && 887*4a5c6430Seric (h_errno != TRY_AGAIN || 888*4a5c6430Seric (sleep(30), !getcanonname(hostbuf, size, TRUE)))) 889*4a5c6430Seric { 890*4a5c6430Seric errno = h_errno + E_DNSBASE; 891*4a5c6430Seric syserr("!My host name (%s) not known to DNS", 892*4a5c6430Seric hostbuf); 893*4a5c6430Seric } 894747df804Seric } 895747df804Seric #endif 89638ad259dSeric 89738ad259dSeric if (hp->h_addrtype == AF_INET && hp->h_length == 4) 89838ad259dSeric { 89938ad259dSeric register int i; 90038ad259dSeric 901d8d0a4aeSeric for (i = 0; hp->h_addr_list[i] != NULL; i++) 90238ad259dSeric { 903d8d0a4aeSeric char ipbuf[100]; 904d8d0a4aeSeric 905d8d0a4aeSeric sprintf(ipbuf, "[%s]", 906d8d0a4aeSeric inet_ntoa(*((struct in_addr *) hp->h_addr_list[i]))); 907d8d0a4aeSeric setclass('w', ipbuf); 90838ad259dSeric } 90938ad259dSeric } 91038ad259dSeric 911a44d5a5eSeric return (hp->h_aliases); 9127364df9fSeric } 913cb452edcSeric /* 9149f8b0eadSeric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 9159f8b0eadSeric ** 9169f8b0eadSeric ** Uses RFC1413 protocol to try to get info from the other end. 917320e0d1cSeric ** 918320e0d1cSeric ** Parameters: 919320e0d1cSeric ** fd -- the descriptor 920320e0d1cSeric ** 921320e0d1cSeric ** Returns: 9229f8b0eadSeric ** The user@host information associated with this descriptor. 923320e0d1cSeric */ 924320e0d1cSeric 925c73f2aa4Seric #if IDENTPROTO 9269f8b0eadSeric 9279f8b0eadSeric static jmp_buf CtxAuthTimeout; 9289f8b0eadSeric 9299f8b0eadSeric static 9309f8b0eadSeric authtimeout() 9319f8b0eadSeric { 9329f8b0eadSeric longjmp(CtxAuthTimeout, 1); 9339f8b0eadSeric } 9349f8b0eadSeric 9359f8b0eadSeric #endif 9369f8b0eadSeric 937320e0d1cSeric char * 9389f8b0eadSeric getauthinfo(fd) 939320e0d1cSeric int fd; 940320e0d1cSeric { 9419f8b0eadSeric int falen; 942a5546e24Seric register char *p; 943c73f2aa4Seric #if IDENTPROTO 9449f8b0eadSeric SOCKADDR la; 9459f8b0eadSeric int lalen; 9469f8b0eadSeric register struct servent *sp; 9479f8b0eadSeric int s; 9489f8b0eadSeric int i; 9499f8b0eadSeric EVENT *ev; 9509f8b0eadSeric #endif 9519f8b0eadSeric static char hbuf[MAXNAME * 2 + 2]; 9529f8b0eadSeric extern char *hostnamebyanyaddr(); 9539f8b0eadSeric extern char RealUserName[]; /* main.c */ 954320e0d1cSeric 955e29a76d1Seric falen = sizeof RealHostAddr; 956e29a76d1Seric if (getpeername(fd, &RealHostAddr.sa, &falen) < 0 || falen <= 0 || 957e29a76d1Seric RealHostAddr.sa.sa_family == 0) 9589f8b0eadSeric { 9599f8b0eadSeric (void) sprintf(hbuf, "%s@localhost", RealUserName); 96053853673Seric if (tTd(9, 1)) 9619f8b0eadSeric printf("getauthinfo: %s\n", hbuf); 962320e0d1cSeric return hbuf; 963320e0d1cSeric } 9649f8b0eadSeric 965e29a76d1Seric if (RealHostName == NULL) 966e29a76d1Seric { 967e29a76d1Seric /* translate that to a host name */ 968e29a76d1Seric RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr)); 969e29a76d1Seric } 970e29a76d1Seric 971c73f2aa4Seric #if IDENTPROTO 97293b3215bSeric if (TimeOuts.to_ident == 0) 97393b3215bSeric goto noident; 97493b3215bSeric 9759f8b0eadSeric lalen = sizeof la; 976e29a76d1Seric if (RealHostAddr.sa.sa_family != AF_INET || 9779f8b0eadSeric getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 || 9789f8b0eadSeric la.sa.sa_family != AF_INET) 9799f8b0eadSeric { 9809f8b0eadSeric /* no ident info */ 9819f8b0eadSeric goto noident; 9829f8b0eadSeric } 9839f8b0eadSeric 9849f8b0eadSeric /* create ident query */ 985f2d880b6Seric (void) sprintf(hbuf, "%d,%d\r\n", 986e29a76d1Seric ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port)); 9879f8b0eadSeric 9889f8b0eadSeric /* create local address */ 989d6af7dadSeric la.sin.sin_port = 0; 9909f8b0eadSeric 9919f8b0eadSeric /* create foreign address */ 9929f8b0eadSeric sp = getservbyname("auth", "tcp"); 9939f8b0eadSeric if (sp != NULL) 994e29a76d1Seric RealHostAddr.sin.sin_port = sp->s_port; 9959f8b0eadSeric else 996e29a76d1Seric RealHostAddr.sin.sin_port = htons(113); 9979f8b0eadSeric 9989f8b0eadSeric s = -1; 9999f8b0eadSeric if (setjmp(CtxAuthTimeout) != 0) 10009f8b0eadSeric { 10019f8b0eadSeric if (s >= 0) 10029f8b0eadSeric (void) close(s); 10039f8b0eadSeric goto noident; 10049f8b0eadSeric } 10059f8b0eadSeric 10069f8b0eadSeric /* put a timeout around the whole thing */ 1007a0f780efSeric ev = setevent(TimeOuts.to_ident, authtimeout, 0); 10089f8b0eadSeric 1009d6af7dadSeric /* connect to foreign IDENT server using same address as SMTP socket */ 10109f8b0eadSeric s = socket(AF_INET, SOCK_STREAM, 0); 10119f8b0eadSeric if (s < 0) 10129f8b0eadSeric { 10139f8b0eadSeric clrevent(ev); 10149f8b0eadSeric goto noident; 10159f8b0eadSeric } 1016d6af7dadSeric if (bind(s, &la.sa, sizeof la.sin) < 0 || 1017e29a76d1Seric connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0) 10189f8b0eadSeric { 10197c201575Seric goto closeident; 10209f8b0eadSeric } 10219f8b0eadSeric 102253853673Seric if (tTd(9, 10)) 10239f8b0eadSeric printf("getauthinfo: sent %s", hbuf); 10249f8b0eadSeric 10259f8b0eadSeric /* send query */ 10269f8b0eadSeric if (write(s, hbuf, strlen(hbuf)) < 0) 10279f8b0eadSeric goto closeident; 10289f8b0eadSeric 10299f8b0eadSeric /* get result */ 10309f8b0eadSeric i = read(s, hbuf, sizeof hbuf); 10319f8b0eadSeric (void) close(s); 10329f8b0eadSeric clrevent(ev); 10339f8b0eadSeric if (i <= 0) 10349f8b0eadSeric goto noident; 10359f8b0eadSeric if (hbuf[--i] == '\n' && hbuf[--i] == '\r') 10369f8b0eadSeric i--; 10379f8b0eadSeric hbuf[++i] = '\0'; 10389f8b0eadSeric 103953853673Seric if (tTd(9, 3)) 10409f8b0eadSeric printf("getauthinfo: got %s\n", hbuf); 10419f8b0eadSeric 10429f8b0eadSeric /* parse result */ 10439f8b0eadSeric p = strchr(hbuf, ':'); 10449f8b0eadSeric if (p == NULL) 10459f8b0eadSeric { 10469f8b0eadSeric /* malformed response */ 10479f8b0eadSeric goto noident; 10489f8b0eadSeric } 10499f8b0eadSeric while (isascii(*++p) && isspace(*p)) 10509f8b0eadSeric continue; 10519f8b0eadSeric if (strncasecmp(p, "userid", 6) != 0) 10529f8b0eadSeric { 10539f8b0eadSeric /* presumably an error string */ 10549f8b0eadSeric goto noident; 10559f8b0eadSeric } 10569f8b0eadSeric p += 6; 10579f8b0eadSeric while (isascii(*p) && isspace(*p)) 10589f8b0eadSeric p++; 10599f8b0eadSeric if (*p++ != ':') 10609f8b0eadSeric { 10619f8b0eadSeric /* either useridxx or malformed response */ 10629f8b0eadSeric goto noident; 10639f8b0eadSeric } 10649f8b0eadSeric 10659f8b0eadSeric /* p now points to the OSTYPE field */ 10669f8b0eadSeric p = strchr(p, ':'); 10679f8b0eadSeric if (p == NULL) 10689f8b0eadSeric { 10699f8b0eadSeric /* malformed response */ 10709f8b0eadSeric goto noident; 10719f8b0eadSeric } 107253853673Seric 107353853673Seric /* 1413 says don't do this -- but it's broken otherwise */ 107453853673Seric while (isascii(*++p) && isspace(*p)) 107553853673Seric continue; 10769f8b0eadSeric 10779f8b0eadSeric /* p now points to the authenticated name */ 1078f7869e68Seric (void) sprintf(hbuf, "%s@%s", 1079f7869e68Seric p, RealHostName == NULL ? "localhost" : RealHostName); 108053853673Seric goto finish; 108153853673Seric 10827c201575Seric closeident: 10837c201575Seric (void) close(s); 10847c201575Seric clrevent(ev); 10857c201575Seric 108653853673Seric #endif /* IDENTPROTO */ 108753853673Seric 108853853673Seric noident: 1089f7869e68Seric if (RealHostName == NULL) 1090f7869e68Seric { 1091f7869e68Seric if (tTd(9, 1)) 1092f7869e68Seric printf("getauthinfo: NULL\n"); 1093f7869e68Seric return NULL; 1094f7869e68Seric } 109553853673Seric (void) strcpy(hbuf, RealHostName); 109653853673Seric 109753853673Seric finish: 1098f7869e68Seric if (RealHostName != NULL && RealHostName[0] != '[') 10999f8b0eadSeric { 11009f8b0eadSeric p = &hbuf[strlen(hbuf)]; 11019f8b0eadSeric (void) sprintf(p, " [%s]", anynet_ntoa(&RealHostAddr)); 11029f8b0eadSeric } 110353853673Seric if (tTd(9, 1)) 11049f8b0eadSeric printf("getauthinfo: %s\n", hbuf); 11059f8b0eadSeric return hbuf; 11069f8b0eadSeric } 1107320e0d1cSeric /* 110808de856eSeric ** HOST_MAP_LOOKUP -- turn a hostname into canonical form 110915d084d5Seric ** 111015d084d5Seric ** Parameters: 111105b57da8Seric ** map -- a pointer to this map (unused). 111208de856eSeric ** name -- the (presumably unqualified) hostname. 111300b385a9Seric ** av -- unused -- for compatibility with other mapping 1114d798a1deSeric ** functions. 11152d29d43aSeric ** statp -- an exit status (out parameter) -- set to 11162d29d43aSeric ** EX_TEMPFAIL if the name server is unavailable. 111715d084d5Seric ** 111815d084d5Seric ** Returns: 111915d084d5Seric ** The mapping, if found. 112015d084d5Seric ** NULL if no mapping found. 112115d084d5Seric ** 112215d084d5Seric ** Side Effects: 112315d084d5Seric ** Looks up the host specified in hbuf. If it is not 112415d084d5Seric ** the canonical name for that host, return the canonical 112515d084d5Seric ** name. 1126f36ede03Sbostic */ 1127cb452edcSeric 112815d084d5Seric char * 112900b385a9Seric host_map_lookup(map, name, av, statp) 113005b57da8Seric MAP *map; 113108de856eSeric char *name; 113200b385a9Seric char **av; 11332d29d43aSeric int *statp; 113499f7cf32Seric { 113599f7cf32Seric register struct hostent *hp; 11365f78836eSmiriam u_long in_addr; 113705b57da8Seric char *cp; 113838ad259dSeric int i; 1139eea91d78Seric register STAB *s; 114000b385a9Seric char hbuf[MAXNAME]; 1141eea91d78Seric extern struct hostent *gethostbyaddr(); 11429d4a8008Seric #if NAMED_BIND 1143eea91d78Seric extern int h_errno; 1144c304a798Seric #endif 11455f78836eSmiriam 1146f36ede03Sbostic /* 1147eea91d78Seric ** See if we have already looked up this name. If so, just 1148eea91d78Seric ** return it. 1149eea91d78Seric */ 1150eea91d78Seric 115108de856eSeric s = stab(name, ST_NAMECANON, ST_ENTER); 1152eea91d78Seric if (bitset(NCF_VALID, s->s_namecanon.nc_flags)) 1153eea91d78Seric { 1154f92c3297Seric if (tTd(9, 1)) 115508de856eSeric printf("host_map_lookup(%s) => CACHE %s\n", 115608de856eSeric name, s->s_namecanon.nc_cname); 1157eea91d78Seric errno = s->s_namecanon.nc_errno; 11589d4a8008Seric #if NAMED_BIND 1159eea91d78Seric h_errno = s->s_namecanon.nc_herrno; 1160c304a798Seric #endif 1161eea91d78Seric *statp = s->s_namecanon.nc_stat; 116292270fb3Seric if (CurEnv->e_message == NULL && *statp == EX_TEMPFAIL) 1163ed63aae0Seric { 1164ed63aae0Seric sprintf(hbuf, "%s: Name server timeout", 1165ed63aae0Seric shortenstring(name, 33)); 1166ed63aae0Seric CurEnv->e_message = newstr(hbuf); 1167ed63aae0Seric } 1168eea91d78Seric return s->s_namecanon.nc_cname; 1169eea91d78Seric } 1170eea91d78Seric 1171eea91d78Seric /* 1172eea91d78Seric ** If first character is a bracket, then it is an address 1173eea91d78Seric ** lookup. Address is copied into a temporary buffer to 117408de856eSeric ** strip the brackets and to preserve name if address is 1175eea91d78Seric ** unknown. 1176f36ede03Sbostic */ 117715d084d5Seric 117808de856eSeric if (*name != '[') 117915d084d5Seric { 1180d798a1deSeric extern bool getcanonname(); 1181d798a1deSeric 11828cb4653dSeric if (tTd(9, 1)) 118308de856eSeric printf("host_map_lookup(%s) => ", name); 1184eea91d78Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 118508de856eSeric (void) strcpy(hbuf, name); 11861f2ff1a4Seric if (getcanonname(hbuf, sizeof hbuf - 1, TRUE)) 11879040ec4fSeric { 11889040ec4fSeric if (tTd(9, 1)) 11899040ec4fSeric printf("%s\n", hbuf); 119000b385a9Seric cp = map_rewrite(map, hbuf, strlen(hbuf), av); 119100b385a9Seric s->s_namecanon.nc_cname = newstr(cp); 119200b385a9Seric return cp; 11939040ec4fSeric } 119415d084d5Seric else 11959040ec4fSeric { 11962d29d43aSeric register struct hostent *hp; 11972d29d43aSeric 1198c304a798Seric s->s_namecanon.nc_errno = errno; 11999d4a8008Seric #if NAMED_BIND 1200c304a798Seric s->s_namecanon.nc_herrno = h_errno; 12019040ec4fSeric if (tTd(9, 1)) 12022d29d43aSeric printf("FAIL (%d)\n", h_errno); 12032d29d43aSeric switch (h_errno) 12042d29d43aSeric { 12052d29d43aSeric case TRY_AGAIN: 120689cb2793Seric if (UseNameServer) 12078820d51bSeric { 1208e0326f4fSeric sprintf(hbuf, "%s: Name server timeout", 1209ed63aae0Seric shortenstring(name, 33)); 1210e0326f4fSeric message("%s", hbuf); 12118820d51bSeric if (CurEnv->e_message == NULL) 1212e0326f4fSeric CurEnv->e_message = newstr(hbuf); 12138820d51bSeric } 12142d29d43aSeric *statp = EX_TEMPFAIL; 12152d29d43aSeric break; 12162d29d43aSeric 12172d29d43aSeric case HOST_NOT_FOUND: 12182d29d43aSeric *statp = EX_NOHOST; 12192d29d43aSeric break; 12202d29d43aSeric 12212d29d43aSeric case NO_RECOVERY: 12222d29d43aSeric *statp = EX_SOFTWARE; 12232d29d43aSeric break; 12242d29d43aSeric 12252d29d43aSeric default: 12262d29d43aSeric *statp = EX_UNAVAILABLE; 12272d29d43aSeric break; 12282d29d43aSeric } 1229c304a798Seric #else 1230c304a798Seric if (tTd(9, 1)) 1231c304a798Seric printf("FAIL\n"); 1232c304a798Seric *statp = EX_NOHOST; 1233c304a798Seric #endif 1234eea91d78Seric s->s_namecanon.nc_stat = *statp; 12352d29d43aSeric if (*statp != EX_TEMPFAIL || UseNameServer) 123615d084d5Seric return NULL; 12372d29d43aSeric 12382d29d43aSeric /* 12392d29d43aSeric ** Try to look it up in /etc/hosts 12402d29d43aSeric */ 12412d29d43aSeric 124208de856eSeric hp = gethostbyname(name); 12432d29d43aSeric if (hp == NULL) 12442d29d43aSeric { 12452d29d43aSeric /* no dice there either */ 1246eea91d78Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 12472d29d43aSeric return NULL; 12482d29d43aSeric } 12492d29d43aSeric 1250eea91d78Seric s->s_namecanon.nc_stat = *statp = EX_OK; 125100b385a9Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 125200b385a9Seric s->s_namecanon.nc_cname = newstr(cp); 125300b385a9Seric return cp; 125415d084d5Seric } 12559040ec4fSeric } 125608de856eSeric if ((cp = strchr(name, ']')) == NULL) 125715d084d5Seric return (NULL); 125834e39927Sbostic *cp = '\0'; 125908de856eSeric in_addr = inet_addr(&name[1]); 126038ad259dSeric 126138ad259dSeric /* nope -- ask the name server */ 126231601fa7Seric hp = gethostbyaddr((char *)&in_addr, sizeof(struct in_addr), AF_INET); 1263eea91d78Seric s->s_namecanon.nc_errno = errno; 12649d4a8008Seric #if NAMED_BIND 1265eea91d78Seric s->s_namecanon.nc_herrno = h_errno; 1266c304a798Seric #endif 1267eea91d78Seric s->s_namecanon.nc_flags |= NCF_VALID; /* will be soon */ 12685f78836eSmiriam if (hp == NULL) 1269eea91d78Seric { 1270eea91d78Seric s->s_namecanon.nc_stat = *statp = EX_NOHOST; 127115d084d5Seric return (NULL); 1272eea91d78Seric } 127315d084d5Seric 127438ad259dSeric /* found a match -- copy out */ 127500b385a9Seric cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av); 1276eea91d78Seric s->s_namecanon.nc_stat = *statp = EX_OK; 127700b385a9Seric s->s_namecanon.nc_cname = newstr(cp); 127800b385a9Seric return cp; 127999f7cf32Seric } 1280e2f2f828Seric /* 1281e2f2f828Seric ** ANYNET_NTOA -- convert a network address to printable form. 1282e2f2f828Seric ** 1283e2f2f828Seric ** Parameters: 1284e2f2f828Seric ** sap -- a pointer to a sockaddr structure. 1285e2f2f828Seric ** 1286e2f2f828Seric ** Returns: 1287e2f2f828Seric ** A printable version of that sockaddr. 1288e2f2f828Seric */ 1289e2f2f828Seric 1290e2f2f828Seric char * 1291e2f2f828Seric anynet_ntoa(sap) 1292e2f2f828Seric register SOCKADDR *sap; 1293e2f2f828Seric { 1294e2f2f828Seric register char *bp; 1295e2f2f828Seric register char *ap; 1296e2f2f828Seric int l; 1297e387851eSeric static char buf[100]; 1298e2f2f828Seric 12998cb4653dSeric /* check for null/zero family */ 13008cb4653dSeric if (sap == NULL) 13018cb4653dSeric return "NULLADDR"; 13028cb4653dSeric if (sap->sa.sa_family == 0) 13038cb4653dSeric return "0"; 13048cb4653dSeric 1305e387851eSeric switch (sap->sa.sa_family) 1306e387851eSeric { 1307e387851eSeric #ifdef MAYBENEXTRELEASE /*** UNTESTED *** UNTESTED *** UNTESTED ***/ 1308139b52c8Seric #ifdef NETUNIX 1309e387851eSeric case AF_UNIX: 1310c24cf5a4Seric if (sap->sunix.sun_path[0] != '\0') 1311c24cf5a4Seric sprintf(buf, "[UNIX: %.64s]", sap->sunix.sun_path); 1312e387851eSeric else 1313e387851eSeric sprintf(buf, "[UNIX: localhost]"); 1314e387851eSeric return buf; 1315e387851eSeric #endif 1316139b52c8Seric #endif 1317e387851eSeric 131883c1f4bcSeric #ifdef NETINET 1319e387851eSeric case AF_INET: 1320e2f2f828Seric return inet_ntoa(((struct sockaddr_in *) sap)->sin_addr); 132183c1f4bcSeric #endif 1322e2f2f828Seric 1323e387851eSeric default: 1324e387851eSeric /* this case is only to ensure syntactic correctness */ 1325e387851eSeric break; 1326e387851eSeric } 1327e387851eSeric 1328e2f2f828Seric /* unknown family -- just dump bytes */ 132983c1f4bcSeric (void) sprintf(buf, "Family %d: ", sap->sa.sa_family); 1330e2f2f828Seric bp = &buf[strlen(buf)]; 133183c1f4bcSeric ap = sap->sa.sa_data; 133283c1f4bcSeric for (l = sizeof sap->sa.sa_data; --l >= 0; ) 1333e2f2f828Seric { 1334e2f2f828Seric (void) sprintf(bp, "%02x:", *ap++ & 0377); 1335e2f2f828Seric bp += 3; 1336e2f2f828Seric } 1337e2f2f828Seric *--bp = '\0'; 1338e2f2f828Seric return buf; 1339e2f2f828Seric } 13409f8b0eadSeric /* 13419f8b0eadSeric ** HOSTNAMEBYANYADDR -- return name of host based on address 13429f8b0eadSeric ** 13439f8b0eadSeric ** Parameters: 13449f8b0eadSeric ** sap -- SOCKADDR pointer 13459f8b0eadSeric ** 13469f8b0eadSeric ** Returns: 13479f8b0eadSeric ** text representation of host name. 13489f8b0eadSeric ** 13499f8b0eadSeric ** Side Effects: 13509f8b0eadSeric ** none. 13519f8b0eadSeric */ 13529f8b0eadSeric 13539f8b0eadSeric char * 13549f8b0eadSeric hostnamebyanyaddr(sap) 13559f8b0eadSeric register SOCKADDR *sap; 13569f8b0eadSeric { 13579f8b0eadSeric register struct hostent *hp; 13583490b9dfSeric int saveretry; 13593490b9dfSeric 13609d4a8008Seric #if NAMED_BIND 13613490b9dfSeric /* shorten name server timeout to avoid higher level timeouts */ 13623490b9dfSeric saveretry = _res.retry; 13633490b9dfSeric _res.retry = 3; 13643490b9dfSeric #endif /* NAMED_BIND */ 13653490b9dfSeric 13669f8b0eadSeric switch (sap->sa.sa_family) 13679f8b0eadSeric { 13689f8b0eadSeric #ifdef NETINET 13699f8b0eadSeric case AF_INET: 13709f8b0eadSeric hp = gethostbyaddr((char *) &sap->sin.sin_addr, 13719f8b0eadSeric sizeof sap->sin.sin_addr, 13729f8b0eadSeric AF_INET); 13739f8b0eadSeric break; 13749f8b0eadSeric #endif 13759f8b0eadSeric 13769f8b0eadSeric #ifdef NETISO 13779f8b0eadSeric case AF_ISO: 13789f8b0eadSeric hp = gethostbyaddr((char *) &sap->siso.siso_addr, 13799f8b0eadSeric sizeof sap->siso.siso_addr, 13809f8b0eadSeric AF_ISO); 13819f8b0eadSeric break; 13829f8b0eadSeric #endif 13839f8b0eadSeric 1384e387851eSeric #ifdef MAYBENEXTRELEASE /*** UNTESTED *** UNTESTED *** UNTESTED ***/ 1385e387851eSeric case AF_UNIX: 1386e387851eSeric hp = NULL; 1387e387851eSeric break; 1388e387851eSeric #endif 1389e387851eSeric 13909f8b0eadSeric default: 13919f8b0eadSeric hp = gethostbyaddr(sap->sa.sa_data, 13929f8b0eadSeric sizeof sap->sa.sa_data, 13939f8b0eadSeric sap->sa.sa_family); 13949f8b0eadSeric break; 13959f8b0eadSeric } 13969f8b0eadSeric 13979d4a8008Seric #if NAMED_BIND 13983490b9dfSeric _res.retry = saveretry; 13993490b9dfSeric #endif /* NAMED_BIND */ 14003490b9dfSeric 14019f8b0eadSeric if (hp != NULL) 14029f8b0eadSeric return hp->h_name; 14039f8b0eadSeric else 14049f8b0eadSeric { 14059f8b0eadSeric /* produce a dotted quad */ 14069f8b0eadSeric static char buf[512]; 14079f8b0eadSeric 14089f8b0eadSeric (void) sprintf(buf, "[%s]", anynet_ntoa(sap)); 14099f8b0eadSeric return buf; 14109f8b0eadSeric } 14119f8b0eadSeric } 1412f36ede03Sbostic 14136c2c3107Seric # else /* DAEMON */ 141499f7cf32Seric /* code for systems without sophisticated networking */ 1415444eaf03Seric 1416444eaf03Seric /* 1417444eaf03Seric ** MYHOSTNAME -- stub version for case of no daemon code. 141821e9914dSeric ** 141921e9914dSeric ** Can't convert to upper case here because might be a UUCP name. 1420897f1869Seric ** 1421897f1869Seric ** Mark, you can change this to be anything you want...... 1422444eaf03Seric */ 1423444eaf03Seric 1424444eaf03Seric char ** 1425897f1869Seric myhostname(hostbuf, size) 1426444eaf03Seric char hostbuf[]; 1427897f1869Seric int size; 1428444eaf03Seric { 1429444eaf03Seric register FILE *f; 1430444eaf03Seric 1431444eaf03Seric hostbuf[0] = '\0'; 1432444eaf03Seric f = fopen("/usr/include/whoami", "r"); 1433444eaf03Seric if (f != NULL) 1434444eaf03Seric { 1435897f1869Seric (void) fgets(hostbuf, size, f); 1436444eaf03Seric fixcrlf(hostbuf, TRUE); 1437444eaf03Seric (void) fclose(f); 1438444eaf03Seric } 1439444eaf03Seric return (NULL); 1440444eaf03Seric } 144199f7cf32Seric /* 14429f8b0eadSeric ** GETAUTHINFO -- get the real host name asociated with a file descriptor 1443320e0d1cSeric ** 1444320e0d1cSeric ** Parameters: 1445320e0d1cSeric ** fd -- the descriptor 1446320e0d1cSeric ** 1447320e0d1cSeric ** Returns: 1448320e0d1cSeric ** The host name associated with this descriptor, if it can 1449320e0d1cSeric ** be determined. 1450320e0d1cSeric ** NULL otherwise. 1451320e0d1cSeric ** 1452320e0d1cSeric ** Side Effects: 1453320e0d1cSeric ** none 1454320e0d1cSeric */ 1455320e0d1cSeric 1456320e0d1cSeric char * 14579f8b0eadSeric getauthinfo(fd) 1458320e0d1cSeric int fd; 1459320e0d1cSeric { 1460320e0d1cSeric return NULL; 1461320e0d1cSeric } 1462320e0d1cSeric /* 146399f7cf32Seric ** MAPHOSTNAME -- turn a hostname into canonical form 146499f7cf32Seric ** 146599f7cf32Seric ** Parameters: 146605b57da8Seric ** map -- a pointer to the database map. 146708de856eSeric ** name -- a buffer containing a hostname. 146815d084d5Seric ** avp -- a pointer to a (cf file defined) argument vector. 14692d29d43aSeric ** statp -- an exit status (out parameter). 147099f7cf32Seric ** 147199f7cf32Seric ** Returns: 147215d084d5Seric ** mapped host name 1473cb452edcSeric ** FALSE otherwise. 147499f7cf32Seric ** 147599f7cf32Seric ** Side Effects: 147608de856eSeric ** Looks up the host specified in name. If it is not 147799f7cf32Seric ** the canonical name for that host, replace it with 147899f7cf32Seric ** the canonical name. If the name is unknown, or it 147999f7cf32Seric ** is already the canonical name, leave it unchanged. 148099f7cf32Seric */ 148199f7cf32Seric 148299f7cf32Seric /*ARGSUSED*/ 148315d084d5Seric char * 148408de856eSeric host_map_lookup(map, name, avp, statp) 148505b57da8Seric MAP *map; 148608de856eSeric char *name; 148715d084d5Seric char **avp; 14882d29d43aSeric char *statp; 148999f7cf32Seric { 14902d29d43aSeric register struct hostent *hp; 14912d29d43aSeric 149208de856eSeric hp = gethostbyname(name); 14932d29d43aSeric if (hp != NULL) 14942d29d43aSeric return hp->h_name; 14952d29d43aSeric *statp = EX_NOHOST; 149615d084d5Seric return NULL; 149799f7cf32Seric } 149899f7cf32Seric 14996c2c3107Seric #endif /* DAEMON */ 1500