source: trunk/third/sendmail/src/daemon.c @ 12554

Revision 12554, 44.9 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12553, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
3 * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
4 * Copyright (c) 1988, 1993
5 *      The Regents of the University of California.  All rights reserved.
6 *
7 * By using this file, you agree to the terms and conditions set
8 * forth in the LICENSE file which can be found at the top level of
9 * the sendmail distribution.
10 *
11 */
12
13#include <errno.h>
14#include "sendmail.h"
15
16#ifndef lint
17#ifdef DAEMON
18static char sccsid[] = "@(#)daemon.c    8.236 (Berkeley) 1/25/1999 (with daemon mode)";
19#else
20static char sccsid[] = "@(#)daemon.c    8.236 (Berkeley) 1/25/1999 (without daemon mode)";
21#endif
22#endif /* not lint */
23
24#if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__)
25# define USE_SOCK_STREAM        1
26#endif
27
28#if DAEMON || defined(USE_SOCK_STREAM)
29# include <arpa/inet.h>
30# if NAMED_BIND
31#  include <resolv.h>
32#  ifndef NO_DATA
33#   define NO_DATA      NO_ADDRESS
34#  endif
35# endif
36#endif
37
38#if DAEMON
39
40# include <sys/time.h>
41
42# if IP_SRCROUTE
43#  include <netinet/in_systm.h>
44#  include <netinet/ip.h>
45#  include <netinet/ip_var.h>
46# endif
47
48/*
49**  DAEMON.C -- routines to use when running as a daemon.
50**
51**      This entire file is highly dependent on the 4.2 BSD
52**      interprocess communication primitives.  No attempt has
53**      been made to make this file portable to Version 7,
54**      Version 6, MPX files, etc.  If you should try such a
55**      thing yourself, I recommend chucking the entire file
56**      and starting from scratch.  Basic semantics are:
57**
58**      getrequests(e)
59**              Opens a port and initiates a connection.
60**              Returns in a child.  Must set InChannel and
61**              OutChannel appropriately.
62**      clrdaemon()
63**              Close any open files associated with getting
64**              the connection; this is used when running the queue,
65**              etc., to avoid having extra file descriptors during
66**              the queue run and to avoid confusing the network
67**              code (if it cares).
68**      makeconnection(host, port, outfile, infile, e)
69**              Make a connection to the named host on the given
70**              port.  Set *outfile and *infile to the files
71**              appropriate for communication.  Returns zero on
72**              success, else an exit status describing the
73**              error.
74**      host_map_lookup(map, hbuf, avp, pstat)
75**              Convert the entry in hbuf into a canonical form.
76*/
77/*
78**  GETREQUESTS -- open mail IPC port and get requests.
79**
80**      Parameters:
81**              e -- the current envelope.
82**
83**      Returns:
84**              none.
85**
86**      Side Effects:
87**              Waits until some interesting activity occurs.  When
88**              it does, a child is created to process it, and the
89**              parent waits for completion.  Return from this
90**              routine is always in the child.  The file pointers
91**              "InChannel" and "OutChannel" should be set to point
92**              to the communication channel.
93*/
94
95int             DaemonSocket    = -1;           /* fd describing socket */
96SOCKADDR        DaemonAddr;                     /* socket for incoming */
97int             ListenQueueSize = 10;           /* size of listen queue */
98int             TcpRcvBufferSize = 0;           /* size of TCP receive buffer */
99int             TcpSndBufferSize = 0;           /* size of TCP send buffer */
100
101void
102getrequests(e)
103        ENVELOPE *e;
104{
105        int t;
106        time_t refuse_connections_until = 0;
107        bool firsttime = TRUE;
108        FILE *pidf;
109        int sff;
110        int socksize;
111        u_short port;
112#if XDEBUG
113        bool j_has_dot;
114#endif
115        char status[MAXLINE];
116        extern void reapchild __P((int));
117#ifdef NETUNIX
118        extern int ControlSocket;
119#endif
120        extern int opendaemonsocket __P((bool));
121        extern int opencontrolsocket __P((void));
122
123        /*
124        **  Set up the address for the mailer.
125        */
126
127        switch (DaemonAddr.sa.sa_family)
128        {
129          case AF_UNSPEC:
130                DaemonAddr.sa.sa_family = AF_INET;
131                /* fall through ... */
132
133          case AF_INET:
134                if (DaemonAddr.sin.sin_addr.s_addr == 0)
135                        DaemonAddr.sin.sin_addr.s_addr = INADDR_ANY;
136                port = DaemonAddr.sin.sin_port;
137                break;
138
139          default:
140                /* unknown protocol */
141                port = 0;
142                break;
143        }
144        if (port == 0)
145        {
146                register struct servent *sp;
147
148                sp = getservbyname("smtp", "tcp");
149                if (sp == NULL)
150                {
151                        syserr("554 service \"smtp\" unknown");
152                        port = htons(25);
153                }
154                else
155                        port = sp->s_port;
156        }
157
158        switch (DaemonAddr.sa.sa_family)
159        {
160          case AF_INET:
161                DaemonAddr.sin.sin_port = port;
162                break;
163
164          default:
165                /* unknown protocol */
166                break;
167        }
168
169        /*
170        **  Try to actually open the connection.
171        */
172
173        if (tTd(15, 1))
174                printf("getrequests: port 0x%x\n", port);
175
176        /* get a socket for the SMTP connection */
177        socksize = opendaemonsocket(TRUE);
178
179        if (opencontrolsocket() < 0)
180                sm_syslog(LOG_WARNING, NOQID,
181                          "daemon could not open control socket %s: %s",
182                          ControlSocketName, errstring(errno));
183
184        (void) setsignal(SIGCHLD, reapchild);
185
186        /* write the pid to the log file for posterity */
187        sff = SFF_NOLINK|SFF_ROOTOK|SFF_REGONLY|SFF_CREAT;
188        if (TrustedUid != 0 && RealUid == TrustedUid)
189                sff |= SFF_OPENASROOT;
190        pidf = safefopen(PidFile, O_WRONLY|O_TRUNC, 0644, sff);
191        if (pidf == NULL)
192        {
193                sm_syslog(LOG_ERR, NOQID, "unable to write %s", PidFile);
194        }
195        else
196        {
197                extern char *CommandLineArgs;
198
199                /* write the process id on line 1 */
200                fprintf(pidf, "%ld\n", (long) getpid());
201
202                /* line 2 contains all command line flags */
203                fprintf(pidf, "%s\n", CommandLineArgs);
204
205                /* flush and close */
206                fclose(pidf);
207        }
208
209#if XDEBUG
210        {
211                char jbuf[MAXHOSTNAMELEN];
212
213                expand("\201j", jbuf, sizeof jbuf, e);
214                j_has_dot = strchr(jbuf, '.') != NULL;
215        }
216#endif
217
218        /* Add parent process as first item */
219        proc_list_add(getpid(), "Sendmail daemon");
220
221        if (tTd(15, 1))
222                printf("getrequests: %d\n", DaemonSocket);
223
224        for (;;)
225        {
226                register pid_t pid;
227                auto SOCKADDR_LEN_T lotherend;
228                bool timedout = FALSE;
229                bool control = FALSE;
230                int savederrno;
231                int pipefd[2];
232                extern bool refuseconnections __P((int));
233
234                /* see if we are rejecting connections */
235                (void) blocksignal(SIGALRM);
236                if (curtime() >= refuse_connections_until)
237                {
238                        if (refuseconnections(ntohs(port)))
239                        {
240                                if (DaemonSocket >= 0)
241                                {
242                                       /* close socket so peer fails quickly */
243                                       (void) close(DaemonSocket);
244                                       DaemonSocket = -1;
245                                }
246
247                                /* refuse connections for next 15 seconds */
248                                refuse_connections_until = curtime() + 15;
249                        }
250                        else if (DaemonSocket < 0 || firsttime)
251                        {
252                              /* arrange to (re)open the socket if needed */
253                              (void) opendaemonsocket(FALSE);
254                              firsttime = FALSE;
255                        }
256                }
257
258#if XDEBUG
259                /* check for disaster */
260                {
261                        char jbuf[MAXHOSTNAMELEN];
262                        extern void dumpstate __P((char *));
263
264                        expand("\201j", jbuf, sizeof jbuf, e);
265                        if (!wordinclass(jbuf, 'w'))
266                        {
267                                dumpstate("daemon lost $j");
268                                sm_syslog(LOG_ALERT, NOQID,
269                                        "daemon process doesn't have $j in $=w; see syslog");
270                                abort();
271                        }
272                        else if (j_has_dot && strchr(jbuf, '.') == NULL)
273                        {
274                                dumpstate("daemon $j lost dot");
275                                sm_syslog(LOG_ALERT, NOQID,
276                                        "daemon process $j lost dot; see syslog");
277                                abort();
278                        }
279                }
280#endif
281
282#if 0
283                /*
284                **  Andrew Sun <asun@ieps-sun.ml.com> claims that this will
285                **  fix the SVr4 problem.  But it seems to have gone away,
286                **  so is it worth doing this?
287                */
288
289                if (DaemonSocket >= 0 &&
290                    SetNonBlocking(DaemonSocket, FALSE) < 0)
291                        log an error here;
292#endif
293                (void) releasesignal(SIGALRM);
294                for (;;)
295                {
296                        int highest = -1;
297                        fd_set readfds;
298                        struct timeval timeout;
299
300                        FD_ZERO(&readfds);
301
302                        /* wait for a connection */
303                        if (DaemonSocket >= 0)
304                        {
305                                sm_setproctitle(TRUE,
306                                                "accepting connections on port %d",
307                                                ntohs(port));
308                                if (DaemonSocket > highest)
309                                        highest = DaemonSocket;
310                                FD_SET(DaemonSocket, &readfds);
311                        }
312#ifdef NETUNIX
313                        if (ControlSocket >= 0)
314                        {
315                                if (ControlSocket > highest)
316                                        highest = ControlSocket;
317                                FD_SET(ControlSocket, &readfds);
318                        }
319#endif
320                        if (DaemonSocket >= 0)
321                                timeout.tv_sec = 60;
322                        else
323                                timeout.tv_sec = 5;
324                        timeout.tv_usec = 0;
325
326                        t = select(highest + 1, FDSET_CAST &readfds,
327                                   NULL, NULL, &timeout);
328
329                        if (DoQueueRun)
330                                (void) runqueue(TRUE, FALSE);
331                        if (t <= 0)
332                        {
333                                timedout = TRUE;
334                                break;
335                        }
336
337                        control = FALSE;
338                        errno = 0;
339                        if (DaemonSocket >= 0 &&
340                            FD_ISSET(DaemonSocket, &readfds))
341                        {
342                                lotherend = socksize;
343                                t = accept(DaemonSocket,
344                                           (struct sockaddr *)&RealHostAddr,
345                                           &lotherend);
346                        }
347#ifdef NETUNIX
348                        else if (ControlSocket >= 0 &&
349                                 FD_ISSET(ControlSocket, &readfds))
350                        {
351                                struct sockaddr_un sa_un;
352
353                                lotherend = sizeof sa_un;
354                                t = accept(ControlSocket,
355                                           (struct sockaddr *)&sa_un,
356                                           &lotherend);
357                                control = TRUE;
358                        }
359#endif
360                        if (t >= 0 || errno != EINTR)
361                                break;
362                }
363                if (timedout)
364                {
365                        timedout = FALSE;
366                        continue;
367                }
368                if (control)
369                {
370                        if (t >= 0)
371                        {
372                                extern void control_command __P((int, ENVELOPE *));
373
374                                control_command(t, e);
375                        }
376                        else
377                                syserr("getrequests: control accept");
378                        continue;
379                }
380                savederrno = errno;
381                (void) blocksignal(SIGALRM);
382                if (t < 0)
383                {
384                        errno = savederrno;
385                        syserr("getrequests: accept");
386
387                        /* arrange to re-open the socket next time around */
388                        (void) close(DaemonSocket);
389                        DaemonSocket = -1;
390                        continue;
391                }
392
393                /*
394                **  Create a subprocess to process the mail.
395                */
396
397                if (tTd(15, 2))
398                        printf("getrequests: forking (fd = %d)\n", t);
399
400                /*
401                **  Create a pipe to keep the child from writing to the
402                **  socket until after the parent has closed it.  Otherwise
403                **  the parent may hang if the child has closed it first.
404                */
405
406                if (pipe(pipefd) < 0)
407                        pipefd[0] = pipefd[1] = -1;
408
409                blocksignal(SIGCHLD);
410                pid = fork();
411                if (pid < 0)
412                {
413                        syserr("daemon: cannot fork");
414                        if (pipefd[0] != -1)
415                        {
416                                (void) close(pipefd[0]);
417                                (void) close(pipefd[1]);
418                        }
419                        (void) releasesignal(SIGCHLD);
420                        sleep(10);
421                        (void) close(t);
422                        continue;
423                }
424
425                if (pid == 0)
426                {
427                        char *p;
428                        extern SIGFUNC_DECL intsig __P((int));
429                        FILE *inchannel, *outchannel;
430
431                        /*
432                        **  CHILD -- return to caller.
433                        **      Collect verified idea of sending host.
434                        **      Verify calling user id if possible here.
435                        */
436
437                        (void) releasesignal(SIGALRM);
438                        (void) releasesignal(SIGCHLD);
439                        (void) setsignal(SIGCHLD, SIG_DFL);
440                        (void) setsignal(SIGHUP, intsig);
441                        (void) close(DaemonSocket);
442                        clrcontrol();
443                        proc_list_clear();
444
445                        /* Add parent process as first child item */
446                        proc_list_add(getpid(), "daemon child");
447
448                        /* don't schedule queue runs if we are told to ETRN */
449                        QueueIntvl = 0;
450
451                        sm_setproctitle(TRUE, "startup with %s",
452                                anynet_ntoa(&RealHostAddr));
453
454                        if (pipefd[0] != -1)
455                        {
456                                auto char c;
457
458                                /*
459                                **  Wait for the parent to close the write end
460                                **  of the pipe, which we will see as an EOF.
461                                **  This guarantees that we won't write to the
462                                **  socket until after the parent has closed
463                                **  the pipe.
464                                */
465
466                                /* close the write end of the pipe */
467                                (void) close(pipefd[1]);
468
469                                /* we shouldn't be interrupted, but ... */
470                                while (read(pipefd[0], &c, 1) < 0 &&
471                                       errno == EINTR)
472                                        continue;
473                                (void) close(pipefd[0]);
474                        }
475
476                        /* determine host name */
477                        p = hostnamebyanyaddr(&RealHostAddr);
478                        if (strlen(p) > (SIZE_T) MAXNAME)
479                                p[MAXNAME] = '\0';
480                        RealHostName = newstr(p);
481                        sm_setproctitle(TRUE, "startup with %s", p);
482
483                        if ((inchannel = fdopen(t, "r")) == NULL ||
484                            (t = dup(t)) < 0 ||
485                            (outchannel = fdopen(t, "w")) == NULL)
486                        {
487                                syserr("cannot open SMTP server channel, fd=%d", t);
488                                finis(FALSE, EX_OK);
489                        }
490
491                        InChannel = inchannel;
492                        OutChannel = outchannel;
493                        DisConnected = FALSE;
494
495#ifdef XLA
496                        if (!xla_host_ok(RealHostName))
497                        {
498                                message("421 Too many SMTP sessions for this host");
499                                finis(FALSE, EX_OK);
500                        }
501#endif
502                        break;
503                }
504
505                /* parent -- keep track of children */
506                snprintf(status, sizeof status, "SMTP server child for %s",
507                         anynet_ntoa(&RealHostAddr));
508                proc_list_add(pid, status);
509                (void) releasesignal(SIGCHLD);
510
511                /* close the read end of the synchronization pipe */
512                if (pipefd[0] != -1)
513                        (void) close(pipefd[0]);
514
515                /* close the port so that others will hang (for a while) */
516                (void) close(t);
517
518                /* release the child by closing the read end of the sync pipe */
519                if (pipefd[1] != -1)
520                        (void) close(pipefd[1]);
521        }
522        if (tTd(15, 2))
523                printf("getreq: returning\n");
524        return;
525}
526/*
527**  OPENDAEMONSOCKET -- open the SMTP socket
528**
529**      Deals with setting all appropriate options.  DaemonAddr must
530**      be set up in advance.
531**
532**      Parameters:
533**              firsttime -- set if this is the initial open.
534**
535**      Returns:
536**              Size in bytes of the daemon socket addr.
537**
538**      Side Effects:
539**              Leaves DaemonSocket set to the open socket.
540**              Exits if the socket cannot be created.
541*/
542
543#define MAXOPENTRIES    10      /* maximum number of tries to open connection */
544
545int
546opendaemonsocket(firsttime)
547        bool firsttime;
548{
549        int on = 1;
550        int socksize = 0;
551        int ntries = 0;
552        int saveerrno;
553
554        if (tTd(15, 2))
555                printf("opendaemonsocket()\n");
556
557        do
558        {
559                if (ntries > 0)
560                        sleep(5);
561                if (firsttime || DaemonSocket < 0)
562                {
563                        DaemonSocket = socket(DaemonAddr.sa.sa_family, SOCK_STREAM, 0);
564                        if (DaemonSocket < 0)
565                        {
566                                saveerrno = errno;
567                                syserr("opendaemonsocket: can't create server SMTP socket");
568                          severe:
569                                if (LogLevel > 0)
570                                        sm_syslog(LOG_ALERT, NOQID,
571                                                "problem creating SMTP socket");
572                                DaemonSocket = -1;
573                                continue;
574                        }
575
576                        /* turn on network debugging? */
577                        if (tTd(15, 101))
578                                (void) setsockopt(DaemonSocket, SOL_SOCKET,
579                                                  SO_DEBUG, (char *)&on,
580                                                  sizeof on);
581
582                        (void) setsockopt(DaemonSocket, SOL_SOCKET,
583                                          SO_REUSEADDR, (char *)&on, sizeof on);
584                        (void) setsockopt(DaemonSocket, SOL_SOCKET,
585                                          SO_KEEPALIVE, (char *)&on, sizeof on);
586
587#ifdef SO_RCVBUF
588                        if (TcpRcvBufferSize > 0)
589                        {
590                                if (setsockopt(DaemonSocket, SOL_SOCKET,
591                                               SO_RCVBUF,
592                                               (char *) &TcpRcvBufferSize,
593                                               sizeof(TcpRcvBufferSize)) < 0)
594                                        syserr("opendaemonsocket: setsockopt(SO_RCVBUF)");
595                        }
596#endif
597
598                        switch (DaemonAddr.sa.sa_family)
599                        {
600# if NETINET
601                          case AF_INET:
602                                socksize = sizeof DaemonAddr.sin;
603                                break;
604# endif
605
606# if NETISO
607                          case AF_ISO:
608                                socksize = sizeof DaemonAddr.siso;
609                                break;
610# endif
611
612                          default:
613                                socksize = sizeof DaemonAddr;
614                                break;
615                        }
616
617                        if (bind(DaemonSocket, &DaemonAddr.sa, socksize) < 0)
618                        {
619                                /* probably another daemon already */
620                                saveerrno = errno;
621                                syserr("opendaemonsocket: cannot bind");
622                                (void) close(DaemonSocket);
623                                goto severe;
624                        }
625                }
626                if (!firsttime && listen(DaemonSocket, ListenQueueSize) < 0)
627                {
628                        saveerrno = errno;
629                        syserr("opendaemonsocket: cannot listen");
630                        (void) close(DaemonSocket);
631                        goto severe;
632                }
633                return socksize;
634        } while (ntries++ < MAXOPENTRIES && transienterror(saveerrno));
635        syserr("!opendaemonsocket: server SMTP socket wedged: exiting");
636        /*NOTREACHED*/
637        return -1;  /* avoid compiler warning on IRIX */
638}
639/*
640**  CLRDAEMON -- reset the daemon connection
641**
642**      Parameters:
643**              none.
644**
645**      Returns:
646**              none.
647**
648**      Side Effects:
649**              releases any resources used by the passive daemon.
650*/
651
652void
653clrdaemon()
654{
655        if (DaemonSocket >= 0)
656                (void) close(DaemonSocket);
657        DaemonSocket = -1;
658}
659/*
660**  SETDAEMONOPTIONS -- set options for running the daemon
661**
662**      Parameters:
663**              p -- the options line.
664**
665**      Returns:
666**              none.
667*/
668
669void
670setdaemonoptions(p)
671        register char *p;
672{
673        if (DaemonAddr.sa.sa_family == AF_UNSPEC)
674                DaemonAddr.sa.sa_family = AF_INET;
675
676        while (p != NULL)
677        {
678                register char *f;
679                register char *v;
680
681                while (isascii(*p) && isspace(*p))
682                        p++;
683                if (*p == '\0')
684                        break;
685                f = p;
686                p = strchr(p, ',');
687                if (p != NULL)
688                        *p++ = '\0';
689                v = strchr(f, '=');
690                if (v == NULL)
691                        continue;
692                while (isascii(*++v) && isspace(*v))
693                        continue;
694                if (isascii(*f) && islower(*f))
695                        *f = toupper(*f);
696
697                switch (*f)
698                {
699                  case 'F':             /* address family */
700                        if (isascii(*v) && isdigit(*v))
701                                DaemonAddr.sa.sa_family = atoi(v);
702#if NETINET
703                        else if (strcasecmp(v, "inet") == 0)
704                                DaemonAddr.sa.sa_family = AF_INET;
705#endif
706#if NETISO
707                        else if (strcasecmp(v, "iso") == 0)
708                                DaemonAddr.sa.sa_family = AF_ISO;
709#endif
710#if NETNS
711                        else if (strcasecmp(v, "ns") == 0)
712                                DaemonAddr.sa.sa_family = AF_NS;
713#endif
714#if NETX25
715                        else if (strcasecmp(v, "x.25") == 0)
716                                DaemonAddr.sa.sa_family = AF_CCITT;
717#endif
718                        else
719                                syserr("554 Unknown address family %s in Family=option", v);
720                        break;
721
722                  case 'A':             /* address */
723                        switch (DaemonAddr.sa.sa_family)
724                        {
725#if NETINET
726                          case AF_INET:
727                                if (isascii(*v) && isdigit(*v))
728                                        DaemonAddr.sin.sin_addr.s_addr = inet_addr(v);
729                                else
730                                {
731                                        register struct hostent *hp;
732
733                                        hp = sm_gethostbyname(v);
734                                        if (hp == NULL)
735                                                syserr("554 host \"%s\" unknown", v);
736                                        else
737                                                bcopy(hp->h_addr, &DaemonAddr.sin.sin_addr, INADDRSZ);
738                                }
739                                break;
740#endif
741
742                          default:
743                                syserr("554 Address= option unsupported for family %d",
744                                        DaemonAddr.sa.sa_family);
745                                break;
746                        }
747                        break;
748
749                  case 'P':             /* port */
750                        switch (DaemonAddr.sa.sa_family)
751                        {
752#if NETISO
753                                short port;
754#endif
755
756#if NETINET
757                          case AF_INET:
758                                if (isascii(*v) && isdigit(*v))
759                                        DaemonAddr.sin.sin_port = htons(atoi(v));
760                                else
761                                {
762                                        register struct servent *sp;
763
764                                        sp = getservbyname(v, "tcp");
765                                        if (sp == NULL)
766                                                syserr("554 service \"%s\" unknown", v);
767                                        else
768                                                DaemonAddr.sin.sin_port = sp->s_port;
769                                }
770                                break;
771#endif
772
773#if NETISO
774                          case AF_ISO:
775                                /* assume two byte transport selector */
776                                if (isascii(*v) && isdigit(*v))
777                                        port = htons(atoi(v));
778                                else
779                                {
780                                        register struct servent *sp;
781
782                                        sp = getservbyname(v, "tcp");
783                                        if (sp == NULL)
784                                                syserr("554 service \"%s\" unknown", v);
785                                        else
786                                                port = sp->s_port;
787                                }
788                                bcopy((char *) &port, TSEL(&DaemonAddr.siso), 2);
789                                break;
790#endif
791
792                          default:
793                                syserr("554 Port= option unsupported for family %d",
794                                        DaemonAddr.sa.sa_family);
795                                break;
796                        }
797                        break;
798
799                  case 'L':             /* listen queue size */
800                        ListenQueueSize = atoi(v);
801                        break;
802
803                  case 'S':             /* send buffer size */
804                        TcpSndBufferSize = atoi(v);
805                        break;
806
807                  case 'R':             /* receive buffer size */
808                        TcpRcvBufferSize = atoi(v);
809                        break;
810
811                  default:
812                        syserr("554 DaemonPortOptions parameter \"%s\" unknown", f);
813                }
814        }
815}
816/*
817**  MAKECONNECTION -- make a connection to an SMTP socket on another machine.
818**
819**      Parameters:
820**              host -- the name of the host.
821**              port -- the port number to connect to.
822**              mci -- a pointer to the mail connection information
823**                      structure to be filled in.
824**              e -- the current envelope.
825**
826**      Returns:
827**              An exit code telling whether the connection could be
828**                      made and if not why not.
829**
830**      Side Effects:
831**              none.
832*/
833
834static jmp_buf  CtxConnectTimeout;
835
836static void
837connecttimeout()
838{
839        errno = ETIMEDOUT;
840        longjmp(CtxConnectTimeout, 1);
841}
842
843SOCKADDR        CurHostAddr;            /* address of current host */
844
845int
846makeconnection(host, port, mci, e)
847        char *host;
848        u_short port;
849        register MCI *mci;
850        ENVELOPE *e;
851{
852        register volatile int addrno = 0;
853        register volatile int s;
854        register struct hostent *volatile hp = (struct hostent *)NULL;
855        SOCKADDR addr;
856        int sav_errno;
857        volatile int addrlen;
858        volatile bool firstconnect;
859        EVENT *volatile ev = NULL;
860
861        /*
862        **  Set up the address for the mailer.
863        **      Accept "[a.b.c.d]" syntax for host name.
864        */
865
866#if NAMED_BIND
867        h_errno = 0;
868#endif
869        errno = 0;
870        bzero(&CurHostAddr, sizeof CurHostAddr);
871        SmtpPhase = mci->mci_phase = "initial connection";
872        CurHostName = host;
873
874        if (host[0] == '[')
875        {
876#if NETINET
877                unsigned long hid = INADDR_NONE;
878#endif
879                register char *p = strchr(host, ']');
880
881                if (p != NULL)
882                {
883                        *p = '\0';
884#if NETINET
885                        hid = inet_addr(&host[1]);
886                        if (hid == INADDR_NONE)
887#endif
888                        {
889                                /* try it as a host name (avoid MX lookup) */
890                                hp = sm_gethostbyname(&host[1]);
891                                if (hp == NULL && p[-1] == '.')
892                                {
893#if NAMED_BIND
894                                        int oldopts = _res.options;
895
896                                        _res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
897#endif
898                                        p[-1] = '\0';
899                                        hp = sm_gethostbyname(&host[1]);
900                                        p[-1] = '.';
901#if NAMED_BIND
902                                        _res.options = oldopts;
903#endif
904                                }
905                                *p = ']';
906                                goto gothostent;
907                        }
908                        *p = ']';
909                }
910                if (p == NULL)
911                {
912                        extern char MsgBuf[];
913
914                        usrerr("553 Invalid numeric domain spec \"%s\"", host);
915                        mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf);
916                        return EX_NOHOST;
917                }
918#if NETINET
919                addr.sin.sin_family = AF_INET;          /*XXX*/
920                addr.sin.sin_addr.s_addr = hid;
921#endif
922        }
923        else
924        {
925                /* contortion to get around SGI cc complaints */
926                {
927                        register char *p = &host[strlen(host) - 1];
928
929                        hp = sm_gethostbyname(host);
930                        if (hp == NULL && *p == '.')
931                        {
932#if NAMED_BIND
933                                int oldopts = _res.options;
934
935                                _res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
936#endif
937                                *p = '\0';
938                                hp = sm_gethostbyname(host);
939                                *p = '.';
940#if NAMED_BIND
941                                _res.options = oldopts;
942#endif
943                        }
944                }
945gothostent:
946                if (hp == NULL)
947                {
948#if NAMED_BIND
949                        /* check for name server timeouts */
950                        if (errno == ETIMEDOUT || h_errno == TRY_AGAIN ||
951                            (errno == ECONNREFUSED && UseNameServer))
952                        {
953                                mci_setstat(mci, EX_TEMPFAIL, "4.4.3", NULL);
954                                return EX_TEMPFAIL;
955                        }
956#endif
957                        mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
958                        return (EX_NOHOST);
959                }
960                addr.sa.sa_family = hp->h_addrtype;
961                switch (hp->h_addrtype)
962                {
963#if NETINET
964                  case AF_INET:
965                        bcopy(hp->h_addr,
966                                &addr.sin.sin_addr,
967                                INADDRSZ);
968                        break;
969#endif
970
971                  default:
972                        if (hp->h_length > sizeof addr.sa.sa_data)
973                        {
974                                syserr("makeconnection: long sa_data: family %d len %d",
975                                        hp->h_addrtype, hp->h_length);
976                                mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
977                                return EX_NOHOST;
978                        }
979                        bcopy(hp->h_addr,
980                                addr.sa.sa_data,
981                                hp->h_length);
982                        break;
983                }
984                addrno = 1;
985        }
986
987        /*
988        **  Determine the port number.
989        */
990
991        if (port == 0)
992        {
993                register struct servent *sp = getservbyname("smtp", "tcp");
994
995                if (sp == NULL)
996                {
997                        if (LogLevel > 2)
998                                sm_syslog(LOG_ERR, NOQID,
999                                        "makeconnection: service \"smtp\" unknown");
1000                        port = htons(25);
1001                }
1002                else
1003                        port = sp->s_port;
1004        }
1005
1006        switch (addr.sa.sa_family)
1007        {
1008#if NETINET
1009          case AF_INET:
1010                addr.sin.sin_port = port;
1011                addrlen = sizeof (struct sockaddr_in);
1012                break;
1013#endif
1014
1015#if NETISO
1016          case AF_ISO:
1017                /* assume two byte transport selector */
1018                bcopy((char *) &port, TSEL((struct sockaddr_iso *) &addr), 2);
1019                addrlen = sizeof (struct sockaddr_iso);
1020                break;
1021#endif
1022
1023          default:
1024                syserr("Can't connect to address family %d", addr.sa.sa_family);
1025                mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
1026                return (EX_NOHOST);
1027        }
1028
1029        /*
1030        **  Try to actually open the connection.
1031        */
1032
1033#ifdef XLA
1034        /* if too many connections, don't bother trying */
1035        if (!xla_noqueue_ok(host))
1036                return EX_TEMPFAIL;
1037#endif
1038
1039        firstconnect = TRUE;
1040        for (;;)
1041        {
1042                if (tTd(16, 1))
1043                        printf("makeconnection (%s [%s])\n",
1044                                host, anynet_ntoa(&addr));
1045
1046                /* save for logging */
1047                CurHostAddr = addr;
1048
1049                if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags))
1050                {
1051                        int rport = IPPORT_RESERVED - 1;
1052
1053                        s = rresvport(&rport);
1054                }
1055                else
1056                {
1057                        s = socket(addr.sa.sa_family, SOCK_STREAM, 0);
1058                }
1059                if (s < 0)
1060                {
1061                        sav_errno = errno;
1062                        syserr("makeconnection: cannot create socket");
1063#ifdef XLA
1064                        xla_host_end(host);
1065#endif
1066                        mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
1067                        return EX_TEMPFAIL;
1068                }
1069
1070#ifdef SO_SNDBUF
1071                if (TcpSndBufferSize > 0)
1072                {
1073                        if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
1074                                       (char *) &TcpSndBufferSize,
1075                                       sizeof(TcpSndBufferSize)) < 0)
1076                                syserr("makeconnection: setsockopt(SO_SNDBUF)");
1077                }
1078#endif
1079
1080                if (tTd(16, 1))
1081                        printf("makeconnection: fd=%d\n", s);
1082
1083                /* turn on network debugging? */
1084                if (tTd(16, 101))
1085                {
1086                        int on = 1;
1087                        (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
1088                                          (char *)&on, sizeof on);
1089                }
1090                if (e->e_xfp != NULL)
1091                        (void) fflush(e->e_xfp);                /* for debugging */
1092                errno = 0;                                      /* for debugging */
1093
1094                /*
1095                **  Linux seems to hang in connect for 90 minutes (!!!).
1096                **  Time out the connect to avoid this problem.
1097                */
1098
1099                if (setjmp(CtxConnectTimeout) == 0)
1100                {
1101                        int i;
1102
1103                        if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0)
1104                                ev = setevent(TimeOuts.to_iconnect, connecttimeout, 0);
1105                        else if (TimeOuts.to_connect != 0)
1106                                ev = setevent(TimeOuts.to_connect, connecttimeout, 0);
1107                        else
1108                                ev = NULL;
1109
1110#if _FFR_CONNECTONLYTO_OPTION
1111                        /* for testing */
1112                        if (ConnectOnlyTo != 0)
1113                                addr.sin.sin_addr.s_addr = ConnectOnlyTo;
1114#endif
1115                        i = connect(s, (struct sockaddr *) &addr, addrlen);
1116                        sav_errno = errno;
1117                        if (ev != NULL)
1118                                clrevent(ev);
1119                        if (i >= 0)
1120                                break;
1121                }
1122                else
1123                        sav_errno = errno;
1124
1125                /* if running demand-dialed connection, try again */
1126                if (DialDelay > 0 && firstconnect)
1127                {
1128                        if (tTd(16, 1))
1129                                printf("Connect failed (%s); trying again...\n",
1130                                        errstring(sav_errno));
1131                        firstconnect = FALSE;
1132                        sleep(DialDelay);
1133                        continue;
1134                }
1135
1136                /* couldn't connect.... figure out why */
1137                (void) close(s);
1138
1139                if (LogLevel >= 14)
1140                        sm_syslog(LOG_INFO, e->e_id,
1141                                  "makeconnection (%s [%s]) failed: %s",
1142                                  host, anynet_ntoa(&addr),
1143                                  errstring(sav_errno));
1144
1145                if (hp != NULL && hp->h_addr_list[addrno] != NULL)
1146                {
1147                        if (tTd(16, 1))
1148                                printf("Connect failed (%s); trying new address....\n",
1149                                        errstring(sav_errno));
1150                        switch (addr.sa.sa_family)
1151                        {
1152#if NETINET
1153                          case AF_INET:
1154                                bcopy(hp->h_addr_list[addrno++],
1155                                      &addr.sin.sin_addr,
1156                                      INADDRSZ);
1157                                break;
1158#endif
1159
1160                          default:
1161                                bcopy(hp->h_addr_list[addrno++],
1162                                        addr.sa.sa_data,
1163                                        hp->h_length);
1164                                break;
1165                        }
1166                        continue;
1167                }
1168
1169                /* couldn't open connection */
1170#ifdef XLA
1171                xla_host_end(host);
1172#endif
1173                mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL);
1174                return EX_TEMPFAIL;
1175        }
1176
1177        /* connection ok, put it into canonical form */
1178        if ((mci->mci_out = fdopen(s, "w")) == NULL ||
1179            (s = dup(s)) < 0 ||
1180            (mci->mci_in = fdopen(s, "r")) == NULL)
1181        {
1182                syserr("cannot open SMTP client channel, fd=%d", s);
1183                mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
1184                return EX_TEMPFAIL;
1185        }
1186
1187        mci_setstat(mci, EX_OK, NULL, NULL);
1188        return (EX_OK);
1189}
1190/*
1191**  MYHOSTNAME -- return the name of this host.
1192**
1193**      Parameters:
1194**              hostbuf -- a place to return the name of this host.
1195**              size -- the size of hostbuf.
1196**
1197**      Returns:
1198**              A list of aliases for this host.
1199**
1200**      Side Effects:
1201**              Adds numeric codes to $=w.
1202*/
1203
1204struct hostent *
1205myhostname(hostbuf, size)
1206        char hostbuf[];
1207        int size;
1208{
1209        register struct hostent *hp;
1210
1211        if (gethostname(hostbuf, size) < 0)
1212        {
1213                (void) strcpy(hostbuf, "localhost");
1214        }
1215        hp = sm_gethostbyname(hostbuf);
1216        if (hp == NULL)
1217                return NULL;
1218        if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL)
1219        {
1220                (void) strncpy(hostbuf, hp->h_name, size - 1);
1221                hostbuf[size - 1] = '\0';
1222        }
1223
1224        /*
1225        **  If there is still no dot in the name, try looking for a
1226        **  dotted alias.
1227        */
1228
1229        if (strchr(hostbuf, '.') == NULL)
1230        {
1231                char **ha;
1232
1233                for (ha = hp->h_aliases; *ha != NULL; ha++)
1234                {
1235                        if (strchr(*ha, '.') != NULL)
1236                        {
1237                                (void) strncpy(hostbuf, *ha, size - 1);
1238                                hostbuf[size - 1] = '\0';
1239                                break;
1240                        }
1241                }
1242        }
1243
1244        /*
1245        **  If _still_ no dot, wait for a while and try again -- it is
1246        **  possible that some service is starting up.  This can result
1247        **  in excessive delays if the system is badly configured, but
1248        **  there really isn't a way around that, particularly given that
1249        **  the config file hasn't been read at this point.
1250        **  All in all, a bit of a mess.
1251        */
1252
1253        if (strchr(hostbuf, '.') == NULL &&
1254            !getcanonname(hostbuf, size, TRUE))
1255        {
1256                sm_syslog(LOG_CRIT, NOQID,
1257                        "My unqualified host name (%s) unknown; sleeping for retry",
1258                        hostbuf);
1259                message("My unqualified host name (%s) unknown; sleeping for retry",
1260                        hostbuf);
1261                sleep(60);
1262                if (!getcanonname(hostbuf, size, TRUE))
1263                {
1264                        sm_syslog(LOG_ALERT, NOQID,
1265                                "unable to qualify my own domain name (%s) -- using short name",
1266                                hostbuf);
1267                        message("WARNING: unable to qualify my own domain name (%s) -- using short name",
1268                                hostbuf);
1269                }
1270        }
1271        return (hp);
1272}
1273/*
1274**  ADDRCMP -- compare two host addresses
1275**
1276**      Parameters:
1277**              hp -- hostent structure for the first address
1278**              ha -- actual first address
1279**              sa -- second address
1280**
1281**      Returns:
1282**              0 -- if ha and sa match
1283**              else -- they don't match
1284*/
1285
1286int
1287addrcmp(hp, ha, sa)
1288        struct hostent *hp;
1289        char *ha;
1290        SOCKADDR *sa;
1291{
1292        switch (sa->sa.sa_family)
1293        {
1294          case AF_INET:
1295                if (hp->h_addrtype == AF_INET)
1296                        return bcmp(ha, (char *) &sa->sin.sin_addr, hp->h_length);
1297                break;
1298
1299        }
1300        return -1;
1301}
1302/*
1303**  GETAUTHINFO -- get the real host name asociated with a file descriptor
1304**
1305**      Uses RFC1413 protocol to try to get info from the other end.
1306**
1307**      Parameters:
1308**              fd -- the descriptor
1309**              may_be_forged -- an outage that is set to TRUE if the
1310**                      forward lookup of RealHostName does not match
1311**                      RealHostAddr; set to FALSE if they do match.
1312**
1313**      Returns:
1314**              The user@host information associated with this descriptor.
1315*/
1316
1317static jmp_buf  CtxAuthTimeout;
1318
1319static void
1320authtimeout()
1321{
1322        longjmp(CtxAuthTimeout, 1);
1323}
1324
1325char *
1326getauthinfo(fd, may_be_forged)
1327        int fd;
1328        bool *may_be_forged;
1329{
1330        SOCKADDR_LEN_T falen;
1331        register char *volatile p = NULL;
1332        SOCKADDR la;
1333        SOCKADDR_LEN_T lalen;
1334        register struct servent *sp;
1335        volatile int s;
1336        int i = 0;
1337        EVENT *ev;
1338        int nleft;
1339        struct hostent *hp;
1340        char *ostype = NULL;
1341        char **ha;
1342        char ibuf[MAXNAME + 1];
1343        static char hbuf[MAXNAME * 2 + 11];
1344
1345        *may_be_forged = FALSE;
1346        falen = sizeof RealHostAddr;
1347        if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 ||
1348            falen <= 0 || RealHostAddr.sa.sa_family == 0)
1349        {
1350                if (i < 0 && errno != ENOTSOCK)
1351                        return NULL;
1352                (void) snprintf(hbuf, sizeof hbuf, "%s@localhost",
1353                        RealUserName);
1354                if (tTd(9, 1))
1355                        printf("getauthinfo: %s\n", hbuf);
1356                return hbuf;
1357        }
1358
1359        if (RealHostName == NULL)
1360        {
1361                /* translate that to a host name */
1362                RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr));
1363                if (strlen(RealHostName) > MAXNAME)
1364                        RealHostName[MAXNAME] = '\0';
1365        }
1366
1367        /* cross check RealHostName with forward DNS lookup */
1368        if (anynet_ntoa(&RealHostAddr)[0] == '[' ||
1369            RealHostName[0] == '[')
1370        {
1371                /*
1372                **  address is not a socket or have an
1373                **  IP address with no forward lookup
1374                */
1375                *may_be_forged = FALSE;
1376        }
1377        else
1378        {
1379                /* try to match the reverse against the forward lookup */
1380                hp = sm_gethostbyname(RealHostName);
1381
1382                if (hp == NULL)
1383                        *may_be_forged = TRUE;
1384                else
1385                {
1386                        for (ha = hp->h_addr_list; *ha != NULL; ha++)
1387                                if (addrcmp(hp, *ha, &RealHostAddr) == 0)
1388                                        break;
1389                        *may_be_forged = *ha == NULL;
1390                }
1391        }
1392
1393        if (TimeOuts.to_ident == 0)
1394                goto noident;
1395
1396        lalen = sizeof la;
1397        if (RealHostAddr.sa.sa_family != AF_INET ||
1398            getsockname(fd, &la.sa, &lalen) < 0 || lalen <= 0 ||
1399            la.sa.sa_family != AF_INET)
1400        {
1401                /* no ident info */
1402                goto noident;
1403        }
1404
1405        /* create ident query */
1406        (void) snprintf(ibuf, sizeof ibuf, "%d,%d\r\n",
1407                ntohs(RealHostAddr.sin.sin_port), ntohs(la.sin.sin_port));
1408
1409        /* create local address */
1410        la.sin.sin_port = 0;
1411
1412        /* create foreign address */
1413        sp = getservbyname("auth", "tcp");
1414        if (sp != NULL)
1415                RealHostAddr.sin.sin_port = sp->s_port;
1416        else
1417                RealHostAddr.sin.sin_port = htons(113);
1418
1419        s = -1;
1420        if (setjmp(CtxAuthTimeout) != 0)
1421        {
1422                if (s >= 0)
1423                        (void) close(s);
1424                goto noident;
1425        }
1426
1427        /* put a timeout around the whole thing */
1428        ev = setevent(TimeOuts.to_ident, authtimeout, 0);
1429
1430        /* connect to foreign IDENT server using same address as SMTP socket */
1431        s = socket(AF_INET, SOCK_STREAM, 0);
1432        if (s < 0)
1433        {
1434                clrevent(ev);
1435                goto noident;
1436        }
1437        if (bind(s, &la.sa, sizeof la.sin) < 0 ||
1438            connect(s, &RealHostAddr.sa, sizeof RealHostAddr.sin) < 0)
1439        {
1440                goto closeident;
1441        }
1442
1443        if (tTd(9, 10))
1444                printf("getauthinfo: sent %s", ibuf);
1445
1446        /* send query */
1447        if (write(s, ibuf, strlen(ibuf)) < 0)
1448                goto closeident;
1449
1450        /* get result */
1451        p = &ibuf[0];
1452        nleft = sizeof ibuf - 1;
1453        while ((i = read(s, p, nleft)) > 0)
1454        {
1455                p += i;
1456                nleft -= i;
1457                *p = '\0';
1458                if (strchr(ibuf, '\n') != NULL)
1459                        break;
1460        }
1461        (void) close(s);
1462        clrevent(ev);
1463        if (i < 0 || p == &ibuf[0])
1464                goto noident;
1465
1466        if (*--p == '\n' && *--p == '\r')
1467                p--;
1468        *++p = '\0';
1469
1470        if (tTd(9, 3))
1471                printf("getauthinfo:  got %s\n", ibuf);
1472
1473        /* parse result */
1474        p = strchr(ibuf, ':');
1475        if (p == NULL)
1476        {
1477                /* malformed response */
1478                goto noident;
1479        }
1480        while (isascii(*++p) && isspace(*p))
1481                continue;
1482        if (strncasecmp(p, "userid", 6) != 0)
1483        {
1484                /* presumably an error string */
1485                goto noident;
1486        }
1487        p += 6;
1488        while (isascii(*p) && isspace(*p))
1489                p++;
1490        if (*p++ != ':')
1491        {
1492                /* either useridxx or malformed response */
1493                goto noident;
1494        }
1495
1496        /* p now points to the OSTYPE field */
1497        while (isascii(*p) && isspace(*p))
1498                p++;
1499        ostype = p;
1500        p = strchr(p, ':');
1501        if (p == NULL)
1502        {
1503                /* malformed response */
1504                goto noident;
1505        }
1506        else
1507        {
1508                char *charset;
1509
1510                *p = '\0';
1511                charset = strchr(ostype, ',');
1512                if (charset != NULL)
1513                        *charset = '\0';
1514        }
1515
1516        /* 1413 says don't do this -- but it's broken otherwise */
1517        while (isascii(*++p) && isspace(*p))
1518                continue;
1519
1520        /* p now points to the authenticated name -- copy carefully */
1521        if (strncasecmp(ostype, "other", 5) == 0 &&
1522            (ostype[5] == ' ' || ostype[5] == '\0'))
1523        {
1524                snprintf(hbuf, sizeof hbuf, "IDENT:");
1525                cleanstrcpy(&hbuf[6], p, MAXNAME);
1526        }
1527        else
1528                cleanstrcpy(hbuf, p, MAXNAME);
1529        i = strlen(hbuf);
1530        snprintf(&hbuf[i], sizeof hbuf - i, "@%s",
1531                 RealHostName == NULL ? "localhost" : RealHostName);
1532        goto postident;
1533
1534closeident:
1535        (void) close(s);
1536        clrevent(ev);
1537
1538noident:
1539        if (RealHostName == NULL)
1540        {
1541                if (tTd(9, 1))
1542                        printf("getauthinfo: NULL\n");
1543                return NULL;
1544        }
1545        snprintf(hbuf, sizeof hbuf, "%s", RealHostName);
1546
1547postident:
1548#if IP_SRCROUTE
1549# ifndef GET_IPOPT_DST
1550#  define GET_IPOPT_DST(dst)    (dst)
1551# endif
1552        /*
1553        **  Extract IP source routing information.
1554        **
1555        **      Format of output for a connection from site a through b
1556        **      through c to d:
1557        **              loose:      @site-c@site-b:site-a
1558        **              strict:    !@site-c@site-b:site-a
1559        **
1560        **      o - pointer within ipopt_list structure.
1561        **      q - pointer within ls/ss rr route data
1562        **      p - pointer to hbuf
1563        */
1564
1565        if (RealHostAddr.sa.sa_family == AF_INET)
1566        {
1567                SOCKOPT_LEN_T ipoptlen;
1568                int j;
1569                u_char *q;
1570                u_char *o;
1571                int l;
1572                struct in_addr addr;
1573                struct ipoption ipopt;
1574
1575                ipoptlen = sizeof ipopt;
1576                if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS,
1577                               (char *) &ipopt, &ipoptlen) < 0)
1578                        goto noipsr;
1579                if (ipoptlen == 0)
1580                        goto noipsr;
1581                o = (u_char *) ipopt.ipopt_list;
1582                while (o != NULL && o < (u_char *) &ipopt + ipoptlen)
1583                {
1584                        switch (*o)
1585                        {
1586                          case IPOPT_EOL:
1587                                o = NULL;
1588                                break;
1589
1590                          case IPOPT_NOP:
1591                                o++;
1592                                break;
1593
1594                          case IPOPT_SSRR:
1595                          case IPOPT_LSRR:
1596                                /*
1597                                **  Source routing.
1598                                **      o[0] is the option type (loose/strict).
1599                                **      o[1] is the length of this option,
1600                                **              including option type and
1601                                **              length.
1602                                **      o[2] is the pointer into the route
1603                                **              data.
1604                                **      o[3] begins the route data.
1605                                */
1606
1607                                p = &hbuf[strlen(hbuf)];
1608                                l = sizeof hbuf - (hbuf - p) - 6;
1609                                snprintf(p, SPACELEFT(hbuf, p), " [%s@%.*s",
1610                                    *o == IPOPT_SSRR ? "!" : "",
1611                                    l > 240 ? 120 : l / 2,
1612                                    inet_ntoa(GET_IPOPT_DST(ipopt.ipopt_dst)));
1613                                i = strlen(p);
1614                                p += i;
1615                                l -= strlen(p);
1616
1617                                j = o[1] / sizeof(struct in_addr) - 1;
1618
1619                                /* q skips length and router pointer to data */
1620                                q = &o[3];
1621                                for ( ; j >= 0; j--)
1622                                {
1623                                        memcpy(&addr, q, sizeof(addr));
1624                                        snprintf(p, SPACELEFT(hbuf, p),
1625                                                "%c%.*s",
1626                                                j != 0 ? '@' : ':',
1627                                                l > 240 ? 120 :
1628                                                    j == 0 ? l : l / 2,
1629                                                inet_ntoa(addr));
1630                                        i = strlen(p);
1631                                        p += i;
1632                                        l -= i + 1;
1633                                        q += sizeof(struct in_addr);
1634                                }
1635                                o += o[1];
1636                                break;
1637
1638                          default:
1639                                /* Skip over option */
1640                                o += o[1];
1641                                break;
1642                        }
1643                }
1644                snprintf(p, SPACELEFT(hbuf, p), "]");
1645                goto postipsr;
1646        }
1647
1648noipsr:
1649#endif
1650        if (RealHostName != NULL && RealHostName[0] != '[')
1651        {
1652                p = &hbuf[strlen(hbuf)];
1653                (void) snprintf(p, SPACELEFT(hbuf, p), " [%.100s]",
1654                        anynet_ntoa(&RealHostAddr));
1655        }
1656        if (*may_be_forged)
1657        {
1658                p = &hbuf[strlen(hbuf)];
1659                (void) snprintf(p, SPACELEFT(hbuf, p), " (may be forged)");
1660        }
1661
1662#if IP_SRCROUTE
1663postipsr:
1664#endif
1665        if (tTd(9, 1))
1666                printf("getauthinfo: %s\n", hbuf);
1667        return hbuf;
1668}
1669/*
1670**  HOST_MAP_LOOKUP -- turn a hostname into canonical form
1671**
1672**      Parameters:
1673**              map -- a pointer to this map.
1674**              name -- the (presumably unqualified) hostname.
1675**              av -- unused -- for compatibility with other mapping
1676**                      functions.
1677**              statp -- an exit status (out parameter) -- set to
1678**                      EX_TEMPFAIL if the name server is unavailable.
1679**
1680**      Returns:
1681**              The mapping, if found.
1682**              NULL if no mapping found.
1683**
1684**      Side Effects:
1685**              Looks up the host specified in hbuf.  If it is not
1686**              the canonical name for that host, return the canonical
1687**              name (unless MF_MATCHONLY is set, which will cause the
1688**              status only to be returned).
1689*/
1690
1691char *
1692host_map_lookup(map, name, av, statp)
1693        MAP *map;
1694        char *name;
1695        char **av;
1696        int *statp;
1697{
1698        register struct hostent *hp;
1699        struct in_addr in_addr;
1700        char *cp;
1701        register STAB *s;
1702        char hbuf[MAXNAME + 1];
1703
1704        /*
1705        **  See if we have already looked up this name.  If so, just
1706        **  return it.
1707        */
1708
1709        s = stab(name, ST_NAMECANON, ST_ENTER);
1710        if (bitset(NCF_VALID, s->s_namecanon.nc_flags))
1711        {
1712                if (tTd(9, 1))
1713                        printf("host_map_lookup(%s) => CACHE %s\n",
1714                               name,
1715                               s->s_namecanon.nc_cname == NULL
1716                                        ? "NULL"
1717                                        : s->s_namecanon.nc_cname);
1718                errno = s->s_namecanon.nc_errno;
1719#if NAMED_BIND
1720                h_errno = s->s_namecanon.nc_herrno;
1721#endif
1722                *statp = s->s_namecanon.nc_stat;
1723                if (*statp == EX_TEMPFAIL)
1724                {
1725                        CurEnv->e_status = "4.4.3";
1726                        message("851 %s: Name server timeout",
1727                                shortenstring(name, 33));
1728                }
1729                if (*statp != EX_OK)
1730                        return NULL;
1731                if (s->s_namecanon.nc_cname == NULL)
1732                {
1733                        syserr("host_map_lookup(%s): bogus NULL cache entry, errno = %d, h_errno = %d",
1734                                name,
1735                                s->s_namecanon.nc_errno,
1736                                s->s_namecanon.nc_herrno);
1737                        return NULL;
1738                }
1739                if (bitset(MF_MATCHONLY, map->map_mflags))
1740                        cp = map_rewrite(map, name, strlen(name), NULL);
1741                else
1742                        cp = map_rewrite(map,
1743                                         s->s_namecanon.nc_cname,
1744                                         strlen(s->s_namecanon.nc_cname),
1745                                         av);
1746                return cp;
1747        }
1748
1749        /*
1750        **  If we are running without a regular network connection (usually
1751        **  dial-on-demand) and we are just queueing, we want to avoid DNS
1752        **  lookups because those could try to connect to a server.
1753        */
1754
1755        if (CurEnv->e_sendmode == SM_DEFER)
1756        {
1757                if (tTd(9, 1))
1758                        printf("host_map_lookup(%s) => DEFERRED\n", name);
1759                *statp = EX_TEMPFAIL;
1760                return NULL;
1761        }
1762
1763        /*
1764        **  If first character is a bracket, then it is an address
1765        **  lookup.  Address is copied into a temporary buffer to
1766        **  strip the brackets and to preserve name if address is
1767        **  unknown.
1768        */
1769
1770        if (*name != '[')
1771        {
1772                if (tTd(9, 1))
1773                        printf("host_map_lookup(%s) => ", name);
1774                s->s_namecanon.nc_flags |= NCF_VALID;           /* will be soon */
1775                snprintf(hbuf, sizeof hbuf, "%s", name);
1776                if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX))
1777                {
1778                        if (tTd(9, 1))
1779                                printf("%s\n", hbuf);
1780                        s->s_namecanon.nc_stat = EX_OK;
1781                        s->s_namecanon.nc_cname = newstr(hbuf);
1782                        if (bitset(MF_MATCHONLY, map->map_mflags))
1783                                cp = map_rewrite(map, name, strlen(name), NULL);
1784                        else
1785                                cp = map_rewrite(map, hbuf, strlen(hbuf), av);
1786                        return cp;
1787                }
1788                else
1789                {
1790                        s->s_namecanon.nc_errno = errno;
1791#if NAMED_BIND
1792                        s->s_namecanon.nc_herrno = h_errno;
1793                        if (tTd(9, 1))
1794                                printf("FAIL (%d)\n", h_errno);
1795                        switch (h_errno)
1796                        {
1797                          case TRY_AGAIN:
1798                                if (UseNameServer)
1799                                {
1800                                        CurEnv->e_status = "4.4.3";
1801                                        message("851 %s: Name server timeout",
1802                                                shortenstring(name, 33));
1803                                }
1804                                *statp = EX_TEMPFAIL;
1805                                break;
1806
1807                          case HOST_NOT_FOUND:
1808                          case NO_DATA:
1809                                *statp = EX_NOHOST;
1810                                break;
1811
1812                          case NO_RECOVERY:
1813                                *statp = EX_SOFTWARE;
1814                                break;
1815
1816                          default:
1817                                *statp = EX_UNAVAILABLE;
1818                                break;
1819                        }
1820#else
1821                        if (tTd(9, 1))
1822                                printf("FAIL\n");
1823                        *statp = EX_NOHOST;
1824#endif
1825                        s->s_namecanon.nc_stat = *statp;
1826                        return NULL;
1827                }
1828        }
1829        if ((cp = strchr(name, ']')) == NULL)
1830                return (NULL);
1831        *cp = '\0';
1832        in_addr.s_addr = inet_addr(&name[1]);
1833        *cp = ']';
1834
1835        /* nope -- ask the name server */
1836        hp = sm_gethostbyaddr((char *)&in_addr, INADDRSZ, AF_INET);
1837        s->s_namecanon.nc_errno = errno;
1838#if NAMED_BIND
1839        s->s_namecanon.nc_herrno = h_errno;
1840#endif
1841        s->s_namecanon.nc_flags |= NCF_VALID;           /* will be soon */
1842        if (hp == NULL)
1843        {
1844                s->s_namecanon.nc_stat = *statp = EX_NOHOST;
1845                return (NULL);
1846        }
1847
1848        /* found a match -- copy out */
1849        hp->h_name = denlstring((char *) hp->h_name, TRUE, TRUE);
1850        s->s_namecanon.nc_stat = *statp = EX_OK;
1851        s->s_namecanon.nc_cname = newstr(hp->h_name);
1852        if (bitset(MF_MATCHONLY, map->map_mflags))
1853                cp = map_rewrite(map, name, strlen(name), NULL);
1854        else
1855                cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), av);
1856        return cp;
1857}
1858
1859# else /* DAEMON */
1860/* code for systems without sophisticated networking */
1861
1862/*
1863**  MYHOSTNAME -- stub version for case of no daemon code.
1864**
1865**      Can't convert to upper case here because might be a UUCP name.
1866**
1867**      Mark, you can change this to be anything you want......
1868*/
1869
1870char **
1871myhostname(hostbuf, size)
1872        char hostbuf[];
1873        int size;
1874{
1875        register FILE *f;
1876
1877        hostbuf[0] = '\0';
1878        f = fopen("/usr/include/whoami", "r");
1879        if (f != NULL)
1880        {
1881                (void) fgets(hostbuf, size, f);
1882                fixcrlf(hostbuf, TRUE);
1883                (void) fclose(f);
1884        }
1885        return (NULL);
1886}
1887/*
1888**  GETAUTHINFO -- get the real host name asociated with a file descriptor
1889**
1890**      Parameters:
1891**              fd -- the descriptor
1892**              may_be_forged -- an outage that is set to TRUE if the
1893**                      forward lookup of RealHostName does not match
1894**                      RealHostAddr; set to FALSE if they do match.
1895**
1896**      Returns:
1897**              The host name associated with this descriptor, if it can
1898**                      be determined.
1899**              NULL otherwise.
1900**
1901**      Side Effects:
1902**              none
1903*/
1904
1905char *
1906getauthinfo(fd, may_be_forged)
1907        int fd;
1908        bool *may_be_forged;
1909{
1910        *may_be_forged = FALSE;
1911        return NULL;
1912}
1913/*
1914**  MAPHOSTNAME -- turn a hostname into canonical form
1915**
1916**      Parameters:
1917**              map -- a pointer to the database map.
1918**              name -- a buffer containing a hostname.
1919**              avp -- a pointer to a (cf file defined) argument vector.
1920**              statp -- an exit status (out parameter).
1921**
1922**      Returns:
1923**              mapped host name
1924**              FALSE otherwise.
1925**
1926**      Side Effects:
1927**              Looks up the host specified in name.  If it is not
1928**              the canonical name for that host, replace it with
1929**              the canonical name.  If the name is unknown, or it
1930**              is already the canonical name, leave it unchanged.
1931*/
1932
1933/*ARGSUSED*/
1934char *
1935host_map_lookup(map, name, avp, statp)
1936        MAP *map;
1937        char *name;
1938        char **avp;
1939        char *statp;
1940{
1941        register struct hostent *hp;
1942        char *cp;
1943
1944        hp = sm_gethostbyname(name);
1945        if (hp == NULL)
1946        {
1947                *statp = EX_NOHOST;
1948                return NULL;
1949        }
1950        if (bitset(MF_MATCHONLY, map->map_mflags))
1951                cp = map_rewrite(map, name, strlen(name), NULL);
1952        else
1953                cp = map_rewrite(map, hp->h_name, strlen(hp->h_name), avp);
1954        return cp;
1955}
1956
1957#endif /* DAEMON */
1958/*
1959**  HOST_MAP_INIT -- initialize host class structures
1960*/
1961
1962bool
1963host_map_init(map, args)
1964        MAP *map;
1965        char *args;
1966{
1967        register char *p = args;
1968
1969        for (;;)
1970        {
1971                while (isascii(*p) && isspace(*p))
1972                        p++;
1973                if (*p != '-')
1974                        break;
1975                switch (*++p)
1976                {
1977                  case 'a':
1978                        map->map_app = ++p;
1979                        break;
1980
1981                  case 'T':
1982                        map->map_tapp = ++p;
1983                        break;
1984
1985                  case 'm':
1986                        map->map_mflags |= MF_MATCHONLY;
1987                        break;
1988
1989                  case 't':
1990                        map->map_mflags |= MF_NODEFER;
1991                        break;
1992                }
1993                while (*p != '\0' && !(isascii(*p) && isspace(*p)))
1994                        p++;
1995                if (*p != '\0')
1996                        *p++ = '\0';
1997        }
1998        if (map->map_app != NULL)
1999                map->map_app = newstr(map->map_app);
2000        if (map->map_tapp != NULL)
2001                map->map_tapp = newstr(map->map_tapp);
2002        return TRUE;
2003}
2004/*
2005**  ANYNET_NTOA -- convert a network address to printable form.
2006**
2007**      Parameters:
2008**              sap -- a pointer to a sockaddr structure.
2009**
2010**      Returns:
2011**              A printable version of that sockaddr.
2012*/
2013
2014#ifdef USE_SOCK_STREAM
2015
2016#if NETLINK
2017# include <net/if_dl.h>
2018#endif
2019
2020char *
2021anynet_ntoa(sap)
2022        register SOCKADDR *sap;
2023{
2024        register char *bp;
2025        register char *ap;
2026        int l;
2027        static char buf[100];
2028
2029        /* check for null/zero family */
2030        if (sap == NULL)
2031                return "NULLADDR";
2032        if (sap->sa.sa_family == 0)
2033                return "0";
2034
2035        switch (sap->sa.sa_family)
2036        {
2037#if NETUNIX
2038          case AF_UNIX:
2039                if (sap->sunix.sun_path[0] != '\0')
2040                        snprintf(buf, sizeof buf, "[UNIX: %.64s]",
2041                                sap->sunix.sun_path);
2042                else
2043                        snprintf(buf, sizeof buf, "[UNIX: localhost]");
2044                return buf;
2045#endif
2046
2047#if NETINET
2048          case AF_INET:
2049                return inet_ntoa(sap->sin.sin_addr);
2050#endif
2051
2052#if NETLINK
2053          case AF_LINK:
2054                snprintf(buf, sizeof buf, "[LINK: %s]",
2055                        link_ntoa((struct sockaddr_dl *) &sap->sa));
2056                return buf;
2057#endif
2058          default:
2059                /* this case is needed when nothing is #defined */
2060                /* in order to keep the switch syntactically correct */
2061                break;
2062        }
2063
2064        /* unknown family -- just dump bytes */
2065        (void) snprintf(buf, sizeof buf, "Family %d: ", sap->sa.sa_family);
2066        bp = &buf[strlen(buf)];
2067        ap = sap->sa.sa_data;
2068        for (l = sizeof sap->sa.sa_data; --l >= 0; )
2069        {
2070                (void) snprintf(bp, SPACELEFT(buf, bp), "%02x:", *ap++ & 0377);
2071                bp += 3;
2072        }
2073        *--bp = '\0';
2074        return buf;
2075}
2076/*
2077**  HOSTNAMEBYANYADDR -- return name of host based on address
2078**
2079**      Parameters:
2080**              sap -- SOCKADDR pointer
2081**
2082**      Returns:
2083**              text representation of host name.
2084**
2085**      Side Effects:
2086**              none.
2087*/
2088
2089char *
2090hostnamebyanyaddr(sap)
2091        register SOCKADDR *sap;
2092{
2093        register struct hostent *hp;
2094        int saveretry;
2095
2096#if NAMED_BIND
2097        /* shorten name server timeout to avoid higher level timeouts */
2098        saveretry = _res.retry;
2099        _res.retry = 3;
2100#endif /* NAMED_BIND */
2101
2102        switch (sap->sa.sa_family)
2103        {
2104#if NETINET
2105          case AF_INET:
2106                hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr,
2107                        INADDRSZ,
2108                        AF_INET);
2109                break;
2110#endif
2111
2112#if NETISO
2113          case AF_ISO:
2114                hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr,
2115                        sizeof sap->siso.siso_addr,
2116                        AF_ISO);
2117                break;
2118#endif
2119
2120#if NETUNIX
2121          case AF_UNIX:
2122                hp = NULL;
2123                break;
2124#endif
2125
2126          default:
2127                hp = sm_gethostbyaddr(sap->sa.sa_data,
2128                           sizeof sap->sa.sa_data,
2129                           sap->sa.sa_family);
2130                break;
2131        }
2132
2133#if NAMED_BIND
2134        _res.retry = saveretry;
2135#endif /* NAMED_BIND */
2136
2137        if (hp != NULL && hp->h_name[0] != '[' &&
2138            inet_addr(hp->h_name) == INADDR_NONE)
2139                return denlstring((char *) hp->h_name, TRUE, TRUE);
2140#if NETUNIX
2141        else if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0')
2142                return "localhost";
2143#endif
2144        else
2145        {
2146                /* produce a dotted quad */
2147                static char buf[203];
2148
2149                (void) snprintf(buf, sizeof buf, "[%.200s]", anynet_ntoa(sap));
2150                return buf;
2151        }
2152}
2153
2154#endif /* SOCK_STREAM */
Note: See TracBrowser for help on using the repository browser.