source: trunk/third/sendmail/sendmail/daemon.c @ 19204

Revision 19204, 94.6 KB checked in by zacheiss, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19203, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers.
3 *      All rights reserved.
4 * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5 * Copyright (c) 1988, 1993
6 *      The Regents of the University of California.  All rights reserved.
7 *
8 * By using this file, you agree to the terms and conditions set
9 * forth in the LICENSE file which can be found at the top level of
10 * the sendmail distribution.
11 *
12 */
13
14#include <sendmail.h>
15
16SM_RCSID("@(#)$Id: daemon.c,v 1.1.1.1 2003-04-08 15:08:53 zacheiss Exp $")
17
18#if defined(SOCK_STREAM) || defined(__GNU_LIBRARY__)
19# define USE_SOCK_STREAM        1
20#endif /* defined(SOCK_STREAM) || defined(__GNU_LIBRARY__) */
21
22#if defined(USE_SOCK_STREAM)
23# if NETINET || NETINET6
24#  include <arpa/inet.h>
25# endif /* NETINET || NETINET6 */
26# if NAMED_BIND
27#  ifndef NO_DATA
28#   define NO_DATA      NO_ADDRESS
29#  endif /* ! NO_DATA */
30# endif /* NAMED_BIND */
31#endif /* defined(USE_SOCK_STREAM) */
32
33#if STARTTLS
34#  include <openssl/rand.h>
35#endif /* STARTTLS */
36
37#include <sys/time.h>
38
39#if IP_SRCROUTE && NETINET
40# include <netinet/in_systm.h>
41# include <netinet/ip.h>
42# if HAS_IN_H
43#  include <netinet/in.h>
44#  ifndef IPOPTION
45#   define IPOPTION     ip_opts
46#   define IP_LIST      ip_opts
47#   define IP_DST       ip_dst
48#  endif /* ! IPOPTION */
49# else /* HAS_IN_H */
50#  include <netinet/ip_var.h>
51#  ifndef IPOPTION
52#   define IPOPTION     ipoption
53#   define IP_LIST      ipopt_list
54#   define IP_DST       ipopt_dst
55#  endif /* ! IPOPTION */
56# endif /* HAS_IN_H */
57#endif /* IP_SRCROUTE && NETINET */
58
59#include <sm/fdset.h>
60
61/* structure to describe a daemon or a client */
62struct daemon
63{
64        int             d_socket;       /* fd for socket */
65        SOCKADDR        d_addr;         /* socket for incoming */
66        unsigned short  d_port;         /* port number */
67        int             d_listenqueue;  /* size of listen queue */
68        int             d_tcprcvbufsize;        /* size of TCP receive buffer */
69        int             d_tcpsndbufsize;        /* size of TCP send buffer */
70        time_t          d_refuse_connections_until;
71        bool            d_firsttime;
72        int             d_socksize;
73        BITMAP256       d_flags;        /* flags; see sendmail.h */
74        char            *d_mflags;      /* flags for use in macro */
75        char            *d_name;        /* user-supplied name */
76#if MILTER
77# if _FFR_MILTER_PERDAEMON
78        char            *d_inputfilterlist;
79        struct milter   *d_inputfilters[MAXFILTERS];
80# endif /* _FFR_MILTER_PERDAEMON */
81#endif /* MILTER */
82};
83
84typedef struct daemon DAEMON_T;
85
86static void             connecttimeout __P((void));
87static int              opendaemonsocket __P((DAEMON_T *, bool));
88static unsigned short   setupdaemon __P((SOCKADDR *));
89static void             getrequests_checkdiskspace __P((ENVELOPE *e));
90
91/*
92**  DAEMON.C -- routines to use when running as a daemon.
93**
94**      This entire file is highly dependent on the 4.2 BSD
95**      interprocess communication primitives.  No attempt has
96**      been made to make this file portable to Version 7,
97**      Version 6, MPX files, etc.  If you should try such a
98**      thing yourself, I recommend chucking the entire file
99**      and starting from scratch.  Basic semantics are:
100**
101**      getrequests(e)
102**              Opens a port and initiates a connection.
103**              Returns in a child.  Must set InChannel and
104**              OutChannel appropriately.
105**      clrdaemon()
106**              Close any open files associated with getting
107**              the connection; this is used when running the queue,
108**              etc., to avoid having extra file descriptors during
109**              the queue run and to avoid confusing the network
110**              code (if it cares).
111**      makeconnection(host, port, mci, e, enough)
112**              Make a connection to the named host on the given
113**              port. Returns zero on success, else an exit status
114**              describing the error.
115**      host_map_lookup(map, hbuf, avp, pstat)
116**              Convert the entry in hbuf into a canonical form.
117*/
118
119static DAEMON_T Daemons[MAXDAEMONS];
120static int      NDaemons = 0;                   /* actual number of daemons */
121
122static time_t   NextDiskSpaceCheck = 0;
123
124/*
125**  GETREQUESTS -- open mail IPC port and get requests.
126**
127**      Parameters:
128**              e -- the current envelope.
129**
130**      Returns:
131**              pointer to flags.
132**
133**      Side Effects:
134**              Waits until some interesting activity occurs.  When
135**              it does, a child is created to process it, and the
136**              parent waits for completion.  Return from this
137**              routine is always in the child.  The file pointers
138**              "InChannel" and "OutChannel" should be set to point
139**              to the communication channel.
140**              May restart persistent queue runners if they have ended
141**              for some reason.
142*/
143
144BITMAP256 *
145getrequests(e)
146        ENVELOPE *e;
147{
148        int t;
149        int idx, curdaemon = -1;
150        int i, olddaemon = 0;
151#if XDEBUG
152        bool j_has_dot;
153#endif /* XDEBUG */
154        char status[MAXLINE];
155        SOCKADDR sa;
156        SOCKADDR_LEN_T len = sizeof sa;
157#if _FFR_QUEUE_RUN_PARANOIA
158        time_t lastrun;
159#endif /* _FFR_QUEUE_RUN_PARANOIA */
160# if NETUNIX
161        extern int ControlSocket;
162# endif /* NETUNIX */
163        extern ENVELOPE BlankEnvelope;
164        extern bool refuseconnections __P((char *, ENVELOPE *, int, bool));
165
166
167        for (idx = 0; idx < NDaemons; idx++)
168        {
169                Daemons[idx].d_port = setupdaemon(&(Daemons[idx].d_addr));
170                Daemons[idx].d_firsttime = true;
171                Daemons[idx].d_refuse_connections_until = (time_t) 0;
172        }
173
174        /*
175        **  Try to actually open the connection.
176        */
177
178        if (tTd(15, 1))
179        {
180                for (idx = 0; idx < NDaemons; idx++)
181                {
182                        sm_dprintf("getrequests: daemon %s: port %d\n",
183                                   Daemons[idx].d_name,
184                                   ntohs(Daemons[idx].d_port));
185                }
186        }
187
188        /* get a socket for the SMTP connection */
189        for (idx = 0; idx < NDaemons; idx++)
190                Daemons[idx].d_socksize = opendaemonsocket(&Daemons[idx], true);
191
192        if (opencontrolsocket() < 0)
193                sm_syslog(LOG_WARNING, NOQID,
194                          "daemon could not open control socket %s: %s",
195                          ControlSocketName, sm_errstring(errno));
196
197        /* If there are any queue runners released reapchild() co-ord's */
198        (void) sm_signal(SIGCHLD, reapchild);
199
200        /* write the pid to file, command line args to syslog */
201        log_sendmail_pid(e);
202
203#if XDEBUG
204        {
205                char jbuf[MAXHOSTNAMELEN];
206
207                expand("\201j", jbuf, sizeof jbuf, e);
208                j_has_dot = strchr(jbuf, '.') != NULL;
209        }
210#endif /* XDEBUG */
211
212        /* Add parent process as first item */
213        proc_list_add(CurrentPid, "Sendmail daemon", PROC_DAEMON, 0, -1);
214
215        if (tTd(15, 1))
216        {
217                for (idx = 0; idx < NDaemons; idx++)
218                        sm_dprintf("getrequests: daemon %s: %d\n",
219                                Daemons[idx].d_name,
220                                Daemons[idx].d_socket);
221        }
222
223        for (;;)
224        {
225                register pid_t pid;
226                auto SOCKADDR_LEN_T lotherend;
227                bool timedout = false;
228                bool control = false;
229                int save_errno;
230                int pipefd[2];
231                time_t now;
232#if STARTTLS
233                long seed;
234#endif /* STARTTLS */
235
236                /* see if we are rejecting connections */
237                (void) sm_blocksignal(SIGALRM);
238
239                if (ShutdownRequest != NULL)
240                        shutdown_daemon();
241                else if (RestartRequest != NULL)
242                        restart_daemon();
243                else if (RestartWorkGroup)
244                        restart_marked_work_groups();
245
246                for (idx = 0; idx < NDaemons; idx++)
247                {
248                        /*
249                        **  XXX do this call outside the loop?
250                        **      no: refuse_connections may sleep().
251                        */
252
253                        now = curtime();
254                        if (now < Daemons[idx].d_refuse_connections_until)
255                                continue;
256                        if (bitnset(D_DISABLE, Daemons[idx].d_flags))
257                                continue;
258                        if (refuseconnections(Daemons[idx].d_name, e, idx,
259                                              curdaemon == idx))
260                        {
261                                if (Daemons[idx].d_socket >= 0)
262                                {
263                                        /* close socket so peer fails quickly */
264                                        (void) close(Daemons[idx].d_socket);
265                                        Daemons[idx].d_socket = -1;
266                                }
267
268                                /* refuse connections for next 15 seconds */
269                                Daemons[idx].d_refuse_connections_until = now + 15;
270                        }
271                        else if (Daemons[idx].d_socket < 0 ||
272                                 Daemons[idx].d_firsttime)
273                        {
274                                if (!Daemons[idx].d_firsttime && LogLevel > 8)
275                                        sm_syslog(LOG_INFO, NOQID,
276                                                "accepting connections again for daemon %s",
277                                                Daemons[idx].d_name);
278
279                                /* arrange to (re)open the socket if needed */
280                                (void) opendaemonsocket(&Daemons[idx], false);
281                                Daemons[idx].d_firsttime = false;
282                        }
283                }
284
285                /* May have been sleeping above, check again */
286                if (ShutdownRequest != NULL)
287                        shutdown_daemon();
288                else if (RestartRequest != NULL)
289                        restart_daemon();
290                else if (RestartWorkGroup)
291                        restart_marked_work_groups();
292
293                getrequests_checkdiskspace(e);
294
295#if XDEBUG
296                /* check for disaster */
297                {
298                        char jbuf[MAXHOSTNAMELEN];
299
300                        expand("\201j", jbuf, sizeof jbuf, e);
301                        if (!wordinclass(jbuf, 'w'))
302                        {
303                                dumpstate("daemon lost $j");
304                                sm_syslog(LOG_ALERT, NOQID,
305                                          "daemon process doesn't have $j in $=w; see syslog");
306                                abort();
307                        }
308                        else if (j_has_dot && strchr(jbuf, '.') == NULL)
309                        {
310                                dumpstate("daemon $j lost dot");
311                                sm_syslog(LOG_ALERT, NOQID,
312                                          "daemon process $j lost dot; see syslog");
313                                abort();
314                        }
315                }
316#endif /* XDEBUG */
317
318#if 0
319                /*
320                **  Andrew Sun <asun@ieps-sun.ml.com> claims that this will
321                **  fix the SVr4 problem.  But it seems to have gone away,
322                **  so is it worth doing this?
323                */
324
325                if (DaemonSocket >= 0 &&
326                    SetNonBlocking(DaemonSocket, false) < 0)
327                        log an error here;
328#endif /* 0 */
329                (void) sm_releasesignal(SIGALRM);
330
331                for (;;)
332                {
333                        bool setproc = false;
334                        int highest = -1;
335                        fd_set readfds;
336                        struct timeval timeout;
337
338                        if (ShutdownRequest != NULL)
339                                shutdown_daemon();
340                        else if (RestartRequest != NULL)
341                                restart_daemon();
342                        else if (RestartWorkGroup)
343                                restart_marked_work_groups();
344
345                        FD_ZERO(&readfds);
346
347                        for (idx = 0; idx < NDaemons; idx++)
348                        {
349                                /* wait for a connection */
350                                if (Daemons[idx].d_socket >= 0)
351                                {
352                                        if (!setproc &&
353                                            !bitnset(D_ETRNONLY,
354                                                     Daemons[idx].d_flags))
355                                        {
356                                                sm_setproctitle(true, e,
357                                                                "accepting connections");
358                                                setproc = true;
359                                        }
360                                        if (Daemons[idx].d_socket > highest)
361                                                highest = Daemons[idx].d_socket;
362                                        SM_FD_SET(Daemons[idx].d_socket,
363                                                  &readfds);
364                                }
365                        }
366
367#if NETUNIX
368                        if (ControlSocket >= 0)
369                        {
370                                if (ControlSocket > highest)
371                                        highest = ControlSocket;
372                                SM_FD_SET(ControlSocket, &readfds);
373                        }
374#endif /* NETUNIX */
375
376                        timeout.tv_sec = 5;
377                        timeout.tv_usec = 0;
378
379                        t = select(highest + 1, FDSET_CAST &readfds,
380                                   NULL, NULL, &timeout);
381
382                        /* Did someone signal while waiting? */
383                        if (ShutdownRequest != NULL)
384                                shutdown_daemon();
385                        else if (RestartRequest != NULL)
386                                restart_daemon();
387                        else if (RestartWorkGroup)
388                                restart_marked_work_groups();
389
390
391
392                        curdaemon = -1;
393                        if (doqueuerun())
394                        {
395                                (void) runqueue(true, false, false, false);
396#if _FFR_QUEUE_RUN_PARANOIA
397                                lastrun = now;
398#endif /* _FFR_QUEUE_RUN_PARANOIA */
399                        }
400#if _FFR_QUEUE_RUN_PARANOIA
401                        else if (QueueIntvl > 0 &&
402                                 lastrun + QueueIntvl + 60 < now)
403                        {
404
405                                /*
406                                **  set lastrun unconditionally to avoid
407                                **  calling checkqueuerunner() all the time.
408                                **  That's also why we currently ignore the
409                                **  result of the function call.
410                                */
411
412                                (void) checkqueuerunner();
413                                lastrun = now;
414                        }
415#endif /* _FFR_QUEUE_RUN_PARANOIA */
416
417                        if (t <= 0)
418                        {
419                                timedout = true;
420                                break;
421                        }
422
423                        control = false;
424                        errno = 0;
425
426                        /* look "round-robin" for an active socket */
427                        if ((idx = olddaemon + 1) >= NDaemons)
428                                idx = 0;
429                        for (i = 0; i < NDaemons; i++)
430                        {
431                                if (Daemons[idx].d_socket >= 0 &&
432                                    SM_FD_ISSET(Daemons[idx].d_socket,
433                                                &readfds))
434                                {
435                                        lotherend = Daemons[idx].d_socksize;
436                                        memset(&RealHostAddr, '\0',
437                                               sizeof RealHostAddr);
438                                        t = accept(Daemons[idx].d_socket,
439                                                   (struct sockaddr *)&RealHostAddr,
440                                                   &lotherend);
441
442                                        /*
443                                        **  If remote side closes before
444                                        **  accept() finishes, sockaddr
445                                        **  might not be fully filled in.
446                                        */
447
448                                        if (t >= 0 &&
449                                            (lotherend == 0 ||
450# ifdef BSD4_4_SOCKADDR
451                                             RealHostAddr.sa.sa_len == 0 ||
452# endif /* BSD4_4_SOCKADDR */
453                                             RealHostAddr.sa.sa_family != Daemons[idx].d_addr.sa.sa_family))
454                                        {
455                                                (void) close(t);
456                                                t = -1;
457                                                errno = EINVAL;
458                                        }
459                                        olddaemon = curdaemon = idx;
460                                        break;
461                                }
462                                if (++idx >= NDaemons)
463                                        idx = 0;
464                        }
465#if NETUNIX
466                        if (curdaemon == -1 && ControlSocket >= 0 &&
467                            SM_FD_ISSET(ControlSocket, &readfds))
468                        {
469                                struct sockaddr_un sa_un;
470
471                                lotherend = sizeof sa_un;
472                                memset(&sa_un, '\0', sizeof sa_un);
473                                t = accept(ControlSocket,
474                                           (struct sockaddr *)&sa_un,
475                                           &lotherend);
476
477                                /*
478                                **  If remote side closes before
479                                **  accept() finishes, sockaddr
480                                **  might not be fully filled in.
481                                */
482
483                                if (t >= 0 &&
484                                    (lotherend == 0 ||
485# ifdef BSD4_4_SOCKADDR
486                                     sa_un.sun_len == 0 ||
487# endif /* BSD4_4_SOCKADDR */
488                                     sa_un.sun_family != AF_UNIX))
489                                {
490                                        (void) close(t);
491                                        t = -1;
492                                        errno = EINVAL;
493                                }
494                                if (t >= 0)
495                                        control = true;
496                        }
497#else /* NETUNIX */
498                        if (curdaemon == -1)
499                        {
500                                /* No daemon to service */
501                                continue;
502                        }
503#endif /* NETUNIX */
504                        if (t >= 0 || errno != EINTR)
505                                break;
506                }
507                if (timedout)
508                {
509                        timedout = false;
510                        continue;
511                }
512                save_errno = errno;
513                (void) sm_blocksignal(SIGALRM);
514                if (t < 0)
515                {
516                        errno = save_errno;
517                        syserr("getrequests: accept");
518
519                        /* arrange to re-open the socket next time around */
520                        (void) close(Daemons[curdaemon].d_socket);
521                        Daemons[curdaemon].d_socket = -1;
522#if SO_REUSEADDR_IS_BROKEN
523                        /*
524                        **  Give time for bound socket to be released.
525                        **  This creates a denial-of-service if you can
526                        **  force accept() to fail on affected systems.
527                        */
528
529                        Daemons[curdaemon].d_refuse_connections_until = curtime() + 15;
530#endif /* SO_REUSEADDR_IS_BROKEN */
531                        continue;
532                }
533
534                if (!control)
535                {
536                        /* set some daemon related macros */
537                        switch (Daemons[curdaemon].d_addr.sa.sa_family)
538                        {
539                          case AF_UNSPEC:
540                                macdefine(&BlankEnvelope.e_macro, A_PERM,
541                                        macid("{daemon_family}"), "unspec");
542                                break;
543#if _FFR_DAEMON_NETUNIX
544# if NETUNIX
545                          case AF_UNIX:
546                                macdefine(&BlankEnvelope.e_macro, A_PERM,
547                                        macid("{daemon_family}"), "local");
548                                break;
549# endif /* NETUNIX */
550#endif /* _FFR_DAEMON_NETUNIX */
551#if NETINET
552                          case AF_INET:
553                                macdefine(&BlankEnvelope.e_macro, A_PERM,
554                                        macid("{daemon_family}"), "inet");
555                                break;
556#endif /* NETINET */
557#if NETINET6
558                          case AF_INET6:
559                                macdefine(&BlankEnvelope.e_macro, A_PERM,
560                                        macid("{daemon_family}"), "inet6");
561                                break;
562#endif /* NETINET6 */
563#if NETISO
564                          case AF_ISO:
565                                macdefine(&BlankEnvelope.e_macro, A_PERM,
566                                        macid("{daemon_family}"), "iso");
567                                break;
568#endif /* NETISO */
569#if NETNS
570                          case AF_NS:
571                                macdefine(&BlankEnvelope.e_macro, A_PERM,
572                                        macid("{daemon_family}"), "ns");
573                                break;
574#endif /* NETNS */
575#if NETX25
576                          case AF_CCITT:
577                                macdefine(&BlankEnvelope.e_macro, A_PERM,
578                                        macid("{daemon_family}"), "x.25");
579                                break;
580#endif /* NETX25 */
581                        }
582                        macdefine(&BlankEnvelope.e_macro, A_PERM,
583                                macid("{daemon_name}"),
584                                Daemons[curdaemon].d_name);
585                        if (Daemons[curdaemon].d_mflags != NULL)
586                                macdefine(&BlankEnvelope.e_macro, A_PERM,
587                                        macid("{daemon_flags}"),
588                                        Daemons[curdaemon].d_mflags);
589                        else
590                                macdefine(&BlankEnvelope.e_macro, A_PERM,
591                                        macid("{daemon_flags}"), "");
592                }
593
594                /*
595                **  Create a subprocess to process the mail.
596                */
597
598                if (tTd(15, 2))
599                        sm_dprintf("getrequests: forking (fd = %d)\n", t);
600
601                /*
602                **  Advance state of PRNG.
603                **  This is necessary because otherwise all child processes
604                **  will produce the same PRN sequence and hence the selection
605                **  of a queue directory (and other things, e.g., MX selection)
606                **  are not "really" random.
607                */
608#if STARTTLS
609                /* XXX get some better "random" data? */
610                seed = get_random();
611                RAND_seed((void *) &NextDiskSpaceCheck,
612                          sizeof NextDiskSpaceCheck);
613                RAND_seed((void *) &now, sizeof now);
614                RAND_seed((void *) &seed, sizeof seed);
615#else /* STARTTLS */
616                (void) get_random();
617#endif /* STARTTLS */
618
619#if NAMED_BIND
620                /*
621                **  Update MX records for FallBackMX.
622                **  Let's hope this is fast otherwise we screw up the
623                **  response time.
624                */
625
626                if (FallBackMX != NULL)
627                        (void) getfallbackmxrr(FallBackMX);
628#endif /* NAMED_BIND */
629
630                if (tTd(93, 100))
631                {
632                        /* don't fork, handle connection in this process */
633                        pid = 0;
634                        pipefd[0] = pipefd[1] = -1;
635                }
636                else
637                {
638                        /*
639                        **  Create a pipe to keep the child from writing to
640                        **  the socket until after the parent has closed
641                        **  it.  Otherwise the parent may hang if the child
642                        **  has closed it first.
643                        */
644
645                        if (pipe(pipefd) < 0)
646                                pipefd[0] = pipefd[1] = -1;
647
648                        (void) sm_blocksignal(SIGCHLD);
649                        pid = fork();
650                        if (pid < 0)
651                        {
652                                syserr("daemon: cannot fork");
653                                if (pipefd[0] != -1)
654                                {
655                                        (void) close(pipefd[0]);
656                                        (void) close(pipefd[1]);
657                                }
658                                (void) sm_releasesignal(SIGCHLD);
659                                (void) sleep(10);
660                                (void) close(t);
661                                continue;
662                        }
663                }
664
665                if (pid == 0)
666                {
667                        char *p;
668                        SM_FILE_T *inchannel, *outchannel = NULL;
669
670                        /*
671                        **  CHILD -- return to caller.
672                        **      Collect verified idea of sending host.
673                        **      Verify calling user id if possible here.
674                        */
675
676                        /* Reset global flags */
677                        RestartRequest = NULL;
678                        RestartWorkGroup = false;
679                        ShutdownRequest = NULL;
680                        PendingSignal = 0;
681                        CurrentPid = getpid();
682
683                        (void) sm_releasesignal(SIGALRM);
684                        (void) sm_releasesignal(SIGCHLD);
685                        (void) sm_signal(SIGCHLD, SIG_DFL);
686                        (void) sm_signal(SIGHUP, SIG_DFL);
687                        (void) sm_signal(SIGTERM, intsig);
688
689                        /* turn on profiling */
690                        /* SM_PROF(0); */
691
692                        /*
693                        **  Initialize exception stack and default exception
694                        **  handler for child process.
695                        */
696
697                        sm_exc_newthread(fatal_error);
698
699                        if (!control)
700                        {
701                                macdefine(&BlankEnvelope.e_macro, A_TEMP,
702                                        macid("{daemon_addr}"),
703                                        anynet_ntoa(&Daemons[curdaemon].d_addr));
704                                (void) sm_snprintf(status, sizeof status, "%d",
705                                                ntohs(Daemons[curdaemon].d_port));
706                                macdefine(&BlankEnvelope.e_macro, A_TEMP,
707                                        macid("{daemon_port}"), status);
708                        }
709
710                        for (idx = 0; idx < NDaemons; idx++)
711                        {
712                                if (Daemons[idx].d_socket >= 0)
713                                        (void) close(Daemons[idx].d_socket);
714                                Daemons[idx].d_socket = -1;
715                        }
716                        clrcontrol();
717
718                        /* Avoid SMTP daemon actions if control command */
719                        if (control)
720                        {
721                                /* Add control socket process */
722                                proc_list_add(CurrentPid,
723                                              "console socket child",
724                                              PROC_CONTROL_CHILD, 0, -1);
725                        }
726                        else
727                        {
728                                proc_list_clear();
729
730                                /* clean up background delivery children */
731                                (void) sm_signal(SIGCHLD, reapchild);
732
733                                /* Add parent process as first child item */
734                                proc_list_add(CurrentPid, "daemon child",
735                                              PROC_DAEMON_CHILD, 0, -1);
736
737                                /* don't schedule queue runs if ETRN */
738                                QueueIntvl = 0;
739
740                                sm_setproctitle(true, e, "startup with %s",
741                                                anynet_ntoa(&RealHostAddr));
742                        }
743
744                        if (pipefd[0] != -1)
745                        {
746                                auto char c;
747
748                                /*
749                                **  Wait for the parent to close the write end
750                                **  of the pipe, which we will see as an EOF.
751                                **  This guarantees that we won't write to the
752                                **  socket until after the parent has closed
753                                **  the pipe.
754                                */
755
756                                /* close the write end of the pipe */
757                                (void) close(pipefd[1]);
758
759                                /* we shouldn't be interrupted, but ... */
760                                while (read(pipefd[0], &c, 1) < 0 &&
761                                       errno == EINTR)
762                                        continue;
763                                (void) close(pipefd[0]);
764                        }
765
766                        /* control socket processing */
767                        if (control)
768                        {
769                                control_command(t, e);
770                                /* NOTREACHED */
771                                exit(EX_SOFTWARE);
772                        }
773
774                        /* determine host name */
775                        p = hostnamebyanyaddr(&RealHostAddr);
776                        if (strlen(p) > MAXNAME) /* XXX  - 1 ? */
777                                p[MAXNAME] = '\0';
778                        RealHostName = newstr(p);
779                        if (RealHostName[0] == '[')
780                        {
781                                macdefine(&BlankEnvelope.e_macro, A_PERM,
782                                        macid("{client_resolve}"),
783                                        h_errno == TRY_AGAIN ? "TEMP" : "FAIL");
784                        }
785                        else
786                                macdefine(&BlankEnvelope.e_macro, A_PERM,
787                                        macid("{client_resolve}"), "OK");
788                        sm_setproctitle(true, e, "startup with %s", p);
789                        markstats(e, NULL, STATS_CONNECT);
790
791                        if ((inchannel = sm_io_open(SmFtStdiofd,
792                                                    SM_TIME_DEFAULT,
793                                                    (void *) &t,
794                                                    SM_IO_RDONLY,
795                                                    NULL)) == NULL ||
796                            (t = dup(t)) < 0 ||
797                            (outchannel = sm_io_open(SmFtStdiofd,
798                                                     SM_TIME_DEFAULT,
799                                                     (void *) &t,
800                                                     SM_IO_WRONLY,
801                                                     NULL)) == NULL)
802                        {
803                                syserr("cannot open SMTP server channel, fd=%d",
804                                        t);
805                                finis(false, true, EX_OK);
806                        }
807                        sm_io_automode(inchannel, outchannel);
808
809                        InChannel = inchannel;
810                        OutChannel = outchannel;
811                        DisConnected = false;
812
813#if XLA
814                        if (!xla_host_ok(RealHostName))
815                        {
816                                message("421 4.4.5 Too many SMTP sessions for this host");
817                                finis(false, true, EX_OK);
818                        }
819#endif /* XLA */
820                        /* find out name for interface of connection */
821                        if (getsockname(sm_io_getinfo(InChannel, SM_IO_WHAT_FD,
822                                                      NULL), &sa.sa, &len) == 0)
823                        {
824                                p = hostnamebyanyaddr(&sa);
825                                if (tTd(15, 9))
826                                        sm_dprintf("getreq: got name %s\n", p);
827                                macdefine(&BlankEnvelope.e_macro, A_TEMP,
828                                        macid("{if_name}"), p);
829
830                                /*
831                                **  Do this only if it is not the loopback
832                                **  interface.
833                                */
834
835                                if (!isloopback(sa))
836                                {
837                                        char *addr;
838                                        char family[5];
839
840                                        addr = anynet_ntoa(&sa);
841                                        (void) sm_snprintf(family,
842                                                sizeof(family),
843                                                "%d", sa.sa.sa_family);
844                                        macdefine(&BlankEnvelope.e_macro,
845                                                A_TEMP,
846                                                macid("{if_addr}"), addr);
847                                        macdefine(&BlankEnvelope.e_macro,
848                                                A_TEMP,
849                                                macid("{if_family}"), family);
850                                        if (tTd(15, 7))
851                                                sm_dprintf("getreq: got addr %s and family %s\n",
852                                                        addr, family);
853                                }
854                                else
855                                {
856                                        macdefine(&BlankEnvelope.e_macro,
857                                                A_PERM,
858                                                macid("{if_addr}"), NULL);
859                                        macdefine(&BlankEnvelope.e_macro,
860                                                A_PERM,
861                                                macid("{if_family}"), NULL);
862                                }
863                        }
864                        else
865                        {
866                                if (tTd(15, 7))
867                                        sm_dprintf("getreq: getsockname failed\n");
868                                macdefine(&BlankEnvelope.e_macro, A_PERM,
869                                        macid("{if_name}"), NULL);
870                                macdefine(&BlankEnvelope.e_macro, A_PERM,
871                                        macid("{if_addr}"), NULL);
872                                macdefine(&BlankEnvelope.e_macro, A_PERM,
873                                        macid("{if_family}"), NULL);
874                        }
875                        break;
876                }
877
878                /* parent -- keep track of children */
879                if (control)
880                {
881                        (void) sm_snprintf(status, sizeof status,
882                                           "control socket server child");
883                        proc_list_add(pid, status, PROC_CONTROL, 0, -1);
884                }
885                else
886                {
887                        (void) sm_snprintf(status, sizeof status,
888                                           "SMTP server child for %s",
889                                           anynet_ntoa(&RealHostAddr));
890                        proc_list_add(pid, status, PROC_DAEMON, 0, -1);
891                }
892                (void) sm_releasesignal(SIGCHLD);
893
894                /* close the read end of the synchronization pipe */
895                if (pipefd[0] != -1)
896                {
897                        (void) close(pipefd[0]);
898                        pipefd[0] = -1;
899                }
900
901                /* close the port so that others will hang (for a while) */
902                (void) close(t);
903
904                /* release the child by closing the read end of the sync pipe */
905                if (pipefd[1] != -1)
906                {
907                        (void) close(pipefd[1]);
908                        pipefd[1] = -1;
909                }
910        }
911        if (tTd(15, 2))
912                sm_dprintf("getreq: returning\n");
913
914#if MILTER
915# if _FFR_MILTER_PERDAEMON
916        /* set the filters for this daemon */
917        if (Daemons[curdaemon].d_inputfilterlist != NULL)
918        {
919                for (i = 0;
920                     (i < MAXFILTERS &&
921                      Daemons[curdaemon].d_inputfilters[i] != NULL);
922                     i++)
923                {
924                        InputFilters[i] = Daemons[curdaemon].d_inputfilters[i];
925                }
926                if (i < MAXFILTERS)
927                        InputFilters[i] = NULL;
928        }
929# endif /* _FFR_MILTER_PERDAEMON */
930#endif /* MILTER */
931        return &Daemons[curdaemon].d_flags;
932}
933
934/*
935**  GETREQUESTS_CHECKDISKSPACE -- check available diskspace.
936**
937**      Parameters:
938**              e -- envelope.
939**
940**      Returns:
941**              none.
942**
943**      Side Effects:
944**              Modifies Daemon flags (D_ETRNONLY) if not enough disk space.
945*/
946
947static void
948getrequests_checkdiskspace(e)
949        ENVELOPE *e;
950{
951        bool logged = false;
952        int idx;
953        time_t now;
954
955        now = curtime();
956        if (now < NextDiskSpaceCheck)
957                return;
958
959        /* Check if there is available disk space in all queue groups. */
960        if (!enoughdiskspace(0, NULL))
961        {
962                for (idx = 0; idx < NDaemons; ++idx)
963                {
964                        if (bitnset(D_ETRNONLY, Daemons[idx].d_flags))
965                                continue;
966
967                        /* log only if not logged before */
968                        if (!logged)
969                        {
970                                if (LogLevel > 8)
971                                        sm_syslog(LOG_INFO, NOQID,
972                                                  "rejecting new messages: min free: %ld",
973                                                  MinBlocksFree);
974                                sm_setproctitle(true, e,
975                                                "rejecting new messages: min free: %ld",
976                                                MinBlocksFree);
977                                logged = true;
978                        }
979                        setbitn(D_ETRNONLY, Daemons[idx].d_flags);
980                }
981        }
982        else
983        {
984                for (idx = 0; idx < NDaemons; ++idx)
985                {
986                        if (!bitnset(D_ETRNONLY, Daemons[idx].d_flags))
987                                continue;
988
989                        /* log only if not logged before */
990                        if (!logged)
991                        {
992                                if (LogLevel > 8)
993                                        sm_syslog(LOG_INFO, NOQID,
994                                                  "accepting new messages (again)");
995                                logged = true;
996                        }
997
998                        /* title will be set later */
999                        clrbitn(D_ETRNONLY, Daemons[idx].d_flags);
1000                }
1001        }
1002
1003        /* only check disk space once a minute */
1004        NextDiskSpaceCheck = now + 60;
1005}
1006
1007/*
1008**  OPENDAEMONSOCKET -- open SMTP socket
1009**
1010**      Deals with setting all appropriate options.
1011**
1012**      Parameters:
1013**              d -- the structure for the daemon to open.
1014**              firsttime -- set if this is the initial open.
1015**
1016**      Returns:
1017**              Size in bytes of the daemon socket addr.
1018**
1019**      Side Effects:
1020**              Leaves DaemonSocket set to the open socket.
1021**              Exits if the socket cannot be created.
1022*/
1023
1024#define MAXOPENTRIES    10      /* maximum number of tries to open connection */
1025
1026static int
1027opendaemonsocket(d, firsttime)
1028        DAEMON_T *d;
1029        bool firsttime;
1030{
1031        int on = 1;
1032        int fdflags;
1033        SOCKADDR_LEN_T socksize = 0;
1034        int ntries = 0;
1035        int save_errno;
1036
1037        if (tTd(15, 2))
1038                sm_dprintf("opendaemonsocket(%s)\n", d->d_name);
1039
1040        do
1041        {
1042                if (ntries > 0)
1043                        (void) sleep(5);
1044                if (firsttime || d->d_socket < 0)
1045                {
1046#if _FFR_DAEMON_NETUNIX
1047# if NETUNIX
1048                        if (d->d_addr.sa.sa_family == AF_UNIX)
1049                        {
1050                                int rval;
1051                                long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK|SFF_CREAT;
1052
1053                                /* if not safe, don't use it */
1054                                rval = safefile(d->d_addr.sunix.sun_path,
1055                                                RunAsUid, RunAsGid,
1056                                                RunAsUserName, sff,
1057                                                S_IRUSR|S_IWUSR, NULL);
1058                                if (rval != 0)
1059                                {
1060                                        save_errno = errno;
1061                                        syserr("opendaemonsocket: daemon %s: unsafe domain socket %s",
1062                                               d->d_name,
1063                                               d->d_addr.sunix.sun_path);
1064                                        goto fail;
1065                                }
1066
1067                                /* Don't try to overtake an existing socket */
1068                                (void) unlink(d->d_addr.sunix.sun_path);
1069                        }
1070# endif /* NETUNIX */
1071#endif /* _FFR_DOMAIN_NETUNIX */
1072                        d->d_socket = socket(d->d_addr.sa.sa_family,
1073                                             SOCK_STREAM, 0);
1074                        if (d->d_socket < 0)
1075                        {
1076                                save_errno = errno;
1077                                syserr("opendaemonsocket: daemon %s: can't create server SMTP socket",
1078                                       d->d_name);
1079                          fail:
1080                                if (bitnset(D_OPTIONAL, d->d_flags) &&
1081                                    (!transienterror(save_errno) ||
1082                                     ntries >= MAXOPENTRIES - 1))
1083                                {
1084                                        syserr("opendaemonsocket: daemon %s: optional socket disabled",
1085                                               d->d_name);
1086                                        setbitn(D_DISABLE, d->d_flags);
1087                                        d->d_socket = -1;
1088                                        return -1;
1089                                }
1090                          severe:
1091                                if (LogLevel > 0)
1092                                        sm_syslog(LOG_ALERT, NOQID,
1093                                                  "daemon %s: problem creating SMTP socket",
1094                                                  d->d_name);
1095                                d->d_socket = -1;
1096                                continue;
1097                        }
1098
1099                        if (SM_FD_SETSIZE > 0 && d->d_socket >= SM_FD_SETSIZE)
1100                        {
1101                                save_errno = EINVAL;
1102                                syserr("opendaemonsocket: daemon %s: server SMTP socket (%d) too large",
1103                                       d->d_name, d->d_socket);
1104                                goto fail;
1105                        }
1106
1107                        /* turn on network debugging? */
1108                        if (tTd(15, 101))
1109                                (void) setsockopt(d->d_socket, SOL_SOCKET,
1110                                                  SO_DEBUG, (char *)&on,
1111                                                  sizeof on);
1112
1113                        (void) setsockopt(d->d_socket, SOL_SOCKET,
1114                                          SO_REUSEADDR, (char *)&on, sizeof on);
1115                        (void) setsockopt(d->d_socket, SOL_SOCKET,
1116                                          SO_KEEPALIVE, (char *)&on, sizeof on);
1117
1118#ifdef SO_RCVBUF
1119                        if (d->d_tcprcvbufsize > 0)
1120                        {
1121                                if (setsockopt(d->d_socket, SOL_SOCKET,
1122                                               SO_RCVBUF,
1123                                               (char *) &d->d_tcprcvbufsize,
1124                                               sizeof(d->d_tcprcvbufsize)) < 0)
1125                                        syserr("opendaemonsocket: daemon %s: setsockopt(SO_RCVBUF)", d->d_name);
1126                        }
1127#endif /* SO_RCVBUF */
1128#ifdef SO_SNDBUF
1129                        if (d->d_tcpsndbufsize > 0)
1130                        {
1131                                if (setsockopt(d->d_socket, SOL_SOCKET,
1132                                               SO_SNDBUF,
1133                                               (char *) &d->d_tcpsndbufsize,
1134                                               sizeof(d->d_tcpsndbufsize)) < 0)
1135                                        syserr("opendaemonsocket: daemon %s: setsockopt(SO_SNDBUF)", d->d_name);
1136                        }
1137#endif /* SO_SNDBUF */
1138
1139                        if ((fdflags = fcntl(d->d_socket, F_GETFD, 0)) == -1 ||
1140                            fcntl(d->d_socket, F_SETFD,
1141                                  fdflags | FD_CLOEXEC) == -1)
1142                        {
1143                                save_errno = errno;
1144                                syserr("opendaemonsocket: daemon %s: failed to %s close-on-exec flag: %s",
1145                                       d->d_name,
1146                                       fdflags == -1 ? "get" : "set",
1147                                       sm_errstring(save_errno));
1148                                (void) close(d->d_socket);
1149                                goto severe;
1150                        }
1151
1152                        switch (d->d_addr.sa.sa_family)
1153                        {
1154#if _FFR_DAEMON_NETUNIX
1155# ifdef NETUNIX
1156                          case AF_UNIX:
1157                                socksize = sizeof d->d_addr.sunix;
1158                                break;
1159# endif /* NETUNIX */
1160#endif /* _FFR_DAEMON_NETUNIX */
1161#if NETINET
1162                          case AF_INET:
1163                                socksize = sizeof d->d_addr.sin;
1164                                break;
1165#endif /* NETINET */
1166
1167#if NETINET6
1168                          case AF_INET6:
1169                                socksize = sizeof d->d_addr.sin6;
1170                                break;
1171#endif /* NETINET6 */
1172
1173#if NETISO
1174                          case AF_ISO:
1175                                socksize = sizeof d->d_addr.siso;
1176                                break;
1177#endif /* NETISO */
1178
1179                          default:
1180                                socksize = sizeof d->d_addr;
1181                                break;
1182                        }
1183
1184                        if (bind(d->d_socket, &d->d_addr.sa, socksize) < 0)
1185                        {
1186                                /* probably another daemon already */
1187                                save_errno = errno;
1188                                syserr("opendaemonsocket: daemon %s: cannot bind",
1189                                       d->d_name);
1190                                (void) close(d->d_socket);
1191                                goto fail;
1192                        }
1193                }
1194                if (!firsttime &&
1195                    listen(d->d_socket, d->d_listenqueue) < 0)
1196                {
1197                        save_errno = errno;
1198                        syserr("opendaemonsocket: daemon %s: cannot listen",
1199                               d->d_name);
1200                        (void) close(d->d_socket);
1201                        goto severe;
1202                }
1203                return socksize;
1204        } while (ntries++ < MAXOPENTRIES && transienterror(save_errno));
1205        syserr("!opendaemonsocket: daemon %s: server SMTP socket wedged: exiting",
1206               d->d_name);
1207        /* NOTREACHED */
1208        return -1;  /* avoid compiler warning on IRIX */
1209}
1210/*
1211**  SETUPDAEMON -- setup socket for daemon
1212**
1213**      Parameters:
1214**              daemonaddr -- socket for daemon
1215**
1216**      Returns:
1217**              port number on which daemon should run
1218**
1219*/
1220
1221static unsigned short
1222setupdaemon(daemonaddr)
1223        SOCKADDR *daemonaddr;
1224{
1225        unsigned short port;
1226
1227        /*
1228        **  Set up the address for the mailer.
1229        */
1230
1231        if (daemonaddr->sa.sa_family == AF_UNSPEC)
1232        {
1233                memset(daemonaddr, '\0', sizeof *daemonaddr);
1234#if NETINET
1235                daemonaddr->sa.sa_family = AF_INET;
1236#endif /* NETINET */
1237        }
1238
1239        switch (daemonaddr->sa.sa_family)
1240        {
1241#if NETINET
1242          case AF_INET:
1243                if (daemonaddr->sin.sin_addr.s_addr == 0)
1244                        daemonaddr->sin.sin_addr.s_addr = INADDR_ANY;
1245                port = daemonaddr->sin.sin_port;
1246                break;
1247#endif /* NETINET */
1248
1249#if NETINET6
1250          case AF_INET6:
1251                if (IN6_IS_ADDR_UNSPECIFIED(&daemonaddr->sin6.sin6_addr))
1252                        daemonaddr->sin6.sin6_addr = in6addr_any;
1253                port = daemonaddr->sin6.sin6_port;
1254                break;
1255#endif /* NETINET6 */
1256
1257          default:
1258                /* unknown protocol */
1259                port = 0;
1260                break;
1261        }
1262        if (port == 0)
1263        {
1264#ifdef NO_GETSERVBYNAME
1265                port = htons(25);
1266#else /* NO_GETSERVBYNAME */
1267                {
1268                        register struct servent *sp;
1269
1270                        sp = getservbyname("smtp", "tcp");
1271                        if (sp == NULL)
1272                        {
1273                                syserr("554 5.3.5 service \"smtp\" unknown");
1274                                port = htons(25);
1275                        }
1276                        else
1277                                port = sp->s_port;
1278                }
1279#endif /* NO_GETSERVBYNAME */
1280        }
1281
1282        switch (daemonaddr->sa.sa_family)
1283        {
1284#if NETINET
1285          case AF_INET:
1286                daemonaddr->sin.sin_port = port;
1287                break;
1288#endif /* NETINET */
1289
1290#if NETINET6
1291          case AF_INET6:
1292                daemonaddr->sin6.sin6_port = port;
1293                break;
1294#endif /* NETINET6 */
1295
1296          default:
1297                /* unknown protocol */
1298                break;
1299        }
1300        return port;
1301}
1302/*
1303**  CLRDAEMON -- reset the daemon connection
1304**
1305**      Parameters:
1306**              none.
1307**
1308**      Returns:
1309**              none.
1310**
1311**      Side Effects:
1312**              releases any resources used by the passive daemon.
1313*/
1314
1315void
1316clrdaemon()
1317{
1318        int i;
1319
1320        for (i = 0; i < NDaemons; i++)
1321        {
1322                if (Daemons[i].d_socket >= 0)
1323                        (void) close(Daemons[i].d_socket);
1324                Daemons[i].d_socket = -1;
1325        }
1326}
1327
1328/*
1329**  GETMODIFIERS -- get modifier flags
1330**
1331**      Parameters:
1332**              v -- the modifiers (input text line).
1333**              modifiers -- pointer to flag field to represent modifiers.
1334**
1335**      Returns:
1336**              (xallocat()ed) string representation of modifiers.
1337**
1338**      Side Effects:
1339**              fills in modifiers.
1340*/
1341
1342char *
1343getmodifiers(v, modifiers)
1344        char *v;
1345        BITMAP256 modifiers;
1346{
1347        int l;
1348        char *h, *f, *flags;
1349
1350        /* maximum length of flags: upper case Option -> "OO " */
1351        l = 3 * strlen(v) + 3;
1352
1353        /* is someone joking? */
1354        if (l < 0 || l > 256)
1355        {
1356                if (LogLevel > 2)
1357                        sm_syslog(LOG_ERR, NOQID,
1358                                  "getmodifiers too long, ignored");
1359                return NULL;
1360        }
1361        flags = xalloc(l);
1362        f = flags;
1363        clrbitmap(modifiers);
1364        for (h = v; *h != '\0'; h++)
1365        {
1366                if (isascii(*h) && !isspace(*h) && isprint(*h))
1367                {
1368                        setbitn(*h, modifiers);
1369                        if (flags != f)
1370                                *flags++ = ' ';
1371                        *flags++ = *h;
1372                        if (isupper(*h))
1373                                *flags++ = *h;
1374                }
1375        }
1376        *flags++ = '\0';
1377        return f;
1378}
1379
1380/*
1381**  CHKDAEMONMODIFIERS -- check whether all daemons have set a flag.
1382**
1383**      Parameters:
1384**              flag -- the flag to test.
1385**
1386**      Returns:
1387**              true iff all daemons have set flag.
1388*/
1389
1390bool
1391chkdaemonmodifiers(flag)
1392        int flag;
1393{
1394        int i;
1395
1396        for (i = 0; i < NDaemons; i++)
1397                if (!bitnset((char) flag, Daemons[i].d_flags))
1398                        return false;
1399        return true;
1400}
1401
1402/*
1403**  SETSOCKADDROPTIONS -- set options for SOCKADDR (daemon or client)
1404**
1405**      Parameters:
1406**              p -- the options line.
1407**              d -- the daemon structure to fill in.
1408**
1409**      Returns:
1410**              none.
1411*/
1412
1413static void
1414setsockaddroptions(p, d)
1415        register char *p;
1416        DAEMON_T *d;
1417{
1418#if NETISO
1419        short portno;
1420#endif /* NETISO */
1421        char *port = NULL;
1422        char *addr = NULL;
1423
1424#if NETINET
1425        if (d->d_addr.sa.sa_family == AF_UNSPEC)
1426                d->d_addr.sa.sa_family = AF_INET;
1427#endif /* NETINET */
1428
1429        while (p != NULL)
1430        {
1431                register char *f;
1432                register char *v;
1433
1434                while (isascii(*p) && isspace(*p))
1435                        p++;
1436                if (*p == '\0')
1437                        break;
1438                f = p;
1439                p = strchr(p, ',');
1440                if (p != NULL)
1441                        *p++ = '\0';
1442                v = strchr(f, '=');
1443                if (v == NULL)
1444                        continue;
1445                while (isascii(*++v) && isspace(*v))
1446                        continue;
1447                if (isascii(*f) && islower(*f))
1448                        *f = toupper(*f);
1449
1450                switch (*f)
1451                {
1452                  case 'F':             /* address family */
1453                        if (isascii(*v) && isdigit(*v))
1454                                d->d_addr.sa.sa_family = atoi(v);
1455#if _FFR_DAEMON_NETUNIX
1456# ifdef NETUNIX
1457                        else if (sm_strcasecmp(v, "unix") == 0 ||
1458                                 sm_strcasecmp(v, "local") == 0)
1459                                d->d_addr.sa.sa_family = AF_UNIX;
1460# endif /* NETUNIX */
1461#endif /* _FFR_DAEMON_NETUNIX */
1462#if NETINET
1463                        else if (sm_strcasecmp(v, "inet") == 0)
1464                                d->d_addr.sa.sa_family = AF_INET;
1465#endif /* NETINET */
1466#if NETINET6
1467                        else if (sm_strcasecmp(v, "inet6") == 0)
1468                                d->d_addr.sa.sa_family = AF_INET6;
1469#endif /* NETINET6 */
1470#if NETISO
1471                        else if (sm_strcasecmp(v, "iso") == 0)
1472                                d->d_addr.sa.sa_family = AF_ISO;
1473#endif /* NETISO */
1474#if NETNS
1475                        else if (sm_strcasecmp(v, "ns") == 0)
1476                                d->d_addr.sa.sa_family = AF_NS;
1477#endif /* NETNS */
1478#if NETX25
1479                        else if (sm_strcasecmp(v, "x.25") == 0)
1480                                d->d_addr.sa.sa_family = AF_CCITT;
1481#endif /* NETX25 */
1482                        else
1483                                syserr("554 5.3.5 Unknown address family %s in Family=option",
1484                                       v);
1485                        break;
1486
1487                  case 'A':             /* address */
1488                        addr = v;
1489                        break;
1490
1491#if MILTER
1492# if _FFR_MILTER_PERDAEMON
1493                  case 'I':
1494                        d->d_inputfilterlist = v;
1495                        break;
1496# endif /* _FFR_MILTER_PERDAEMON */
1497#endif /* MILTER */
1498
1499                  case 'P':             /* port */
1500                        port = v;
1501                        break;
1502
1503                  case 'L':             /* listen queue size */
1504                        d->d_listenqueue = atoi(v);
1505                        break;
1506
1507                  case 'M':             /* modifiers (flags) */
1508                        d->d_mflags = getmodifiers(v, d->d_flags);
1509                        break;
1510
1511                  case 'S':             /* send buffer size */
1512                        d->d_tcpsndbufsize = atoi(v);
1513                        break;
1514
1515                  case 'R':             /* receive buffer size */
1516                        d->d_tcprcvbufsize = atoi(v);
1517                        break;
1518
1519                  case 'N':             /* name */
1520                        d->d_name = v;
1521                        break;
1522
1523                  default:
1524                        syserr("554 5.3.5 PortOptions parameter \"%s\" unknown",
1525                               f);
1526                }
1527        }
1528
1529        /* Check addr and port after finding family */
1530        if (addr != NULL)
1531        {
1532                switch (d->d_addr.sa.sa_family)
1533                {
1534#if _FFR_DAEMON_NETUNIX
1535# if NETUNIX
1536                  case AF_UNIX:
1537                        if (strlen(addr) >= sizeof(d->d_addr.sunix.sun_path))
1538                        {
1539                                errno = ENAMETOOLONG;
1540                                syserr("setsockaddroptions: domain socket name too long: %s > %d",
1541                                       addr, sizeof(d->d_addr.sunix.sun_path));
1542                                break;
1543                        }
1544
1545                        /* file safety check done in opendaemonsocket() */
1546                        (void) memset(&d->d_addr.sunix.sun_path, '\0',
1547                                      sizeof(d->d_addr.sunix.sun_path));
1548                        (void) sm_strlcpy((char *)&d->d_addr.sunix.sun_path,
1549                                          addr,
1550                                          sizeof(d->d_addr.sunix.sun_path));
1551                        break;
1552# endif /* NETUNIX */
1553#endif  /* _FFR_DAEMON_NETUNIX */
1554#if NETINET
1555                  case AF_INET:
1556                        if (!isascii(*addr) || !isdigit(*addr) ||
1557                            ((d->d_addr.sin.sin_addr.s_addr = inet_addr(addr))
1558                             == INADDR_NONE))
1559                        {
1560                                register struct hostent *hp;
1561
1562                                hp = sm_gethostbyname(addr, AF_INET);
1563                                if (hp == NULL)
1564                                        syserr("554 5.3.0 host \"%s\" unknown",
1565                                               addr);
1566                                else
1567                                {
1568                                        while (*(hp->h_addr_list) != NULL &&
1569                                               hp->h_addrtype != AF_INET)
1570                                                hp->h_addr_list++;
1571                                        if (*(hp->h_addr_list) == NULL)
1572                                                syserr("554 5.3.0 host \"%s\" unknown",
1573                                                       addr);
1574                                        else
1575                                                memmove(&d->d_addr.sin.sin_addr,
1576                                                        *(hp->h_addr_list),
1577                                                        INADDRSZ);
1578# if NETINET6
1579                                        freehostent(hp);
1580                                        hp = NULL;
1581# endif /* NETINET6 */
1582                                }
1583                        }
1584                        break;
1585#endif /* NETINET */
1586
1587#if NETINET6
1588                  case AF_INET6:
1589                        if (anynet_pton(AF_INET6, addr,
1590                                        &d->d_addr.sin6.sin6_addr) != 1)
1591                        {
1592                                register struct hostent *hp;
1593
1594                                hp = sm_gethostbyname(addr, AF_INET6);
1595                                if (hp == NULL)
1596                                        syserr("554 5.3.0 host \"%s\" unknown",
1597                                               addr);
1598                                else
1599                                {
1600                                        while (*(hp->h_addr_list) != NULL &&
1601                                               hp->h_addrtype != AF_INET6)
1602                                                hp->h_addr_list++;
1603                                        if (*(hp->h_addr_list) == NULL)
1604                                                syserr("554 5.3.0 host \"%s\" unknown",
1605                                                       addr);
1606                                        else
1607                                                memmove(&d->d_addr.sin6.sin6_addr,
1608                                                        *(hp->h_addr_list),
1609                                                        IN6ADDRSZ);
1610                                        freehostent(hp);
1611                                        hp = NULL;
1612                                }
1613                        }
1614                        break;
1615#endif /* NETINET6 */
1616
1617                  default:
1618                        syserr("554 5.3.5 address= option unsupported for family %d",
1619                               d->d_addr.sa.sa_family);
1620                        break;
1621                }
1622        }
1623
1624        if (port != NULL)
1625        {
1626                switch (d->d_addr.sa.sa_family)
1627                {
1628#if NETINET
1629                  case AF_INET:
1630                        if (isascii(*port) && isdigit(*port))
1631                                d->d_addr.sin.sin_port = htons((unsigned short)
1632                                                     atoi((const char *) port));
1633                        else
1634                        {
1635# ifdef NO_GETSERVBYNAME
1636                                syserr("554 5.3.5 invalid port number: %s",
1637                                       port);
1638# else /* NO_GETSERVBYNAME */
1639                                register struct servent *sp;
1640
1641                                sp = getservbyname(port, "tcp");
1642                                if (sp == NULL)
1643                                        syserr("554 5.3.5 service \"%s\" unknown",
1644                                               port);
1645                                else
1646                                        d->d_addr.sin.sin_port = sp->s_port;
1647# endif /* NO_GETSERVBYNAME */
1648                        }
1649                        break;
1650#endif /* NETINET */
1651
1652#if NETINET6
1653                  case AF_INET6:
1654                        if (isascii(*port) && isdigit(*port))
1655                                d->d_addr.sin6.sin6_port = htons((unsigned short)
1656                                                                  atoi(port));
1657                        else
1658                        {
1659# ifdef NO_GETSERVBYNAME
1660                                syserr("554 5.3.5 invalid port number: %s",
1661                                       port);
1662# else /* NO_GETSERVBYNAME */
1663                                register struct servent *sp;
1664
1665                                sp = getservbyname(port, "tcp");
1666                                if (sp == NULL)
1667                                        syserr("554 5.3.5 service \"%s\" unknown",
1668                                               port);
1669                                else
1670                                        d->d_addr.sin6.sin6_port = sp->s_port;
1671# endif /* NO_GETSERVBYNAME */
1672                        }
1673                        break;
1674#endif /* NETINET6 */
1675
1676#if NETISO
1677                  case AF_ISO:
1678                        /* assume two byte transport selector */
1679                        if (isascii(*port) && isdigit(*port))
1680                                portno = htons((unsigned short) atoi(port));
1681                        else
1682                        {
1683# ifdef NO_GETSERVBYNAME
1684                                syserr("554 5.3.5 invalid port number: %s",
1685                                       port);
1686# else /* NO_GETSERVBYNAME */
1687                                register struct servent *sp;
1688
1689                                sp = getservbyname(port, "tcp");
1690                                if (sp == NULL)
1691                                        syserr("554 5.3.5 service \"%s\" unknown",
1692                                               port);
1693                                else
1694                                        portno = sp->s_port;
1695# endif /* NO_GETSERVBYNAME */
1696                        }
1697                        memmove(TSEL(&d->d_addr.siso),
1698                                (char *) &portno, 2);
1699                        break;
1700#endif /* NETISO */
1701
1702                  default:
1703                        syserr("554 5.3.5 Port= option unsupported for family %d",
1704                               d->d_addr.sa.sa_family);
1705                        break;
1706                }
1707        }
1708}
1709/*
1710**  SETDAEMONOPTIONS -- set options for running the MTA daemon
1711**
1712**      Parameters:
1713**              p -- the options line.
1714**
1715**      Returns:
1716**              true if successful, false otherwise.
1717**
1718**      Side Effects:
1719**              increments number of daemons.
1720*/
1721
1722#define DEF_LISTENQUEUE 10
1723
1724struct dflags
1725{
1726        char    *d_name;
1727        int     d_flag;
1728};
1729
1730static struct dflags    DaemonFlags[] =
1731{
1732        { "AUTHREQ",            D_AUTHREQ       },
1733        { "BINDIF",             D_BINDIF        },
1734        { "CANONREQ",           D_CANONREQ      },
1735        { "IFNHELO",            D_IFNHELO       },
1736        { "FQMAIL",             D_FQMAIL        },
1737        { "FQRCPT",             D_FQRCPT        },
1738#if _FFR_SMTP_SSL
1739        { "SMTPS",              D_SMTPS         },
1740#endif /* _FFR_SMTP_SSL */
1741        { "UNQUALOK",           D_UNQUALOK      },
1742        { "NOAUTH",             D_NOAUTH        },
1743        { "NOCANON",            D_NOCANON       },
1744        { "NOETRN",             D_NOETRN        },
1745        { "NOTLS",              D_NOTLS         },
1746        { "ETRNONLY",           D_ETRNONLY      },
1747        { "OPTIONAL",           D_OPTIONAL      },
1748        { "DISABLE",            D_DISABLE       },
1749        { "ISSET",              D_ISSET         },
1750        { NULL,                 0               }
1751};
1752
1753static void
1754printdaemonflags(d)
1755        DAEMON_T *d;
1756{
1757        register struct dflags *df;
1758        bool first = true;
1759
1760        for (df = DaemonFlags; df->d_name != NULL; df++)
1761        {
1762                if (!bitnset(df->d_flag, d->d_flags))
1763                        continue;
1764                if (first)
1765                        (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, "<%s",
1766                                             df->d_name);
1767                else
1768                        (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, ",%s",
1769                                             df->d_name);
1770                first = false;
1771        }
1772        if (!first)
1773                (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, ">");
1774}
1775
1776bool
1777setdaemonoptions(p)
1778        register char *p;
1779{
1780        if (NDaemons >= MAXDAEMONS)
1781                return false;
1782        Daemons[NDaemons].d_socket = -1;
1783        Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE;
1784        clrbitmap(Daemons[NDaemons].d_flags);
1785        setsockaddroptions(p, &Daemons[NDaemons]);
1786
1787#if MILTER
1788# if _FFR_MILTER_PERDAEMON
1789        if (Daemons[NDaemons].d_inputfilterlist != NULL)
1790                Daemons[NDaemons].d_inputfilterlist = newstr(Daemons[NDaemons].d_inputfilterlist);
1791# endif /* _FFR_MILTER_PERDAEMON */
1792#endif /* MILTER */
1793
1794        if (Daemons[NDaemons].d_name != NULL)
1795                Daemons[NDaemons].d_name = newstr(Daemons[NDaemons].d_name);
1796        else
1797        {
1798                char num[30];
1799
1800                (void) sm_snprintf(num, sizeof num, "Daemon%d", NDaemons);
1801                Daemons[NDaemons].d_name = newstr(num);
1802        }
1803
1804        if (tTd(37, 1))
1805        {
1806                sm_dprintf("Daemon %s flags: ", Daemons[NDaemons].d_name);
1807                printdaemonflags(&Daemons[NDaemons]);
1808                sm_dprintf("\n");
1809        }
1810        ++NDaemons;
1811        return true;
1812}
1813/*
1814**  INITDAEMON -- initialize daemon if not yet done.
1815**
1816**      Parameters:
1817**              none
1818**
1819**      Returns:
1820**              none
1821**
1822**      Side Effects:
1823**              initializes structure for one daemon.
1824*/
1825
1826void
1827initdaemon()
1828{
1829        if (NDaemons == 0)
1830        {
1831                Daemons[NDaemons].d_socket = -1;
1832                Daemons[NDaemons].d_listenqueue = DEF_LISTENQUEUE;
1833                Daemons[NDaemons].d_name = "Daemon0";
1834                NDaemons = 1;
1835        }
1836}
1837/*
1838**  SETCLIENTOPTIONS -- set options for running the client
1839**
1840**      Parameters:
1841**              p -- the options line.
1842**
1843**      Returns:
1844**              none.
1845*/
1846
1847static DAEMON_T ClientSettings[AF_MAX + 1];
1848
1849void
1850setclientoptions(p)
1851        register char *p;
1852{
1853        int family;
1854        DAEMON_T d;
1855
1856        memset(&d, '\0', sizeof d);
1857        setsockaddroptions(p, &d);
1858
1859        /* grab what we need */
1860        family = d.d_addr.sa.sa_family;
1861        STRUCTCOPY(d, ClientSettings[family]);
1862        setbitn(D_ISSET, ClientSettings[family].d_flags); /* mark as set */
1863        if (d.d_name != NULL)
1864                ClientSettings[family].d_name = newstr(d.d_name);
1865        else
1866        {
1867                char num[30];
1868
1869                (void) sm_snprintf(num, sizeof num, "Client%d", family);
1870                ClientSettings[family].d_name = newstr(num);
1871        }
1872}
1873/*
1874**  ADDR_FAMILY -- determine address family from address
1875**
1876**      Parameters:
1877**              addr -- the string representation of the address
1878**
1879**      Returns:
1880**              AF_INET, AF_INET6 or AF_UNSPEC
1881**
1882**      Side Effects:
1883**              none.
1884*/
1885
1886static int
1887addr_family(addr)
1888        char *addr;
1889{
1890#if NETINET6
1891        SOCKADDR clt_addr;
1892#endif /* NETINET6 */
1893
1894#if NETINET
1895        if (inet_addr(addr) != INADDR_NONE)
1896        {
1897                if (tTd(16, 9))
1898                        sm_dprintf("addr_family(%s): INET\n", addr);
1899                return AF_INET;
1900        }
1901#endif /* NETINET */
1902#if NETINET6
1903        if (anynet_pton(AF_INET6, addr, &clt_addr.sin6.sin6_addr) == 1)
1904        {
1905                if (tTd(16, 9))
1906                        sm_dprintf("addr_family(%s): INET6\n", addr);
1907                return AF_INET6;
1908        }
1909#endif /* NETINET6 */
1910#if _FFR_DAEMON_NETUNIX
1911# if NETUNIX
1912        if (*addr == '/')
1913        {
1914                if (tTd(16, 9))
1915                        sm_dprintf("addr_family(%s): LOCAL\n", addr);
1916                return AF_UNIX;
1917        }
1918# endif /* NETUNIX */
1919#endif  /* _FFR_DAEMON_NETUNIX */
1920        if (tTd(16, 9))
1921                sm_dprintf("addr_family(%s): UNSPEC\n", addr);
1922        return AF_UNSPEC;
1923}
1924
1925/*
1926**  CHKCLIENTMODIFIERS -- check whether all clients have set a flag.
1927**
1928**      Parameters:
1929**              flag -- the flag to test.
1930**
1931**      Returns:
1932**              true iff all configured clients have set the flag.
1933*/
1934
1935bool
1936chkclientmodifiers(flag)
1937        int flag;
1938{
1939        int i;
1940        bool flagisset;
1941
1942        flagisset = false;
1943        for (i = 0; i < AF_MAX; i++)
1944        {
1945                if (bitnset(D_ISSET, ClientSettings[i].d_flags))
1946                {
1947                        if (!bitnset((char) flag, ClientSettings[i].d_flags))
1948                                return false;
1949                        flagisset = true;
1950                }
1951        }
1952        return flagisset;
1953}
1954
1955#if MILTER
1956# if _FFR_MILTER_PERDAEMON
1957/*
1958**  SETUP_DAEMON_FILTERS -- Parse per-socket filters
1959**
1960**      Parameters:
1961**              none
1962**
1963**      Returns:
1964**              none
1965*/
1966
1967void
1968setup_daemon_milters()
1969{
1970        int idx;
1971
1972        if (OpMode == MD_SMTP)
1973        {
1974                /* no need to configure the daemons */
1975                return;
1976        }
1977
1978        for (idx = 0; idx < NDaemons; idx++)
1979        {
1980                if (Daemons[idx].d_inputfilterlist != NULL)
1981                {
1982                        milter_config(Daemons[idx].d_inputfilterlist,
1983                                      Daemons[idx].d_inputfilters,
1984                                      MAXFILTERS);
1985                }
1986        }
1987}
1988# endif /* _FFR_MILTER_PERDAEMON */
1989#endif /* MILTER */
1990/*
1991**  MAKECONNECTION -- make a connection to an SMTP socket on a machine.
1992**
1993**      Parameters:
1994**              host -- the name of the host.
1995**              port -- the port number to connect to.
1996**              mci -- a pointer to the mail connection information
1997**                      structure to be filled in.
1998**              e -- the current envelope.
1999**              enough -- time at which to stop further connection attempts.
2000**                      (0 means no limit)
2001**
2002**      Returns:
2003**              An exit code telling whether the connection could be
2004**                      made and if not why not.
2005**
2006**      Side Effects:
2007**              none.
2008*/
2009
2010static jmp_buf  CtxConnectTimeout;
2011
2012SOCKADDR        CurHostAddr;            /* address of current host */
2013
2014int
2015makeconnection(host, port, mci, e, enough)
2016        char *host;
2017        volatile unsigned int port;
2018        register MCI *mci;
2019        ENVELOPE *e;
2020        time_t enough;
2021{
2022        register volatile int addrno = 0;
2023        volatile int s;
2024        register struct hostent *volatile hp = (struct hostent *) NULL;
2025        SOCKADDR addr;
2026        SOCKADDR clt_addr;
2027        int save_errno = 0;
2028        volatile SOCKADDR_LEN_T addrlen;
2029        volatile bool firstconnect;
2030        SM_EVENT *volatile ev = NULL;
2031#if NETINET6
2032        volatile bool v6found = false;
2033#endif /* NETINET6 */
2034        volatile int family = InetMode;
2035        SOCKADDR_LEN_T len;
2036        volatile SOCKADDR_LEN_T socksize = 0;
2037        volatile bool clt_bind;
2038        BITMAP256 d_flags;
2039        char *p;
2040        extern ENVELOPE BlankEnvelope;
2041
2042        /* retranslate {daemon_flags} into bitmap */
2043        clrbitmap(d_flags);
2044        if ((p = macvalue(macid("{daemon_flags}"), e)) != NULL)
2045        {
2046                for (; *p != '\0'; p++)
2047                {
2048                        if (!(isascii(*p) && isspace(*p)))
2049                                setbitn(bitidx(*p), d_flags);
2050                }
2051        }
2052
2053#if NETINET6
2054 v4retry:
2055#endif /* NETINET6 */
2056        clt_bind = false;
2057
2058        /* Set up the address for outgoing connection. */
2059        if (bitnset(D_BINDIF, d_flags) &&
2060            (p = macvalue(macid("{if_addr}"), e)) != NULL &&
2061            *p != '\0')
2062        {
2063#if NETINET6
2064                char p6[INET6_ADDRSTRLEN];
2065#endif /* NETINET6 */
2066
2067                memset(&clt_addr, '\0', sizeof clt_addr);
2068
2069                /* infer the address family from the address itself */
2070                clt_addr.sa.sa_family = addr_family(p);
2071                switch (clt_addr.sa.sa_family)
2072                {
2073#if NETINET
2074                  case AF_INET:
2075                        clt_addr.sin.sin_addr.s_addr = inet_addr(p);
2076                        if (clt_addr.sin.sin_addr.s_addr != INADDR_NONE &&
2077                            clt_addr.sin.sin_addr.s_addr != INADDR_LOOPBACK)
2078                        {
2079                                clt_bind = true;
2080                                socksize = sizeof (struct sockaddr_in);
2081                        }
2082                        break;
2083#endif /* NETINET */
2084
2085#if NETINET6
2086                  case AF_INET6:
2087                        if (inet_addr(p) != INADDR_NONE)
2088                                (void) sm_snprintf(p6, sizeof p6,
2089                                                   "IPv6:::ffff:%s", p);
2090                        else
2091                                (void) sm_strlcpy(p6, p, sizeof p6);
2092                        if (anynet_pton(AF_INET6, p6,
2093                                        &clt_addr.sin6.sin6_addr) == 1 &&
2094                            !IN6_IS_ADDR_LOOPBACK(&clt_addr.sin6.sin6_addr))
2095                        {
2096                                clt_bind = true;
2097                                socksize = sizeof (struct sockaddr_in6);
2098                        }
2099                        break;
2100#endif /* NETINET6 */
2101
2102#if 0
2103                  default:
2104                        syserr("554 5.3.5 Address= option unsupported for family %d",
2105                               clt_addr.sa.sa_family);
2106                        break;
2107#endif /* 0 */
2108                }
2109                if (clt_bind)
2110                        family = clt_addr.sa.sa_family;
2111        }
2112
2113        /* D_BINDIF not set or not available, fallback to ClientPortOptions */
2114        if (!clt_bind)
2115        {
2116                STRUCTCOPY(ClientSettings[family].d_addr, clt_addr);
2117                switch (clt_addr.sa.sa_family)
2118                {
2119#if NETINET
2120                  case AF_INET:
2121                        if (clt_addr.sin.sin_addr.s_addr == 0)
2122                                clt_addr.sin.sin_addr.s_addr = INADDR_ANY;
2123                        else
2124                                clt_bind = true;
2125                        if (clt_addr.sin.sin_port != 0)
2126                                clt_bind = true;
2127                        socksize = sizeof (struct sockaddr_in);
2128                        break;
2129#endif /* NETINET */
2130#if NETINET6
2131                  case AF_INET6:
2132                        if (IN6_IS_ADDR_UNSPECIFIED(&clt_addr.sin6.sin6_addr))
2133                                clt_addr.sin6.sin6_addr = in6addr_any;
2134                        else
2135                                clt_bind = true;
2136                        socksize = sizeof (struct sockaddr_in6);
2137                        if (clt_addr.sin6.sin6_port != 0)
2138                                clt_bind = true;
2139                        break;
2140#endif /* NETINET6 */
2141#if NETISO
2142                  case AF_ISO:
2143                        socksize = sizeof clt_addr.siso;
2144                        clt_bind = true;
2145                        break;
2146#endif /* NETISO */
2147                  default:
2148                        break;
2149                }
2150        }
2151
2152        /*
2153        **  Set up the address for the mailer.
2154        **      Accept "[a.b.c.d]" syntax for host name.
2155        */
2156
2157        SM_SET_H_ERRNO(0);
2158        errno = 0;
2159        memset(&CurHostAddr, '\0', sizeof CurHostAddr);
2160        memset(&addr, '\0', sizeof addr);
2161        SmtpPhase = mci->mci_phase = "initial connection";
2162        CurHostName = host;
2163
2164        if (host[0] == '[')
2165        {
2166                p = strchr(host, ']');
2167                if (p != NULL)
2168                {
2169#if NETINET
2170                        unsigned long hid = INADDR_NONE;
2171#endif /* NETINET */
2172#if NETINET6
2173                        struct sockaddr_in6 hid6;
2174#endif /* NETINET6 */
2175
2176                        *p = '\0';
2177#if NETINET6
2178                        memset(&hid6, '\0', sizeof hid6);
2179#endif /* NETINET6 */
2180#if NETINET
2181                        if (family == AF_INET &&
2182                            (hid = inet_addr(&host[1])) != INADDR_NONE)
2183                        {
2184                                addr.sin.sin_family = AF_INET;
2185                                addr.sin.sin_addr.s_addr = hid;
2186                        }
2187                        else
2188#endif /* NETINET */
2189#if NETINET6
2190                        if (family == AF_INET6 &&
2191                            anynet_pton(AF_INET6, &host[1],
2192                                        &hid6.sin6_addr) == 1)
2193                        {
2194                                addr.sin6.sin6_family = AF_INET6;
2195                                addr.sin6.sin6_addr = hid6.sin6_addr;
2196                        }
2197                        else
2198#endif /* NETINET6 */
2199                        {
2200                                /* try it as a host name (avoid MX lookup) */
2201                                hp = sm_gethostbyname(&host[1], family);
2202                                if (hp == NULL && p[-1] == '.')
2203                                {
2204#if NAMED_BIND
2205                                        int oldopts = _res.options;
2206
2207                                        _res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
2208#endif /* NAMED_BIND */
2209                                        p[-1] = '\0';
2210                                        hp = sm_gethostbyname(&host[1],
2211                                                              family);
2212                                        p[-1] = '.';
2213#if NAMED_BIND
2214                                        _res.options = oldopts;
2215#endif /* NAMED_BIND */
2216                                }
2217                                *p = ']';
2218                                goto gothostent;
2219                        }
2220                        *p = ']';
2221                }
2222                if (p == NULL)
2223                {
2224                        extern char MsgBuf[];
2225
2226                        usrerrenh("5.1.2",
2227                                  "553 Invalid numeric domain spec \"%s\"",
2228                                  host);
2229                        mci_setstat(mci, EX_NOHOST, "5.1.2", MsgBuf);
2230                        errno = EINVAL;
2231                        return EX_NOHOST;
2232                }
2233        }
2234        else
2235        {
2236                /* contortion to get around SGI cc complaints */
2237                {
2238                        p = &host[strlen(host) - 1];
2239                        hp = sm_gethostbyname(host, family);
2240                        if (hp == NULL && *p == '.')
2241                        {
2242#if NAMED_BIND
2243                                int oldopts = _res.options;
2244
2245                                _res.options &= ~(RES_DEFNAMES|RES_DNSRCH);
2246#endif /* NAMED_BIND */
2247                                *p = '\0';
2248                                hp = sm_gethostbyname(host, family);
2249                                *p = '.';
2250#if NAMED_BIND
2251                                _res.options = oldopts;
2252#endif /* NAMED_BIND */
2253                        }
2254                }
2255gothostent:
2256                if (hp == NULL)
2257                {
2258#if NAMED_BIND
2259                        /* check for name server timeouts */
2260# if NETINET6
2261                        if (WorkAroundBrokenAAAA && family == AF_INET6 &&
2262                            errno == ETIMEDOUT)
2263                        {
2264                                /*
2265                                **  An attempt with family AF_INET may
2266                                **  succeed By skipping the next section
2267                                **  of code, we will try AF_INET before
2268                                **  failing.
2269                                */
2270
2271                                if (tTd(16, 10))
2272                                        sm_dprintf("makeconnection: WorkAroundBrokenAAAA: Trying AF_INET lookup (AF_INET6 failed)\n");
2273                        }
2274                        else
2275# endif /* NETINET6 */
2276                        {
2277                                if (errno == ETIMEDOUT ||
2278                                    h_errno == TRY_AGAIN ||
2279                                    (errno == ECONNREFUSED && UseNameServer))
2280                                {
2281                                        save_errno = errno;
2282                                        mci_setstat(mci, EX_TEMPFAIL,
2283                                                    "4.4.3", NULL);
2284                                        errno = save_errno;
2285                                        return EX_TEMPFAIL;
2286                                }
2287                        }
2288#endif /* NAMED_BIND */
2289#if NETINET6
2290                        /*
2291                        **  Try v6 first, then fall back to v4.
2292                        **  If we found a v6 address, but no v4
2293                        **  addresses, then TEMPFAIL.
2294                        */
2295
2296                        if (family == AF_INET6)
2297                        {
2298                                family = AF_INET;
2299                                goto v4retry;
2300                        }
2301                        if (v6found)
2302                                goto v6tempfail;
2303#endif /* NETINET6 */
2304                        save_errno = errno;
2305                        mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
2306                        errno = save_errno;
2307                        return EX_NOHOST;
2308                }
2309                addr.sa.sa_family = hp->h_addrtype;
2310                switch (hp->h_addrtype)
2311                {
2312#if NETINET
2313                  case AF_INET:
2314                        memmove(&addr.sin.sin_addr,
2315                                hp->h_addr,
2316                                INADDRSZ);
2317                        break;
2318#endif /* NETINET */
2319
2320#if NETINET6
2321                  case AF_INET6:
2322                        memmove(&addr.sin6.sin6_addr,
2323                                hp->h_addr,
2324                                IN6ADDRSZ);
2325                        break;
2326#endif /* NETINET6 */
2327
2328                  default:
2329                        if (hp->h_length > sizeof addr.sa.sa_data)
2330                        {
2331                                syserr("makeconnection: long sa_data: family %d len %d",
2332                                        hp->h_addrtype, hp->h_length);
2333                                mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
2334                                errno = EINVAL;
2335                                return EX_NOHOST;
2336                        }
2337                        memmove(addr.sa.sa_data, hp->h_addr, hp->h_length);
2338                        break;
2339                }
2340                addrno = 1;
2341        }
2342
2343        /*
2344        **  Determine the port number.
2345        */
2346
2347        if (port == 0)
2348        {
2349#ifdef NO_GETSERVBYNAME
2350                port = htons(25);
2351#else /* NO_GETSERVBYNAME */
2352                register struct servent *sp = getservbyname("smtp", "tcp");
2353
2354                if (sp == NULL)
2355                {
2356                        if (LogLevel > 2)
2357                                sm_syslog(LOG_ERR, NOQID,
2358                                          "makeconnection: service \"smtp\" unknown");
2359                        port = htons(25);
2360                }
2361                else
2362                        port = sp->s_port;
2363#endif /* NO_GETSERVBYNAME */
2364        }
2365
2366#if NETINET6
2367        if (addr.sa.sa_family == AF_INET6 &&
2368            IN6_IS_ADDR_V4MAPPED(&addr.sin6.sin6_addr) &&
2369            ClientSettings[AF_INET].d_addr.sa.sa_family != 0)
2370        {
2371                /*
2372                **  Ignore mapped IPv4 address since
2373                **  there is a ClientPortOptions setting
2374                **  for IPv4.
2375                */
2376
2377                goto nextaddr;
2378        }
2379#endif /* NETINET6 */
2380
2381        switch (addr.sa.sa_family)
2382        {
2383#if NETINET
2384          case AF_INET:
2385                addr.sin.sin_port = port;
2386                addrlen = sizeof (struct sockaddr_in);
2387                break;
2388#endif /* NETINET */
2389
2390#if NETINET6
2391          case AF_INET6:
2392                addr.sin6.sin6_port = port;
2393                addrlen = sizeof (struct sockaddr_in6);
2394                break;
2395#endif /* NETINET6 */
2396
2397#if NETISO
2398          case AF_ISO:
2399                /* assume two byte transport selector */
2400                memmove(TSEL((struct sockaddr_iso *) &addr), (char *) &port, 2);
2401                addrlen = sizeof (struct sockaddr_iso);
2402                break;
2403#endif /* NETISO */
2404
2405          default:
2406                syserr("Can't connect to address family %d", addr.sa.sa_family);
2407                mci_setstat(mci, EX_NOHOST, "5.1.2", NULL);
2408                errno = EINVAL;
2409#if NETINET6
2410                if (hp != NULL)
2411                        freehostent(hp);
2412#endif /* NETINET6 */
2413                return EX_NOHOST;
2414        }
2415
2416        /*
2417        **  Try to actually open the connection.
2418        */
2419
2420#if XLA
2421        /* if too many connections, don't bother trying */
2422        if (!xla_noqueue_ok(host))
2423        {
2424# if NETINET6
2425                if (hp != NULL)
2426                        freehostent(hp);
2427# endif /* NETINET6 */
2428                return EX_TEMPFAIL;
2429        }
2430#endif /* XLA */
2431
2432        firstconnect = true;
2433        for (;;)
2434        {
2435                if (tTd(16, 1))
2436                        sm_dprintf("makeconnection (%s [%s].%d (%d))\n",
2437                                   host, anynet_ntoa(&addr), ntohs(port),
2438                                   (int) addr.sa.sa_family);
2439
2440                /* save for logging */
2441                CurHostAddr = addr;
2442
2443#if HASRRESVPORT
2444                if (bitnset(M_SECURE_PORT, mci->mci_mailer->m_flags))
2445                {
2446                        int rport = IPPORT_RESERVED - 1;
2447
2448                        s = rresvport(&rport);
2449                }
2450                else
2451#endif /* HASRRESVPORT */
2452                {
2453                        s = socket(addr.sa.sa_family, SOCK_STREAM, 0);
2454                }
2455                if (s < 0)
2456                {
2457                        save_errno = errno;
2458                        syserr("makeconnection: cannot create socket");
2459#if XLA
2460                        xla_host_end(host);
2461#endif /* XLA */
2462                        mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
2463#if NETINET6
2464                        if (hp != NULL)
2465                                freehostent(hp);
2466#endif /* NETINET6 */
2467                        errno = save_errno;
2468                        return EX_TEMPFAIL;
2469                }
2470
2471#ifdef SO_SNDBUF
2472                if (ClientSettings[family].d_tcpsndbufsize > 0)
2473                {
2474                        if (setsockopt(s, SOL_SOCKET, SO_SNDBUF,
2475                                       (char *) &ClientSettings[family].d_tcpsndbufsize,
2476                                       sizeof(ClientSettings[family].d_tcpsndbufsize)) < 0)
2477                                syserr("makeconnection: setsockopt(SO_SNDBUF)");
2478                }
2479#endif /* SO_SNDBUF */
2480#ifdef SO_RCVBUF
2481                if (ClientSettings[family].d_tcprcvbufsize > 0)
2482                {
2483                        if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
2484                                       (char *) &ClientSettings[family].d_tcprcvbufsize,
2485                                       sizeof(ClientSettings[family].d_tcprcvbufsize)) < 0)
2486                                syserr("makeconnection: setsockopt(SO_RCVBUF)");
2487                }
2488#endif /* SO_RCVBUF */
2489
2490                if (tTd(16, 1))
2491                        sm_dprintf("makeconnection: fd=%d\n", s);
2492
2493                /* turn on network debugging? */
2494                if (tTd(16, 101))
2495                {
2496                        int on = 1;
2497
2498                        (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
2499                                          (char *)&on, sizeof on);
2500                }
2501                if (e->e_xfp != NULL)   /* for debugging */
2502                        (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
2503                errno = 0;              /* for debugging */
2504
2505                if (clt_bind)
2506                {
2507                        int on = 1;
2508
2509                        switch (clt_addr.sa.sa_family)
2510                        {
2511#if NETINET
2512                          case AF_INET:
2513                                if (clt_addr.sin.sin_port != 0)
2514                                        (void) setsockopt(s, SOL_SOCKET,
2515                                                          SO_REUSEADDR,
2516                                                          (char *) &on,
2517                                                          sizeof on);
2518                                break;
2519#endif /* NETINET */
2520
2521#if NETINET6
2522                          case AF_INET6:
2523                                if (clt_addr.sin6.sin6_port != 0)
2524                                        (void) setsockopt(s, SOL_SOCKET,
2525                                                          SO_REUSEADDR,
2526                                                          (char *) &on,
2527                                                          sizeof on);
2528                                break;
2529#endif /* NETINET6 */
2530                        }
2531
2532                        if (bind(s, &clt_addr.sa, socksize) < 0)
2533                        {
2534                                save_errno = errno;
2535                                (void) close(s);
2536                                errno = save_errno;
2537                                syserr("makeconnection: cannot bind socket [%s]",
2538                                       anynet_ntoa(&clt_addr));
2539#if NETINET6
2540                                if (hp != NULL)
2541                                        freehostent(hp);
2542#endif /* NETINET6 */
2543                                errno = save_errno;
2544                                return EX_TEMPFAIL;
2545                        }
2546                }
2547
2548                /*
2549                **  Linux seems to hang in connect for 90 minutes (!!!).
2550                **  Time out the connect to avoid this problem.
2551                */
2552
2553                if (setjmp(CtxConnectTimeout) == 0)
2554                {
2555                        int i;
2556
2557                        if (e->e_ntries <= 0 && TimeOuts.to_iconnect != 0)
2558                                ev = sm_setevent(TimeOuts.to_iconnect,
2559                                                 connecttimeout, 0);
2560                        else if (TimeOuts.to_connect != 0)
2561                                ev = sm_setevent(TimeOuts.to_connect,
2562                                                 connecttimeout, 0);
2563                        else
2564                                ev = NULL;
2565
2566                        switch (ConnectOnlyTo.sa.sa_family)
2567                        {
2568#if NETINET
2569                          case AF_INET:
2570                                addr.sin.sin_addr.s_addr = ConnectOnlyTo.sin.sin_addr.s_addr;
2571                                break;
2572#endif /* NETINET */
2573
2574#if NETINET6
2575                          case AF_INET6:
2576                                memmove(&addr.sin6.sin6_addr,
2577                                        &ConnectOnlyTo.sin6.sin6_addr,
2578                                        IN6ADDRSZ);
2579                                break;
2580#endif /* NETINET6 */
2581                        }
2582                        i = connect(s, (struct sockaddr *) &addr, addrlen);
2583                        save_errno = errno;
2584                        if (ev != NULL)
2585                                sm_clrevent(ev);
2586                        if (i >= 0)
2587                                break;
2588                }
2589                else
2590                        save_errno = errno;
2591
2592                /* couldn't connect.... figure out why */
2593                (void) close(s);
2594
2595                /* if running demand-dialed connection, try again */
2596                if (DialDelay > 0 && firstconnect &&
2597                    bitnset(M_DIALDELAY, mci->mci_mailer->m_flags))
2598                {
2599                        if (tTd(16, 1))
2600                                sm_dprintf("Connect failed (%s); trying again...\n",
2601                                           sm_errstring(save_errno));
2602                        firstconnect = false;
2603                        (void) sleep(DialDelay);
2604                        continue;
2605                }
2606
2607                if (LogLevel > 13)
2608                        sm_syslog(LOG_INFO, e->e_id,
2609                                  "makeconnection (%s [%s]) failed: %s",
2610                                  host, anynet_ntoa(&addr),
2611                                  sm_errstring(save_errno));
2612
2613#if NETINET6
2614nextaddr:
2615#endif /* NETINET6 */
2616                if (hp != NULL && hp->h_addr_list[addrno] != NULL &&
2617                    (enough == 0 || curtime() < enough))
2618                {
2619                        if (tTd(16, 1))
2620                                sm_dprintf("Connect failed (%s); trying new address....\n",
2621                                           sm_errstring(save_errno));
2622                        switch (addr.sa.sa_family)
2623                        {
2624#if NETINET
2625                          case AF_INET:
2626                                memmove(&addr.sin.sin_addr,
2627                                        hp->h_addr_list[addrno++],
2628                                        INADDRSZ);
2629                                break;
2630#endif /* NETINET */
2631
2632#if NETINET6
2633                          case AF_INET6:
2634                                memmove(&addr.sin6.sin6_addr,
2635                                        hp->h_addr_list[addrno++],
2636                                        IN6ADDRSZ);
2637                                break;
2638#endif /* NETINET6 */
2639
2640                          default:
2641                                memmove(addr.sa.sa_data,
2642                                        hp->h_addr_list[addrno++],
2643                                        hp->h_length);
2644                                break;
2645                        }
2646                        continue;
2647                }
2648                errno = save_errno;
2649
2650#if NETINET6
2651                if (family == AF_INET6)
2652                {
2653                        if (tTd(16, 1))
2654                                sm_dprintf("Connect failed (%s); retrying with AF_INET....\n",
2655                                           sm_errstring(save_errno));
2656                        v6found = true;
2657                        family = AF_INET;
2658                        if (hp != NULL)
2659                        {
2660                                freehostent(hp);
2661                                hp = NULL;
2662                        }
2663                        goto v4retry;
2664                }
2665        v6tempfail:
2666#endif /* NETINET6 */
2667                /* couldn't open connection */
2668#if NETINET6
2669                /* Don't clobber an already saved errno from v4retry */
2670                if (errno > 0)
2671#endif /* NETINET6 */
2672                        save_errno = errno;
2673                if (tTd(16, 1))
2674                        sm_dprintf("Connect failed (%s)\n",
2675                                   sm_errstring(save_errno));
2676#if XLA
2677                xla_host_end(host);
2678#endif /* XLA */
2679                mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL);
2680#if NETINET6
2681                if (hp != NULL)
2682                        freehostent(hp);
2683#endif /* NETINET6 */
2684                errno = save_errno;
2685                return EX_TEMPFAIL;
2686        }
2687
2688#if NETINET6
2689        if (hp != NULL)
2690        {
2691                freehostent(hp);
2692                hp = NULL;
2693        }
2694#endif /* NETINET6 */
2695
2696        /* connection ok, put it into canonical form */
2697        mci->mci_out = NULL;
2698        if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
2699                                       (void *) &s,
2700                                       SM_IO_WRONLY, NULL)) == NULL ||
2701            (s = dup(s)) < 0 ||
2702            (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
2703                                      (void *) &s,
2704                                      SM_IO_RDONLY, NULL)) == NULL)
2705        {
2706                save_errno = errno;
2707                syserr("cannot open SMTP client channel, fd=%d", s);
2708                mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
2709                if (mci->mci_out != NULL)
2710                        (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT);
2711                (void) close(s);
2712                errno = save_errno;
2713                return EX_TEMPFAIL;
2714        }
2715        sm_io_automode(mci->mci_out, mci->mci_in);
2716
2717        /* set {client_flags} */
2718        if (ClientSettings[addr.sa.sa_family].d_mflags != NULL)
2719        {
2720                macdefine(&mci->mci_macro, A_PERM,
2721                          macid("{client_flags}"),
2722                          ClientSettings[addr.sa.sa_family].d_mflags);
2723        }
2724        else
2725                macdefine(&mci->mci_macro, A_PERM,
2726                          macid("{client_flags}"), "");
2727
2728        /* "add" {client_flags} to bitmap */
2729        if (bitnset(D_IFNHELO, ClientSettings[addr.sa.sa_family].d_flags))
2730        {
2731                /* look for just this one flag */
2732                setbitn(D_IFNHELO, d_flags);
2733        }
2734
2735        /* find out name for Interface through which we connect */
2736        len = sizeof addr;
2737        if (getsockname(s, &addr.sa, &len) == 0)
2738        {
2739                char *name;
2740                char family[5];
2741
2742                macdefine(&BlankEnvelope.e_macro, A_TEMP,
2743                        macid("{if_addr_out}"), anynet_ntoa(&addr));
2744                (void) sm_snprintf(family, sizeof(family), "%d",
2745                        addr.sa.sa_family);
2746                macdefine(&BlankEnvelope.e_macro, A_TEMP,
2747                        macid("{if_family_out}"), family);
2748
2749                name = hostnamebyanyaddr(&addr);
2750                macdefine(&BlankEnvelope.e_macro, A_TEMP,
2751                        macid("{if_name_out}"), name);
2752                if (LogLevel > 11)
2753                {
2754                        /* log connection information */
2755                        sm_syslog(LOG_INFO, e->e_id,
2756                                  "SMTP outgoing connect on %.40s", name);
2757                }
2758                if (bitnset(D_IFNHELO, d_flags))
2759                {
2760                        if (name[0] != '[' && strchr(name, '.') != NULL)
2761                                mci->mci_heloname = newstr(name);
2762                }
2763        }
2764        else
2765        {
2766                macdefine(&BlankEnvelope.e_macro, A_PERM,
2767                        macid("{if_name_out}"), NULL);
2768                macdefine(&BlankEnvelope.e_macro, A_PERM,
2769                        macid("{if_addr_out}"), NULL);
2770                macdefine(&BlankEnvelope.e_macro, A_PERM,
2771                        macid("{if_family_out}"), NULL);
2772        }
2773        mci_setstat(mci, EX_OK, NULL, NULL);
2774        return EX_OK;
2775}
2776
2777static void
2778connecttimeout()
2779{
2780        /*
2781        **  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
2782        **      ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
2783        **      DOING.
2784        */
2785
2786        errno = ETIMEDOUT;
2787        longjmp(CtxConnectTimeout, 1);
2788}
2789/*
2790**  MAKECONNECTION_DS -- make a connection to a domain socket.
2791**
2792**      Parameters:
2793**              mux_path -- the path of the socket to connect to.
2794**              mci -- a pointer to the mail connection information
2795**                      structure to be filled in.
2796**
2797**      Returns:
2798**              An exit code telling whether the connection could be
2799**                      made and if not why not.
2800**
2801**      Side Effects:
2802**              none.
2803*/
2804
2805#if NETUNIX
2806int
2807makeconnection_ds(mux_path, mci)
2808        char *mux_path;
2809        register MCI *mci;
2810{
2811        int sock;
2812        int rval, save_errno;
2813        long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_ROOTOK|SFF_EXECOK;
2814        struct sockaddr_un unix_addr;
2815
2816        /* if not safe, don't connect */
2817        rval = safefile(mux_path, RunAsUid, RunAsGid, RunAsUserName,
2818                        sff, S_IRUSR|S_IWUSR, NULL);
2819
2820        if (rval != 0)
2821        {
2822                syserr("makeconnection_ds: unsafe domain socket");
2823                mci_setstat(mci, EX_TEMPFAIL, "4.3.5", NULL);
2824                errno = rval;
2825                return EX_TEMPFAIL;
2826        }
2827
2828        /* prepare address structure */
2829        memset(&unix_addr, '\0', sizeof unix_addr);
2830        unix_addr.sun_family = AF_UNIX;
2831
2832        if (strlen(mux_path) >= sizeof unix_addr.sun_path)
2833        {
2834                syserr("makeconnection_ds: domain socket name too long");
2835
2836                /* XXX why TEMPFAIL but 5.x.y ? */
2837                mci_setstat(mci, EX_TEMPFAIL, "5.3.5", NULL);
2838                errno = ENAMETOOLONG;
2839                return EX_UNAVAILABLE;
2840        }
2841        (void) sm_strlcpy(unix_addr.sun_path, mux_path,
2842                          sizeof unix_addr.sun_path);
2843
2844        /* initialize domain socket */
2845        sock = socket(AF_UNIX, SOCK_STREAM, 0);
2846        if (sock == -1)
2847        {
2848                save_errno = errno;
2849                syserr("makeconnection_ds: could not create domain socket");
2850                mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
2851                errno = save_errno;
2852                return EX_TEMPFAIL;
2853        }
2854
2855        /* connect to server */
2856        if (connect(sock, (struct sockaddr *) &unix_addr,
2857                    sizeof(unix_addr)) == -1)
2858        {
2859                save_errno = errno;
2860                syserr("Could not connect to socket %s", mux_path);
2861                mci_setstat(mci, EX_TEMPFAIL, "4.4.1", NULL);
2862                (void) close(sock);
2863                errno = save_errno;
2864                return EX_TEMPFAIL;
2865        }
2866
2867        /* connection ok, put it into canonical form */
2868        mci->mci_out = NULL;
2869        if ((mci->mci_out = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
2870                                       (void *) &sock, SM_IO_WRONLY, NULL))
2871                                        == NULL
2872            || (sock = dup(sock)) < 0 ||
2873            (mci->mci_in = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
2874                                      (void *) &sock, SM_IO_RDONLY, NULL))
2875                                        == NULL)
2876        {
2877                save_errno = errno;
2878                syserr("cannot open SMTP client channel, fd=%d", sock);
2879                mci_setstat(mci, EX_TEMPFAIL, "4.4.5", NULL);
2880                if (mci->mci_out != NULL)
2881                        (void) sm_io_close(mci->mci_out, SM_TIME_DEFAULT);
2882                (void) close(sock);
2883                errno = save_errno;
2884                return EX_TEMPFAIL;
2885        }
2886        sm_io_automode(mci->mci_out, mci->mci_in);
2887
2888        mci_setstat(mci, EX_OK, NULL, NULL);
2889        errno = 0;
2890        return EX_OK;
2891}
2892#endif /* NETUNIX */
2893/*
2894**  SHUTDOWN_DAEMON -- Performs a clean shutdown of the daemon
2895**
2896**      Parameters:
2897**              none.
2898**
2899**      Returns:
2900**              none.
2901**
2902**      Side Effects:
2903**              closes control socket, exits.
2904*/
2905
2906void
2907shutdown_daemon()
2908{
2909        int i;
2910        char *reason;
2911
2912        sm_allsignals(true);
2913
2914        reason = ShutdownRequest;
2915        ShutdownRequest = NULL;
2916        PendingSignal = 0;
2917
2918        if (LogLevel > 79)
2919                sm_syslog(LOG_DEBUG, CurEnv->e_id, "interrupt (%s)",
2920                          reason == NULL ? "implicit call" : reason);
2921
2922        FileName = NULL;
2923        closecontrolsocket(true);
2924#if XLA
2925        xla_all_end();
2926#endif /* XLA */
2927
2928        for (i = 0; i < NDaemons; i++)
2929        {
2930                if (Daemons[i].d_socket >= 0)
2931                {
2932                        (void) close(Daemons[i].d_socket);
2933                        Daemons[i].d_socket = -1;
2934
2935#if _FFR_DAEMON_NETUNIX
2936# if NETUNIX
2937                        /* Remove named sockets */
2938                        if (Daemons[i].d_addr.sa.sa_family == AF_UNIX)
2939                        {
2940                                int rval;
2941                                long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_MUSTOWN|SFF_EXECOK|SFF_CREAT;
2942
2943                                /* if not safe, don't use it */
2944                                rval = safefile(Daemons[i].d_addr.sunix.sun_path,
2945                                                RunAsUid, RunAsGid,
2946                                                RunAsUserName, sff,
2947                                                S_IRUSR|S_IWUSR, NULL);
2948                                if (rval == 0 &&
2949                                    unlink(Daemons[i].d_addr.sunix.sun_path) < 0)
2950                                {
2951                                        sm_syslog(LOG_WARNING, NOQID,
2952                                                  "Could not remove daemon %s socket: %s: %s",
2953                                                  Daemons[i].d_name,
2954                                                  Daemons[i].d_addr.sunix.sun_path,
2955                                                  sm_errstring(errno));
2956                                }
2957                        }
2958# endif /* NETUNIX */
2959#endif  /* _FFR_DAEMON_NETUNIX */
2960                }
2961        }
2962
2963        finis(false, true, EX_OK);
2964}
2965/*
2966**  RESTART_DAEMON -- Performs a clean restart of the daemon
2967**
2968**      Parameters:
2969**              none.
2970**
2971**      Returns:
2972**              none.
2973**
2974**      Side Effects:
2975**              restarts the daemon or exits if restart fails.
2976*/
2977
2978/* Make a non-DFL/IGN signal a noop */
2979#define SM_NOOP_SIGNAL(sig, old)                                \
2980do                                                              \
2981{                                                               \
2982        (old) = sm_signal((sig), sm_signal_noop);               \
2983        if ((old) == SIG_IGN || (old) == SIG_DFL)               \
2984                (void) sm_signal((sig), (old));                 \
2985} while (0)
2986
2987void
2988restart_daemon()
2989{
2990        bool drop;
2991        int i;
2992        int save_errno;
2993        char *reason;
2994        sigfunc_t ignore, oalrm, ousr1;
2995        extern int DtableSize;
2996
2997        /* clear the events to turn off SIGALRMs */
2998        sm_clear_events();
2999        sm_allsignals(true);
3000
3001        reason = RestartRequest;
3002        RestartRequest = NULL;
3003        PendingSignal = 0;
3004
3005        if (SaveArgv[0][0] != '/')
3006        {
3007                if (LogLevel > 3)
3008                        sm_syslog(LOG_INFO, NOQID,
3009                                  "could not restart: need full path");
3010                finis(false, true, EX_OSFILE);
3011                /* NOTREACHED */
3012        }
3013        if (LogLevel > 3)
3014                sm_syslog(LOG_INFO, NOQID, "restarting %s due to %s",
3015                          SaveArgv[0],
3016                          reason == NULL ? "implicit call" : reason);
3017
3018        closecontrolsocket(true);
3019#if SM_CONF_SHM
3020        cleanup_shm(DaemonPid == getpid());
3021#endif /* SM_CONF_SHM */
3022
3023        /*
3024        **  Want to drop to the user who started the process in all cases
3025        **  *but* when running as "smmsp" for the clientmqueue queue run
3026        **  daemon.  In that case, UseMSP will be true, RunAsUid should not
3027        **  be root, and RealUid should be either 0 or RunAsUid.
3028        */
3029
3030        drop = !(UseMSP && RunAsUid != 0 &&
3031                 (RealUid == 0 || RealUid == RunAsUid));
3032
3033        if (drop_privileges(drop) != EX_OK)
3034        {
3035                if (LogLevel > 0)
3036                        sm_syslog(LOG_ALERT, NOQID,
3037                                  "could not drop privileges: %s",
3038                                  sm_errstring(errno));
3039                finis(false, true, EX_OSERR);
3040                /* NOTREACHED */
3041        }
3042
3043        /* arrange for all the files to be closed */
3044        for (i = 3; i < DtableSize; i++)
3045        {
3046                register int j;
3047
3048                if ((j = fcntl(i, F_GETFD, 0)) != -1)
3049                        (void) fcntl(i, F_SETFD, j | FD_CLOEXEC);
3050        }
3051
3052        /*
3053        **  Need to allow signals before execve() to make them "harmless".
3054        **  However, the default action can be "terminate", so it isn't
3055        **  really harmless.  Setting signals to IGN will cause them to be
3056        **  ignored in the new process to, so that isn't a good alternative.
3057        */
3058
3059        SM_NOOP_SIGNAL(SIGALRM, oalrm);
3060        SM_NOOP_SIGNAL(SIGCHLD, ignore);
3061        SM_NOOP_SIGNAL(SIGHUP, ignore);
3062        SM_NOOP_SIGNAL(SIGINT, ignore);
3063        SM_NOOP_SIGNAL(SIGPIPE, ignore);
3064        SM_NOOP_SIGNAL(SIGTERM, ignore);
3065#ifdef SIGUSR1
3066        SM_NOOP_SIGNAL(SIGUSR1, ousr1);
3067#endif /* SIGUSR1 */
3068
3069        /* Turn back on signals */
3070        sm_allsignals(false);
3071
3072        (void) execve(SaveArgv[0], (ARGV_T) SaveArgv, (ARGV_T) ExternalEnviron);
3073        save_errno = errno;
3074
3075        /* block signals again and restore needed signals */
3076        sm_allsignals(true);
3077
3078        /* For finis() events */
3079        (void) sm_signal(SIGALRM, oalrm);
3080
3081#ifdef SIGUSR1
3082        /* For debugging finis() */
3083        (void) sm_signal(SIGUSR1, ousr1);
3084#endif /* SIGUSR1 */
3085
3086        errno = save_errno;
3087        if (LogLevel > 0)
3088                sm_syslog(LOG_ALERT, NOQID, "could not exec %s: %s",
3089                          SaveArgv[0], sm_errstring(errno));
3090        finis(false, true, EX_OSFILE);
3091        /* NOTREACHED */
3092}
3093/*
3094**  MYHOSTNAME -- return the name of this host.
3095**
3096**      Parameters:
3097**              hostbuf -- a place to return the name of this host.
3098**              size -- the size of hostbuf.
3099**
3100**      Returns:
3101**              A list of aliases for this host.
3102**
3103**      Side Effects:
3104**              Adds numeric codes to $=w.
3105*/
3106
3107struct hostent *
3108myhostname(hostbuf, size)
3109        char hostbuf[];
3110        int size;
3111{
3112        register struct hostent *hp;
3113
3114        if (gethostname(hostbuf, size) < 0 || hostbuf[0] == '\0')
3115                (void) sm_strlcpy(hostbuf, "localhost", size);
3116        hp = sm_gethostbyname(hostbuf, InetMode);
3117#if NETINET && NETINET6
3118        if (hp == NULL && InetMode == AF_INET6)
3119        {
3120                /*
3121                **  It's possible that this IPv6 enabled machine doesn't
3122                **  actually have any IPv6 interfaces and, therefore, no
3123                **  IPv6 addresses.  Fall back to AF_INET.
3124                */
3125
3126                hp = sm_gethostbyname(hostbuf, AF_INET);
3127        }
3128#endif /* NETINET && NETINET6 */
3129        if (hp == NULL)
3130                return NULL;
3131        if (strchr(hp->h_name, '.') != NULL || strchr(hostbuf, '.') == NULL)
3132                (void) cleanstrcpy(hostbuf, hp->h_name, size);
3133
3134#if NETINFO
3135        if (strchr(hostbuf, '.') == NULL)
3136        {
3137                char *domainname;
3138
3139                domainname = ni_propval("/locations", NULL, "resolver",
3140                                        "domain", '\0');
3141                if (domainname != NULL &&
3142                    strlen(domainname) + strlen(hostbuf) + 1 < size)
3143                        (void) sm_strlcat2(hostbuf, ".", domainname, size);
3144        }
3145#endif /* NETINFO */
3146
3147        /*
3148        **  If there is still no dot in the name, try looking for a
3149        **  dotted alias.
3150        */
3151
3152        if (strchr(hostbuf, '.') == NULL)
3153        {
3154                char **ha;
3155
3156                for (ha = hp->h_aliases; ha != NULL && *ha != NULL; ha++)
3157                {
3158                        if (strchr(*ha, '.') != NULL)
3159                        {
3160                                (void) cleanstrcpy(hostbuf, *ha, size - 1);
3161                                hostbuf[size - 1] = '\0';
3162                                break;
3163                        }
3164                }
3165        }
3166
3167        /*
3168        **  If _still_ no dot, wait for a while and try again -- it is
3169        **  possible that some service is starting up.  This can result
3170        **  in excessive delays if the system is badly configured, but
3171        **  there really isn't a way around that, particularly given that
3172        **  the config file hasn't been read at this point.
3173        **  All in all, a bit of a mess.
3174        */
3175
3176        if (strchr(hostbuf, '.') == NULL &&
3177            !getcanonname(hostbuf, size, true, NULL))
3178        {
3179                sm_syslog(LOG_CRIT, NOQID,
3180                          "My unqualified host name (%s) unknown; sleeping for retry",
3181                          hostbuf);
3182                message("My unqualified host name (%s) unknown; sleeping for retry",
3183                        hostbuf);
3184                (void) sleep(60);
3185                if (!getcanonname(hostbuf, size, true, NULL))
3186                {
3187                        sm_syslog(LOG_ALERT, NOQID,
3188                                  "unable to qualify my own domain name (%s) -- using short name",
3189                                  hostbuf);
3190                        message("WARNING: unable to qualify my own domain name (%s) -- using short name",
3191                                hostbuf);
3192                }
3193        }
3194        return hp;
3195}
3196/*
3197**  ADDRCMP -- compare two host addresses
3198**
3199**      Parameters:
3200**              hp -- hostent structure for the first address
3201**              ha -- actual first address
3202**              sa -- second address
3203**
3204**      Returns:
3205**              0 -- if ha and sa match
3206**              else -- they don't match
3207*/
3208
3209static int
3210addrcmp(hp, ha, sa)
3211        struct hostent *hp;
3212        char *ha;
3213        SOCKADDR *sa;
3214{
3215#if NETINET6
3216        unsigned char *a;
3217#endif /* NETINET6 */
3218
3219        switch (sa->sa.sa_family)
3220        {
3221#if NETINET
3222          case AF_INET:
3223                if (hp->h_addrtype == AF_INET)
3224                        return memcmp(ha, (char *) &sa->sin.sin_addr, INADDRSZ);
3225                break;
3226#endif /* NETINET */
3227
3228#if NETINET6
3229          case AF_INET6:
3230                a = (unsigned char *) &sa->sin6.sin6_addr;
3231
3232                /* Straight binary comparison */
3233                if (hp->h_addrtype == AF_INET6)
3234                        return memcmp(ha, a, IN6ADDRSZ);
3235
3236                /* If IPv4-mapped IPv6 address, compare the IPv4 section */
3237                if (hp->h_addrtype == AF_INET &&
3238                    IN6_IS_ADDR_V4MAPPED(&sa->sin6.sin6_addr))
3239                        return memcmp(a + IN6ADDRSZ - INADDRSZ, ha, INADDRSZ);
3240                break;
3241#endif /* NETINET6 */
3242        }
3243        return -1;
3244}
3245/*
3246**  GETAUTHINFO -- get the real host name associated with a file descriptor
3247**
3248**      Uses RFC1413 protocol to try to get info from the other end.
3249**
3250**      Parameters:
3251**              fd -- the descriptor
3252**              may_be_forged -- an outage that is set to true if the
3253**                      forward lookup of RealHostName does not match
3254**                      RealHostAddr; set to false if they do match.
3255**
3256**      Returns:
3257**              The user@host information associated with this descriptor.
3258*/
3259
3260static jmp_buf  CtxAuthTimeout;
3261
3262static void
3263authtimeout()
3264{
3265        /*
3266        **  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
3267        **      ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
3268        **      DOING.
3269        */
3270
3271        errno = ETIMEDOUT;
3272        longjmp(CtxAuthTimeout, 1);
3273}
3274
3275char *
3276getauthinfo(fd, may_be_forged)
3277        int fd;
3278        bool *may_be_forged;
3279{
3280        unsigned short SM_NONVOLATILE port = 0;
3281        SOCKADDR_LEN_T falen;
3282        register char *volatile p = NULL;
3283        SOCKADDR la;
3284        SOCKADDR_LEN_T lalen;
3285#ifndef NO_GETSERVBYNAME
3286        register struct servent *sp;
3287# if NETINET
3288        static unsigned short port4 = 0;
3289# endif /* NETINET */
3290# if NETINET6
3291        static unsigned short port6 = 0;
3292# endif /* NETINET6 */
3293#endif /* ! NO_GETSERVBYNAME */
3294        volatile int s;
3295        int i = 0;
3296        size_t len;
3297        SM_EVENT *ev;
3298        int nleft;
3299        struct hostent *hp;
3300        char *ostype = NULL;
3301        char **ha;
3302        char ibuf[MAXNAME + 1];
3303        static char hbuf[MAXNAME + MAXAUTHINFO + 11];
3304
3305        *may_be_forged = false;
3306        falen = sizeof RealHostAddr;
3307        if (isatty(fd) || (i = getpeername(fd, &RealHostAddr.sa, &falen)) < 0 ||
3308            falen <= 0 || RealHostAddr.sa.sa_family == 0)
3309        {
3310                if (i < 0)
3311                {
3312                        /*
3313                        **  ENOTSOCK is OK: bail on anything else, but reset
3314                        **  errno in this case, so a mis-report doesn't
3315                        **  happen later.
3316                        */
3317
3318                        if (errno != ENOTSOCK)
3319                                return NULL;
3320                        errno = 0;
3321                }
3322                (void) sm_strlcpyn(hbuf, sizeof hbuf, 2, RealUserName,
3323                                   "@localhost");
3324                if (tTd(9, 1))
3325                        sm_dprintf("getauthinfo: %s\n", hbuf);
3326                return hbuf;
3327        }
3328
3329        if (RealHostName == NULL)
3330        {
3331                /* translate that to a host name */
3332                RealHostName = newstr(hostnamebyanyaddr(&RealHostAddr));
3333                if (strlen(RealHostName) > MAXNAME)
3334                        RealHostName[MAXNAME] = '\0'; /* XXX - 1 ? */
3335        }
3336
3337        /* cross check RealHostName with forward DNS lookup */
3338        if (anynet_ntoa(&RealHostAddr)[0] != '[' &&
3339            RealHostName[0] != '[')
3340        {
3341                int family;
3342
3343                family = RealHostAddr.sa.sa_family;
3344#if NETINET6 && NEEDSGETIPNODE
3345                /*
3346                **  If RealHostAddr is an IPv6 connection with an
3347                **  IPv4-mapped address, we need RealHostName's IPv4
3348                **  address(es) for addrcmp() to compare against
3349                **  RealHostAddr.
3350                **
3351                **  Actually, we only need to do this for systems
3352                **  which NEEDSGETIPNODE since the real getipnodebyname()
3353                **  already does V4MAPPED address via the AI_V4MAPPEDCFG
3354                **  flag.  A better fix to this problem is to add this
3355                **  functionality to our stub getipnodebyname().
3356                */
3357
3358                if (family == AF_INET6 &&
3359                    IN6_IS_ADDR_V4MAPPED(&RealHostAddr.sin6.sin6_addr))
3360                        family = AF_INET;
3361#endif /* NETINET6 && NEEDSGETIPNODE */
3362
3363                /* try to match the reverse against the forward lookup */
3364                hp = sm_gethostbyname(RealHostName, family);
3365                if (hp == NULL)
3366                        *may_be_forged = true;
3367                else
3368                {
3369                        for (ha = hp->h_addr_list; *ha != NULL; ha++)
3370                        {
3371                                if (addrcmp(hp, *ha, &RealHostAddr) == 0)
3372                                        break;
3373                        }
3374                        *may_be_forged = *ha == NULL;
3375#if NETINET6
3376                        freehostent(hp);
3377                        hp = NULL;
3378#endif /* NETINET6 */
3379                }
3380        }
3381
3382        if (TimeOuts.to_ident == 0)
3383                goto noident;
3384
3385        lalen = sizeof la;
3386        switch (RealHostAddr.sa.sa_family)
3387        {
3388#if NETINET
3389          case AF_INET:
3390                if (getsockname(fd, &la.sa, &lalen) < 0 ||
3391                    lalen <= 0 ||
3392                    la.sa.sa_family != AF_INET)
3393                {
3394                        /* no ident info */
3395                        goto noident;
3396                }
3397                port = RealHostAddr.sin.sin_port;
3398
3399                /* create ident query */
3400                (void) sm_snprintf(ibuf, sizeof ibuf, "%d,%d\r\n",
3401                                ntohs(RealHostAddr.sin.sin_port),
3402                                ntohs(la.sin.sin_port));
3403
3404                /* create local address */
3405                la.sin.sin_port = 0;
3406
3407                /* create foreign address */
3408# ifdef NO_GETSERVBYNAME
3409                RealHostAddr.sin.sin_port = htons(113);
3410# else /* NO_GETSERVBYNAME */
3411
3412                /*
3413                **  getservbyname() consumes about 5% of the time
3414                **  when receiving a small message (almost all of the time
3415                **  spent in this routine).
3416                **  Hence we store the port in a static variable
3417                **  to save this time.
3418                **  The portnumber shouldn't change very often...
3419                **  This code makes the assumption that the port number
3420                **  is not 0.
3421                */
3422
3423                if (port4 == 0)
3424                {
3425                        sp = getservbyname("auth", "tcp");
3426                        if (sp != NULL)
3427                                port4 = sp->s_port;
3428                        else
3429                                port4 = htons(113);
3430                }
3431                RealHostAddr.sin.sin_port = port4;
3432                break;
3433# endif /* NO_GETSERVBYNAME */
3434#endif /* NETINET */
3435
3436#if NETINET6
3437          case AF_INET6:
3438                if (getsockname(fd, &la.sa, &lalen) < 0 ||
3439                    lalen <= 0 ||
3440                    la.sa.sa_family != AF_INET6)
3441                {
3442                        /* no ident info */
3443                        goto noident;
3444                }
3445                port = RealHostAddr.sin6.sin6_port;
3446
3447                /* create ident query */
3448                (void) sm_snprintf(ibuf, sizeof ibuf, "%d,%d\r\n",
3449                                ntohs(RealHostAddr.sin6.sin6_port),
3450                                ntohs(la.sin6.sin6_port));
3451
3452                /* create local address */
3453                la.sin6.sin6_port = 0;
3454
3455                /* create foreign address */
3456# ifdef NO_GETSERVBYNAME
3457                RealHostAddr.sin6.sin6_port = htons(113);
3458# else /* NO_GETSERVBYNAME */
3459                if (port6 == 0)
3460                {
3461                        sp = getservbyname("auth", "tcp");
3462                        if (sp != NULL)
3463                                port6 = sp->s_port;
3464                        else
3465                                port6 = htons(113);
3466                }
3467                RealHostAddr.sin6.sin6_port = port6;
3468                break;
3469# endif /* NO_GETSERVBYNAME */
3470#endif /* NETINET6 */
3471          default:
3472                /* no ident info */
3473                goto noident;
3474        }
3475
3476        s = -1;
3477        if (setjmp(CtxAuthTimeout) != 0)
3478        {
3479                if (s >= 0)
3480                        (void) close(s);
3481                goto noident;
3482        }
3483
3484        /* put a timeout around the whole thing */
3485        ev = sm_setevent(TimeOuts.to_ident, authtimeout, 0);
3486
3487        /* connect to foreign IDENT server using same address as SMTP socket */
3488        s = socket(la.sa.sa_family, SOCK_STREAM, 0);
3489        if (s < 0)
3490        {
3491                sm_clrevent(ev);
3492                goto noident;
3493        }
3494        if (bind(s, &la.sa, lalen) < 0 ||
3495            connect(s, &RealHostAddr.sa, lalen) < 0)
3496                goto closeident;
3497
3498        if (tTd(9, 10))
3499                sm_dprintf("getauthinfo: sent %s", ibuf);
3500
3501        /* send query */
3502        if (write(s, ibuf, strlen(ibuf)) < 0)
3503                goto closeident;
3504
3505        /* get result */
3506        p = &ibuf[0];
3507        nleft = sizeof ibuf - 1;
3508        while ((i = read(s, p, nleft)) > 0)
3509        {
3510                p += i;
3511                nleft -= i;
3512                *p = '\0';
3513                if (strchr(ibuf, '\n') != NULL || nleft <= 0)
3514                        break;
3515        }
3516        (void) close(s);
3517        sm_clrevent(ev);
3518        if (i < 0 || p == &ibuf[0])
3519                goto noident;
3520
3521        if (p >= &ibuf[2] && *--p == '\n' && *--p == '\r')
3522                p--;
3523        *++p = '\0';
3524
3525        if (tTd(9, 3))
3526                sm_dprintf("getauthinfo:  got %s\n", ibuf);
3527
3528        /* parse result */
3529        p = strchr(ibuf, ':');
3530        if (p == NULL)
3531        {
3532                /* malformed response */
3533                goto noident;
3534        }
3535        while (isascii(*++p) && isspace(*p))
3536                continue;
3537        if (sm_strncasecmp(p, "userid", 6) != 0)
3538        {
3539                /* presumably an error string */
3540                goto noident;
3541        }
3542        p += 6;
3543        while (isascii(*p) && isspace(*p))
3544                p++;
3545        if (*p++ != ':')
3546        {
3547                /* either useridxx or malformed response */
3548                goto noident;
3549        }
3550
3551        /* p now points to the OSTYPE field */
3552        while (isascii(*p) && isspace(*p))
3553                p++;
3554        ostype = p;
3555        p = strchr(p, ':');
3556        if (p == NULL)
3557        {
3558                /* malformed response */
3559                goto noident;
3560        }
3561        else
3562        {
3563                char *charset;
3564
3565                *p = '\0';
3566                charset = strchr(ostype, ',');
3567                if (charset != NULL)
3568                        *charset = '\0';
3569        }
3570
3571        /* 1413 says don't do this -- but it's broken otherwise */
3572        while (isascii(*++p) && isspace(*p))
3573                continue;
3574
3575        /* p now points to the authenticated name -- copy carefully */
3576        if (sm_strncasecmp(ostype, "other", 5) == 0 &&
3577            (ostype[5] == ' ' || ostype[5] == '\0'))
3578        {
3579                (void) sm_strlcpy(hbuf, "IDENT:", sizeof hbuf);
3580                cleanstrcpy(&hbuf[6], p, MAXAUTHINFO);
3581        }
3582        else
3583                cleanstrcpy(hbuf, p, MAXAUTHINFO);
3584        len = strlen(hbuf);
3585        (void) sm_strlcpyn(&hbuf[len], sizeof hbuf - len, 2, "@",
3586                           RealHostName == NULL ? "localhost" : RealHostName);
3587        goto postident;
3588
3589closeident:
3590        (void) close(s);
3591        sm_clrevent(ev);
3592
3593noident:
3594        /* put back the original incoming port */
3595        switch (RealHostAddr.sa.sa_family)
3596        {
3597#if NETINET
3598          case AF_INET:
3599                if (port > 0)
3600                        RealHostAddr.sin.sin_port = port;
3601                break;
3602#endif /* NETINET */
3603
3604#if NETINET6
3605          case AF_INET6:
3606                if (port > 0)
3607                        RealHostAddr.sin6.sin6_port = port;
3608                break;
3609#endif /* NETINET6 */
3610        }
3611
3612        if (RealHostName == NULL)
3613        {
3614                if (tTd(9, 1))
3615                        sm_dprintf("getauthinfo: NULL\n");
3616                return NULL;
3617        }
3618        (void) sm_strlcpy(hbuf, RealHostName, sizeof hbuf);
3619
3620postident:
3621#if IP_SRCROUTE
3622# ifndef GET_IPOPT_DST
3623#  define GET_IPOPT_DST(dst)    (dst)
3624# endif /* ! GET_IPOPT_DST */
3625        /*
3626        **  Extract IP source routing information.
3627        **
3628        **      Format of output for a connection from site a through b
3629        **      through c to d:
3630        **              loose:      @site-c@site-b:site-a
3631        **              strict:    !@site-c@site-b:site-a
3632        **
3633        **      o - pointer within ipopt_list structure.
3634        **      q - pointer within ls/ss rr route data
3635        **      p - pointer to hbuf
3636        */
3637
3638        if (RealHostAddr.sa.sa_family == AF_INET)
3639        {
3640                SOCKOPT_LEN_T ipoptlen;
3641                int j;
3642                unsigned char *q;
3643                unsigned char *o;
3644                int l;
3645                struct IPOPTION ipopt;
3646
3647                ipoptlen = sizeof ipopt;
3648                if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS,
3649                               (char *) &ipopt, &ipoptlen) < 0)
3650                        goto noipsr;
3651                if (ipoptlen == 0)
3652                        goto noipsr;
3653                o = (unsigned char *) ipopt.IP_LIST;
3654                while (o != NULL && o < (unsigned char *) &ipopt + ipoptlen)
3655                {
3656                        switch (*o)
3657                        {
3658                          case IPOPT_EOL:
3659                                o = NULL;
3660                                break;
3661
3662                          case IPOPT_NOP:
3663                                o++;
3664                                break;
3665
3666                          case IPOPT_SSRR:
3667                          case IPOPT_LSRR:
3668                                /*
3669                                **  Source routing.
3670                                **      o[0] is the option type (loose/strict).
3671                                **      o[1] is the length of this option,
3672                                **              including option type and
3673                                **              length.
3674                                **      o[2] is the pointer into the route
3675                                **              data.
3676                                **      o[3] begins the route data.
3677                                */
3678
3679                                p = &hbuf[strlen(hbuf)];
3680                                l = sizeof hbuf - (hbuf - p) - 6;
3681                                (void) sm_snprintf(p, SPACELEFT(hbuf, p),
3682                                        " [%s@%.*s",
3683                                        *o == IPOPT_SSRR ? "!" : "",
3684                                        l > 240 ? 120 : l / 2,
3685                                        inet_ntoa(GET_IPOPT_DST(ipopt.IP_DST)));
3686                                i = strlen(p);
3687                                p += i;
3688                                l -= strlen(p);
3689
3690                                j = o[1] / sizeof(struct in_addr) - 1;
3691
3692                                /* q skips length and router pointer to data */
3693                                q = &o[3];
3694                                for ( ; j >= 0; j--)
3695                                {
3696                                        struct in_addr addr;
3697
3698                                        memcpy(&addr, q, sizeof(addr));
3699                                        (void) sm_snprintf(p,
3700                                                SPACELEFT(hbuf, p),
3701                                                "%c%.*s",
3702                                                j != 0 ? '@' : ':',
3703                                                l > 240 ? 120 :
3704                                                        j == 0 ? l : l / 2,
3705                                                inet_ntoa(addr));
3706                                        i = strlen(p);
3707                                        p += i;
3708                                        l -= i + 1;
3709                                        q += sizeof(struct in_addr);
3710                                }
3711                                o += o[1];
3712                                break;
3713
3714                          default:
3715                                /* Skip over option */
3716                                o += o[1];
3717                                break;
3718                        }
3719                }
3720                (void) sm_snprintf(p, SPACELEFT(hbuf, p), "]");
3721                goto postipsr;
3722        }
3723
3724noipsr:
3725#endif /* IP_SRCROUTE */
3726        if (RealHostName != NULL && RealHostName[0] != '[')
3727        {
3728                p = &hbuf[strlen(hbuf)];
3729                (void) sm_snprintf(p, SPACELEFT(hbuf, p), " [%.100s]",
3730                                   anynet_ntoa(&RealHostAddr));
3731        }
3732        if (*may_be_forged)
3733        {
3734                p = &hbuf[strlen(hbuf)];
3735                (void) sm_strlcpy(p, " (may be forged)", SPACELEFT(hbuf, p));
3736                macdefine(&BlankEnvelope.e_macro, A_PERM,
3737                          macid("{client_resolve}"), "FORGED");
3738        }
3739
3740#if IP_SRCROUTE
3741postipsr:
3742#endif /* IP_SRCROUTE */
3743
3744        /* put back the original incoming port */
3745        switch (RealHostAddr.sa.sa_family)
3746        {
3747#if NETINET
3748          case AF_INET:
3749                if (port > 0)
3750                        RealHostAddr.sin.sin_port = port;
3751                break;
3752#endif /* NETINET */
3753
3754#if NETINET6
3755          case AF_INET6:
3756                if (port > 0)
3757                        RealHostAddr.sin6.sin6_port = port;
3758                break;
3759#endif /* NETINET6 */
3760        }
3761
3762        if (tTd(9, 1))
3763                sm_dprintf("getauthinfo: %s\n", hbuf);
3764        return hbuf;
3765}
3766/*
3767**  HOST_MAP_LOOKUP -- turn a hostname into canonical form
3768**
3769**      Parameters:
3770**              map -- a pointer to this map.
3771**              name -- the (presumably unqualified) hostname.
3772**              av -- unused -- for compatibility with other mapping
3773**                      functions.
3774**              statp -- an exit status (out parameter) -- set to
3775**                      EX_TEMPFAIL if the name server is unavailable.
3776**
3777**      Returns:
3778**              The mapping, if found.
3779**              NULL if no mapping found.
3780**
3781**      Side Effects:
3782**              Looks up the host specified in hbuf.  If it is not
3783**              the canonical name for that host, return the canonical
3784**              name (unless MF_MATCHONLY is set, which will cause the
3785**              status only to be returned).
3786*/
3787
3788char *
3789host_map_lookup(map, name, av, statp)
3790        MAP *map;
3791        char *name;
3792        char **av;
3793        int *statp;
3794{
3795        register struct hostent *hp;
3796#if NETINET
3797        struct in_addr in_addr;
3798#endif /* NETINET */
3799#if NETINET6
3800        struct in6_addr in6_addr;
3801#endif /* NETINET6 */
3802        char *cp, *ans = NULL;
3803        register STAB *s;
3804        time_t now;
3805#if NAMED_BIND
3806        time_t SM_NONVOLATILE retrans = 0;
3807        int SM_NONVOLATILE retry = 0;
3808#endif /* NAMED_BIND */
3809        char hbuf[MAXNAME + 1];
3810
3811        /*
3812        **  See if we have already looked up this name.  If so, just
3813        **  return it (unless expired).
3814        */
3815
3816        now = curtime();
3817        s = stab(name, ST_NAMECANON, ST_ENTER);
3818        if (bitset(NCF_VALID, s->s_namecanon.nc_flags) &&
3819            s->s_namecanon.nc_exp >= now)
3820        {
3821                if (tTd(9, 1))
3822                        sm_dprintf("host_map_lookup(%s) => CACHE %s\n",
3823                                    name,
3824                                    s->s_namecanon.nc_cname == NULL
3825                                        ? "NULL"
3826                                        : s->s_namecanon.nc_cname);
3827                errno = s->s_namecanon.nc_errno;
3828                SM_SET_H_ERRNO(s->s_namecanon.nc_herrno);
3829                *statp = s->s_namecanon.nc_stat;
3830                if (*statp == EX_TEMPFAIL)
3831                {
3832                        CurEnv->e_status = "4.4.3";
3833                        message("851 %s: Name server timeout",
3834                                shortenstring(name, 33));
3835                }
3836                if (*statp != EX_OK)
3837                        return NULL;
3838                if (s->s_namecanon.nc_cname == NULL)
3839                {
3840                        syserr("host_map_lookup(%s): bogus NULL cache entry, errno = %d, h_errno = %d",
3841                               name,
3842                               s->s_namecanon.nc_errno,
3843                               s->s_namecanon.nc_herrno);
3844                        return NULL;
3845                }
3846                if (bitset(MF_MATCHONLY, map->map_mflags))
3847                        cp = map_rewrite(map, name, strlen(name), NULL);
3848                else
3849                        cp = map_rewrite(map,
3850                                         s->s_namecanon.nc_cname,
3851                                         strlen(s->s_namecanon.nc_cname),
3852                                         av);
3853                return cp;
3854        }
3855
3856        /*
3857        **  If we are running without a regular network connection (usually
3858        **  dial-on-demand) and we are just queueing, we want to avoid DNS
3859        **  lookups because those could try to connect to a server.
3860        */
3861
3862        if (CurEnv->e_sendmode == SM_DEFER &&
3863            bitset(MF_DEFER, map->map_mflags))
3864        {
3865                if (tTd(9, 1))
3866                        sm_dprintf("host_map_lookup(%s) => DEFERRED\n", name);
3867                *statp = EX_TEMPFAIL;
3868                return NULL;
3869        }
3870
3871        /*
3872        **  If first character is a bracket, then it is an address
3873        **  lookup.  Address is copied into a temporary buffer to
3874        **  strip the brackets and to preserve name if address is
3875        **  unknown.
3876        */
3877
3878        if (tTd(9, 1))
3879                sm_dprintf("host_map_lookup(%s) => ", name);
3880#if NAMED_BIND
3881        if (map->map_timeout > 0)
3882        {
3883                retrans = _res.retrans;
3884                _res.retrans = map->map_timeout;
3885        }
3886        if (map->map_retry > 0)
3887        {
3888                retry = _res.retry;
3889                _res.retry = map->map_retry;
3890        }
3891#endif /* NAMED_BIND */
3892
3893        /* set default TTL */
3894        s->s_namecanon.nc_exp = now + SM_DEFAULT_TTL;
3895        if (*name != '[')
3896        {
3897                int ttl;
3898
3899                (void) sm_strlcpy(hbuf, name, sizeof hbuf);
3900                if (getcanonname(hbuf, sizeof hbuf - 1, !HasWildcardMX, &ttl))
3901                {
3902                        ans = hbuf;
3903                        if (ttl > 0)
3904                                s->s_namecanon.nc_exp = now + SM_MIN(ttl,
3905                                                                SM_DEFAULT_TTL);
3906                }
3907        }
3908        else
3909        {
3910                if ((cp = strchr(name, ']')) == NULL)
3911                {
3912                        if (tTd(9, 1))
3913                                sm_dprintf("FAILED\n");
3914                        return NULL;
3915                }
3916                *cp = '\0';
3917
3918                hp = NULL;
3919#if NETINET
3920                if ((in_addr.s_addr = inet_addr(&name[1])) != INADDR_NONE)
3921                        hp = sm_gethostbyaddr((char *)&in_addr,
3922                                              INADDRSZ, AF_INET);
3923#endif /* NETINET */
3924#if NETINET6
3925                if (hp == NULL &&
3926                    anynet_pton(AF_INET6, &name[1], &in6_addr) == 1)
3927                        hp = sm_gethostbyaddr((char *)&in6_addr,
3928                                              IN6ADDRSZ, AF_INET6);
3929#endif /* NETINET6 */
3930                *cp = ']';
3931
3932                if (hp != NULL)
3933                {
3934                        /* found a match -- copy out */
3935                        ans = denlstring((char *) hp->h_name, true, true);
3936#if NETINET6
3937                        if (ans == hp->h_name)
3938                        {
3939                                static char n[MAXNAME + 1];
3940
3941                                /* hp->h_name is about to disappear */
3942                                (void) sm_strlcpy(n, ans, sizeof n);
3943                                ans = n;
3944                        }
3945                        freehostent(hp);
3946                        hp = NULL;
3947#endif /* NETINET6 */
3948                }
3949        }
3950#if NAMED_BIND
3951        if (map->map_timeout > 0)
3952                _res.retrans = retrans;
3953        if (map->map_retry > 0)
3954                _res.retry = retry;
3955#endif /* NAMED_BIND */
3956
3957        s->s_namecanon.nc_flags |= NCF_VALID;   /* will be soon */
3958
3959        /* Found an answer */
3960        if (ans != NULL)
3961        {
3962                s->s_namecanon.nc_stat = *statp = EX_OK;
3963                if (s->s_namecanon.nc_cname != NULL)
3964                        sm_free(s->s_namecanon.nc_cname);
3965                s->s_namecanon.nc_cname = sm_strdup_x(ans);
3966                if (bitset(MF_MATCHONLY, map->map_mflags))
3967                        cp = map_rewrite(map, name, strlen(name), NULL);
3968                else
3969                        cp = map_rewrite(map, ans, strlen(ans), av);
3970                if (tTd(9, 1))
3971                        sm_dprintf("FOUND %s\n", ans);
3972                return cp;
3973        }
3974
3975
3976        /* No match found */
3977        s->s_namecanon.nc_errno = errno;
3978#if NAMED_BIND
3979        s->s_namecanon.nc_herrno = h_errno;
3980        if (tTd(9, 1))
3981                sm_dprintf("FAIL (%d)\n", h_errno);
3982        switch (h_errno)
3983        {
3984          case TRY_AGAIN:
3985                if (UseNameServer)
3986                {
3987                        CurEnv->e_status = "4.4.3";
3988                        message("851 %s: Name server timeout",
3989                                shortenstring(name, 33));
3990                }
3991                *statp = EX_TEMPFAIL;
3992                break;
3993
3994          case HOST_NOT_FOUND:
3995          case NO_DATA:
3996                *statp = EX_NOHOST;
3997                break;
3998
3999          case NO_RECOVERY:
4000                *statp = EX_SOFTWARE;
4001                break;
4002
4003          default:
4004                *statp = EX_UNAVAILABLE;
4005                break;
4006        }
4007#else /* NAMED_BIND */
4008        if (tTd(9, 1))
4009                sm_dprintf("FAIL\n");
4010        *statp = EX_NOHOST;
4011#endif /* NAMED_BIND */
4012        s->s_namecanon.nc_stat = *statp;
4013        return NULL;
4014}
4015/*
4016**  HOST_MAP_INIT -- initialize host class structures
4017**
4018**      Parameters:
4019**              map -- a pointer to this map.
4020**              args -- argument string.
4021**
4022**      Returns:
4023**              true.
4024*/
4025
4026bool
4027host_map_init(map, args)
4028        MAP *map;
4029        char *args;
4030{
4031        register char *p = args;
4032
4033        for (;;)
4034        {
4035                while (isascii(*p) && isspace(*p))
4036                        p++;
4037                if (*p != '-')
4038                        break;
4039                switch (*++p)
4040                {
4041                  case 'a':
4042                        map->map_app = ++p;
4043                        break;
4044
4045                  case 'T':
4046                        map->map_tapp = ++p;
4047                        break;
4048
4049                  case 'm':
4050                        map->map_mflags |= MF_MATCHONLY;
4051                        break;
4052
4053                  case 't':
4054                        map->map_mflags |= MF_NODEFER;
4055                        break;
4056
4057                  case 'S':     /* only for consistency */
4058                        map->map_spacesub = *++p;
4059                        break;
4060
4061                  case 'D':
4062                        map->map_mflags |= MF_DEFER;
4063                        break;
4064
4065                  case 'd':
4066                        {
4067                                char *h;
4068
4069                                while (isascii(*++p) && isspace(*p))
4070                                        continue;
4071                                h = strchr(p, ' ');
4072                                if (h != NULL)
4073                                        *h = '\0';
4074                                map->map_timeout = convtime(p, 's');
4075                                if (h != NULL)
4076                                        *h = ' ';
4077                        }
4078                        break;
4079
4080                  case 'r':
4081                        while (isascii(*++p) && isspace(*p))
4082                                continue;
4083                        map->map_retry = atoi(p);
4084                        break;
4085                }
4086                while (*p != '\0' && !(isascii(*p) && isspace(*p)))
4087                        p++;
4088                if (*p != '\0')
4089                        *p++ = '\0';
4090        }
4091        if (map->map_app != NULL)
4092                map->map_app = newstr(map->map_app);
4093        if (map->map_tapp != NULL)
4094                map->map_tapp = newstr(map->map_tapp);
4095        return true;
4096}
4097
4098#if NETINET6
4099/*
4100**  ANYNET_NTOP -- convert an IPv6 network address to printable form.
4101**
4102**      Parameters:
4103**              s6a -- a pointer to an in6_addr structure.
4104**              dst -- buffer to store result in
4105**              dst_len -- size of dst buffer
4106**
4107**      Returns:
4108**              A printable version of that structure.
4109*/
4110
4111char *
4112anynet_ntop(s6a, dst, dst_len)
4113        struct in6_addr *s6a;
4114        char *dst;
4115        size_t dst_len;
4116{
4117        register char *ap;
4118
4119        if (IN6_IS_ADDR_V4MAPPED(s6a))
4120                ap = (char *) inet_ntop(AF_INET,
4121                                        &s6a->s6_addr[IN6ADDRSZ - INADDRSZ],
4122                                        dst, dst_len);
4123        else
4124        {
4125                char *d;
4126                size_t sz;
4127
4128                /* Save pointer to beginning of string */
4129                d = dst;
4130
4131                /* Add IPv6: protocol tag */
4132                sz = sm_strlcpy(dst, "IPv6:", dst_len);
4133                if (sz >= dst_len)
4134                        return NULL;
4135                dst += sz;
4136                dst_len -= sz;
4137                ap = (char *) inet_ntop(AF_INET6, s6a, dst, dst_len);
4138
4139                /* Restore pointer to beginning of string */
4140                if (ap != NULL)
4141                        ap = d;
4142        }
4143        return ap;
4144}
4145
4146/*
4147**  ANYNET_PTON -- convert printed form to network address.
4148**
4149**      Wrapper for inet_pton() which handles IPv6: labels.
4150**
4151**      Parameters:
4152**              family -- address family
4153**              src -- string
4154**              dst -- destination address structure
4155**
4156**      Returns:
4157**              1 if the address was valid
4158**              0 if the address wasn't parseable
4159**              -1 if error
4160*/
4161
4162int
4163anynet_pton(family, src, dst)
4164        int family;
4165        const char *src;
4166        void *dst;
4167{
4168        if (family == AF_INET6 && sm_strncasecmp(src, "IPv6:", 5) == 0)
4169                src += 5;
4170        return inet_pton(family, src, dst);
4171}
4172#endif /* NETINET6 */
4173/*
4174**  ANYNET_NTOA -- convert a network address to printable form.
4175**
4176**      Parameters:
4177**              sap -- a pointer to a sockaddr structure.
4178**
4179**      Returns:
4180**              A printable version of that sockaddr.
4181*/
4182
4183#ifdef USE_SOCK_STREAM
4184
4185# if NETLINK
4186#  include <net/if_dl.h>
4187# endif /* NETLINK */
4188
4189char *
4190anynet_ntoa(sap)
4191        register SOCKADDR *sap;
4192{
4193        register char *bp;
4194        register char *ap;
4195        int l;
4196        static char buf[100];
4197
4198        /* check for null/zero family */
4199        if (sap == NULL)
4200                return "NULLADDR";
4201        if (sap->sa.sa_family == 0)
4202                return "0";
4203
4204        switch (sap->sa.sa_family)
4205        {
4206# if NETUNIX
4207          case AF_UNIX:
4208                if (sap->sunix.sun_path[0] != '\0')
4209                        (void) sm_snprintf(buf, sizeof buf, "[UNIX: %.64s]",
4210                                           sap->sunix.sun_path);
4211                else
4212                        (void) sm_strlcpy(buf, "[UNIX: localhost]", sizeof buf);
4213                return buf;
4214# endif /* NETUNIX */
4215
4216# if NETINET
4217          case AF_INET:
4218                return (char *) inet_ntoa(sap->sin.sin_addr);
4219# endif /* NETINET */
4220
4221# if NETINET6
4222          case AF_INET6:
4223                ap = anynet_ntop(&sap->sin6.sin6_addr, buf, sizeof buf);
4224                if (ap != NULL)
4225                        return ap;
4226                break;
4227# endif /* NETINET6 */
4228
4229# if NETLINK
4230          case AF_LINK:
4231                (void) sm_snprintf(buf, sizeof buf, "[LINK: %s]",
4232                                   link_ntoa((struct sockaddr_dl *) &sap->sa));
4233                return buf;
4234# endif /* NETLINK */
4235          default:
4236                /* this case is needed when nothing is #defined */
4237                /* in order to keep the switch syntactically correct */
4238                break;
4239        }
4240
4241        /* unknown family -- just dump bytes */
4242        (void) sm_snprintf(buf, sizeof buf, "Family %d: ", sap->sa.sa_family);
4243        bp = &buf[strlen(buf)];
4244        ap = sap->sa.sa_data;
4245        for (l = sizeof sap->sa.sa_data; --l >= 0; )
4246        {
4247                (void) sm_snprintf(bp, SPACELEFT(buf, bp), "%02x:",
4248                                   *ap++ & 0377);
4249                bp += 3;
4250        }
4251        *--bp = '\0';
4252        return buf;
4253}
4254/*
4255**  HOSTNAMEBYANYADDR -- return name of host based on address
4256**
4257**      Parameters:
4258**              sap -- SOCKADDR pointer
4259**
4260**      Returns:
4261**              text representation of host name.
4262**
4263**      Side Effects:
4264**              none.
4265*/
4266
4267char *
4268hostnamebyanyaddr(sap)
4269        register SOCKADDR *sap;
4270{
4271        register struct hostent *hp;
4272# if NAMED_BIND
4273        int saveretry;
4274# endif /* NAMED_BIND */
4275# if NETINET6
4276        struct in6_addr in6_addr;
4277# endif /* NETINET6 */
4278
4279# if NAMED_BIND
4280        /* shorten name server timeout to avoid higher level timeouts */
4281        saveretry = _res.retry;
4282        if (_res.retry * _res.retrans > 20)
4283                _res.retry = 20 / _res.retrans;
4284# endif /* NAMED_BIND */
4285
4286        switch (sap->sa.sa_family)
4287        {
4288# if NETINET
4289          case AF_INET:
4290                hp = sm_gethostbyaddr((char *) &sap->sin.sin_addr,
4291                                      INADDRSZ, AF_INET);
4292                break;
4293# endif /* NETINET */
4294
4295# if NETINET6
4296          case AF_INET6:
4297                hp = sm_gethostbyaddr((char *) &sap->sin6.sin6_addr,
4298                                      IN6ADDRSZ, AF_INET6);
4299                break;
4300# endif /* NETINET6 */
4301
4302# if NETISO
4303          case AF_ISO:
4304                hp = sm_gethostbyaddr((char *) &sap->siso.siso_addr,
4305                                      sizeof sap->siso.siso_addr, AF_ISO);
4306                break;
4307# endif /* NETISO */
4308
4309# if NETUNIX
4310          case AF_UNIX:
4311                hp = NULL;
4312                break;
4313# endif /* NETUNIX */
4314
4315          default:
4316                hp = sm_gethostbyaddr(sap->sa.sa_data, sizeof sap->sa.sa_data,
4317                                      sap->sa.sa_family);
4318                break;
4319        }
4320
4321# if NAMED_BIND
4322        _res.retry = saveretry;
4323# endif /* NAMED_BIND */
4324
4325# if NETINET || NETINET6
4326        if (hp != NULL && hp->h_name[0] != '['
4327#  if NETINET6
4328            && inet_pton(AF_INET6, hp->h_name, &in6_addr) != 1
4329#  endif /* NETINET6 */
4330#  if NETINET
4331            && inet_addr(hp->h_name) == INADDR_NONE
4332#  endif /* NETINET */
4333            )
4334        {
4335                char *name;
4336
4337                name = denlstring((char *) hp->h_name, true, true);
4338#  if NETINET6
4339                if (name == hp->h_name)
4340                {
4341                        static char n[MAXNAME + 1];
4342
4343                        /* Copy the string, hp->h_name is about to disappear */
4344                        (void) sm_strlcpy(n, name, sizeof n);
4345                        name = n;
4346                }
4347                freehostent(hp);
4348#  endif /* NETINET6 */
4349                return name;
4350        }
4351# endif /* NETINET || NETINET6 */
4352
4353# if NETINET6
4354        if (hp != NULL)
4355        {
4356                freehostent(hp);
4357                hp = NULL;
4358        }
4359# endif /* NETINET6 */
4360
4361# if NETUNIX
4362        if (sap->sa.sa_family == AF_UNIX && sap->sunix.sun_path[0] == '\0')
4363                return "localhost";
4364# endif /* NETUNIX */
4365        {
4366                static char buf[203];
4367
4368                (void) sm_snprintf(buf, sizeof buf, "[%.200s]",
4369                                   anynet_ntoa(sap));
4370                return buf;
4371        }
4372}
4373#endif /* USE_SOCK_STREAM */
Note: See TracBrowser for help on using the repository browser.