Back to index

courier  0.68.2
Classes | Defines | Functions | Variables
tcpd.c File Reference
#include "soxwrap/soxwrap.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <pwd.h>
#include <grp.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include "waitlib/waitlib.h"
#include "rfc1035/rfc1035.h"
#include "liblock/config.h"
#include "liblock/liblock.h"
#include "tcpremoteinfo.h"
#include "numlib/numlib.h"
#include "argparse.h"
#include <netdb.h>

Go to the source code of this file.

Classes

struct  portinfo
struct  blocklist_s

Defines

#define MKS_USEAFINET4   1
#define MKS_ERROK   2

Functions

static void setup_block (const char *)
int openaccess (const char *)
void closeaccess ()
char * chkaccess (const char *)
static int isid (const char *p)
static RETSIGTYPE sigexit (int n)
static RETSIGTYPE sighup (int n)
static struct portinfocreateport (const char *a, const char *s)
static int parseaddr (const char *p)
static int mksocket (const char *ipaddrarg, const char *servname, int flags)
static int mksockets ()
static int init (int argc, char **argv)
static void run (int, const RFC1035_ADDR *, int, const char *, char **)
static void doreap (pid_t p, int wait_stat)
static RETSIGTYPE childsig (int signum)
static int doallowaccess (char *, int)
static int allowaccess (const RFC1035_ADDR *sin, int port)
static int getfreeslot (int *pidptr)
static void accepted (int, int, RFC1035_NETADDR *, int, const char *, char **)
static int doit (int argn, int argc, char **argv)
static void denied (int sockfd)
static void mysetenv (const char *name, const char *val)
static void ip2host (const RFC1035_ADDR *addr, const char *env)
static void mkmymsg (const char *varname, const char *msg)
static void docheckblocklist (struct blocklist_s *p, const char *nameptr)
static void check_blocklist_ipv4 (struct blocklist_s *p, const struct in_addr *ia)
static void check_blocklist (struct blocklist_s *p, const RFC1035_ADDR *ia)
static void check_drop (int sockfd)
static void proxy ()
int main (int argc, char **argv)

Variables

static const char * accessarg = 0
static const char * accesslocal = 0
static const char * denymsgarg = 0
static const char * listenarg = 0
static const char * ipaddrarg = 0
static const char * userarg = 0
static const char * grouparg = 0
static const char * maxprocsarg = 0
static const char * warnarg = 0
static const char * maxperiparg = 0
static const char * maxpercarg = 0
static const char * droparg = 0
static const char * nodnslookup = 0
static const char * noidentlookup = 0
static const char * stderrarg = 0
static const char * stderrloggerarg = 0
static const char * pidarg = 0
static const char * proxyarg = 0
static const char * restartarg = 0
static const char * stoparg = 0
static const char * stderrloggername = 0
static char * lockfilename
static struct args []
static struct portinfofdlist
static int maxfd
static int nprocs
static int maxperc
static int maxperip
static int nwarn
static pid_t * pids
static time_t last_alert = 0
static time_t last_warn = 0
static RFC1035_ADDR * addrs
static int sighup_received = 0
struct blocklist_sblocklist

Class Documentation

struct portinfo

Definition at line 110 of file tcpd.c.

Collaboration diagram for portinfo:
Class Members
int fd1
int fd2
const char * ipaddr
struct portinfo * next
const char * servname
struct blocklist_s

Definition at line 126 of file tcpd.c.

Collaboration diagram for blocklist_s:
Class Members
char * msg
struct blocklist_s * next
char * var
char * zone

Define Documentation

#define MKS_ERROK   2
#define MKS_USEAFINET4   1

Function Documentation

static void accepted ( int  n,
int  sockfd,
RFC1035_NETADDR *  sin,
int  sinl,
const char *  prog,
char **  args 
) [static]

Definition at line 1113 of file tcpd.c.

{
       RFC1035_ADDR addr;
       int    addrport;
#ifdef SO_LINGER
       int    dummy;
       struct linger l;
#endif
       pid_t  p;
       int cnt;

       if (rfc1035_sockaddrip(sin, sinl, &addr)
           || rfc1035_sockaddrport(sin, sinl, &addrport))
       {
              sox_close(sockfd);
              return;
       }

       /* Turn off the CLOEXEC and NONBLOCK bits */

       if (fcntl(sockfd, F_SETFD, 0))
       {
              perror("fcntl");
              sox_close(sockfd);
              return;
       }

       if (fcntl(sockfd, F_SETFL, 0))
       {
              perror("fcntl");
              sox_close(sockfd);
              return;
       }

       if (sighup_received)
       {
              sighup_received=0;
              if (accessarg)
              {
                     closeaccess();
                     if (openaccess(accessarg))
                            perror(accessarg);
              }
       }

#ifdef SO_KEEPALIVE
       dummy=1;
       if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
                     (const char *)&dummy, sizeof(dummy)) < 0)
       {
              perror("setsockopt");
       }
#endif

#ifdef SO_LINGER
       l.l_onoff=0;
       l.l_linger=0;

       if (setsockopt(sockfd, SOL_SOCKET, SO_LINGER,
                     (const char *)&l, sizeof(l)) < 0)
       {
              perror("setsockopt");
       }
#endif
       wait_block();
       if ((p=fork()) == -1)
       {
              perror("fork");
              sox_close(sockfd);
              return;
       }

       if (p == 0)
       {
              wait_restore(childsig);

              if (accesslocal) /* Lookup local interface address too? */
              {
              RFC1035_NETADDR lsin;
              RFC1035_ADDR laddr;
              int    lport;
              socklen_t     i=sizeof(lsin);
              
                     if (sox_getsockname(sockfd, (struct sockaddr *)&lsin, &i) == 0 &&
                            rfc1035_sockaddrip(&lsin, i, &laddr) == 0 &&
                            rfc1035_sockaddrport(&lsin, i, &lport) == 0 &&
                            allowaccess(&laddr,lport) == 0)
                     {
                            sox_close(sockfd);
                            _exit(0);
                     }
              }

              if (allowaccess(&addr,0) == 0)
              {
                     denied(sockfd);
              }

              run(sockfd, &addr, addrport, prog, args);
       }
       pids[n]=p;

       memcpy(addrs+n, &addr, sizeof(addr));
       sox_close(sockfd);
       wait_clear(childsig);

       for (cnt=n=0; n<nprocs; n++)
              if (pids[n] != (pid_t)-1)
                     ++cnt;

       if (cnt == nprocs)
       {
              time_t t;

              time(&t);
              if (last_alert == 0 || last_alert > t || last_alert < t - 60)
              {
                     last_alert=t;
                     fprintf(stderr,
                            "ALERT: %d maximum active connections.\n",
                            nprocs);
              }
       }
       else if (cnt >= nwarn)
       {
              time_t t;

              time(&t);
              if (last_warn == 0 || last_warn > t || last_warn < t - 60)
              {
                     last_warn=t;
                     fprintf(stderr, "WARN: %d active connections.\n",
                            cnt);
              }
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int allowaccess ( const RFC1035_ADDR *  sin,
int  port 
) [static]

Definition at line 859 of file tcpd.c.

{
char   buf[RFC1035_NTOABUFSIZE+6];

       rfc1035_ntoa(sin, buf);
       return (doallowaccess(buf, port));
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void check_blocklist ( struct blocklist_s p,
const RFC1035_ADDR *  ia 
) [static]

Definition at line 1601 of file tcpd.c.

Here is the call graph for this function:

Here is the caller graph for this function:

static void check_blocklist_ipv4 ( struct blocklist_s p,
const struct in_addr ia 
) [static]

Definition at line 1569 of file tcpd.c.

{
unsigned a,b,c,d;
char   hostname[RFC1035_MAXNAMESIZE+1];
const unsigned char *q=(const unsigned char *)ia;

       /* Calculate DNS query hostname */

       a=q[0];
       b=q[1];
       c=q[2];
       d=q[3];

       sprintf(hostname, "%u.%u.%u.%u.%s", d, c, b, a, p->zone);
       docheckblocklist(p, hostname);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void check_drop ( int  sockfd) [static]

Definition at line 1607 of file tcpd.c.

{
       const char *p, *q;
       char *r;

       p=droparg;

       if (p && !*p)
              p="BLOCK";

       for (; p && *p; q=p)
       {
              if (*p == ',')
              {
                     q= ++p;
                     continue;
              }

              for (q=p; *q; ++q)
                     if (*q == ',')
                            break;

              r=malloc(q-p+1);

              if (!r)
              {
                     perror("malloc");
                     _exit(1);
              }

              memcpy(r, p, q-p);
              r[q-p]=0;

              p=getenv(r);
              free(r);

              if (p && *p)
              {
                     fprintf(stderr,
                            "WARN: dropped blocked connection from %s\n",
                            getenv("TCPREMOTEIP"));
                     denied(sockfd);
              }
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static RETSIGTYPE childsig ( int  signum) [static]

Definition at line 818 of file tcpd.c.

{
       signum=signum;
       wait_reap(doreap, childsig);
#if RETSIGTYPE != void
       return (0);
#endif
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* chkaccess ( const char *  )

Definition at line 46 of file tcpdaccess.c.

{
size_t l;
char   *p, *q;

       if (!db_isopen)      return (0);


       p=dbobj_fetch(&db, ip, strlen(ip), &l, "");

       if (!p)       return (0);
       q=(char *)malloc(l+1);
       if (!q)
       {
              perror("malloc");
              free(p);
              return (0);
       }
       memcpy(q, p, l);
       q[l]=0;
       free(p);
       return (q);
}

Here is the caller graph for this function:

void closeaccess ( )

Definition at line 39 of file tcpdaccess.c.

{
       if (!db_isopen)      return;
       dbobj_close(&db);
       db_isopen=0;
}

Here is the caller graph for this function:

static struct portinfo* createport ( const char *  a,
const char *  s 
) [static, read]

Definition at line 208 of file tcpd.c.

{
       struct portinfo *p=(struct portinfo *)malloc(sizeof(struct portinfo));

       if (!p)
       {
              perror("malloc");
              return (NULL);
       }

       p->next=fdlist;
       fdlist=p;
       p->ipaddr=a;
       p->servname=s;
       p->fd1=p->fd2= -1;
       return (p);
}

Here is the caller graph for this function:

static void denied ( int  sockfd) [static]

Definition at line 1099 of file tcpd.c.

{
       if (denymsgarg) {
              if (write(sockfd, denymsgarg, strlen(denymsgarg)) < 0 ||
                  write(sockfd, "\n", 1) < 0)
              {
                     sox_close(sockfd);
                     _exit(1);
              }
       }
       sox_close(sockfd);
       _exit(0);
}

Here is the caller graph for this function:

static int doallowaccess ( char *  buf,
int  port 
) [static]

Definition at line 868 of file tcpd.c.

{
char   *accessptr;
char *p, *q, *r;
int    quote=0;
int    l;

       if (accessarg == 0)  return (1);

       if (port) snprintf(buf+strlen(buf), 7, ".%d", ntohs(port));
       while ((accessptr= *buf ? chkaccess(buf):0) == 0)
       {
              if ((accessptr=strrchr(buf, '.')) == 0
#if RFC1035_IPV6
                     && (accessptr=strrchr(buf, ':')) == 0
#endif
                     )
              {
                     if (port)
                     {
                            snprintf(buf, 8, "*.%d", ntohs(port));
                            if ((accessptr=chkaccess(buf)) != 0)
                                   break;
                     }
                     if ((accessptr=chkaccess("*")) != 0)
                            break;
                     return (1);
              }
              *accessptr=0;
       }

       if (strncmp(accessptr, "deny", 4) == 0)
       {
              free(accessptr);
              return (0);
       }

       p=accessptr;
       if (strncmp(accessptr, "allow", 5) == 0)
       {
              p += 5;
              if (*p == ',')       ++p;
       }

       while ( p && *p )
       {
              q=p;
              r=q;
              while (*p)
              {
                     if (*p == ',' && !quote)
                     {
                            *p++=0;
                            break;
                     }
                     if (!quote && (*p == '"' || *p == '\''))
                     {
                            quote=*p;
                            p++;
                            continue;
                     }
                     if (quote && *p == quote)
                     {
                            quote=0;
                            p++;
                            continue;
                     }
                     *r++=*p++;
              }
              *r=0;
              if (strchr(q, '=') == 0)
              {
              char   *r=malloc(strlen(q)+2);

                     if (!r)
                     {
                            perror("malloc");
                            return (0);
                     }
                     q=strcat(strcpy(r, q), "=");
              }

              while (*q && isspace((int)(unsigned char)*q))    ++q;
              while ((l=strlen(q)) > 0
                     && isspace((int)(unsigned char)q[l-1]))
                     q[--l]=0;
              putenv(q);
       }
       return (1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void docheckblocklist ( struct blocklist_s p,
const char *  nameptr 
) [static]

Definition at line 1417 of file tcpd.c.

{
       const char *q;
       const char *varname=p->var;
       char   hostname[RFC1035_MAXNAMESIZE+1];
       char   buf[RFC1035_MAXNAMESIZE+1];
       int    hasnotxt;
       struct blocklist_s *pp;
       struct rfc1035_reply *replyp;
       struct rfc1035_res res;
       int i;

       hostname[0]=0;
       strncat(hostname, nameptr, RFC1035_MAXNAMESIZE);

       if (!varname) varname="BLOCK";

       if ((q=getenv(varname)) != 0)      return;
                                   /* Env var already set */

       rfc1035_init_resolv(&res);

       if (p->ia.s_addr == INADDR_ANY)
       {
              /* We're not looking for a particular token IP address */

              if (p->msg == 0 || *p->msg == 0)
              {
                     /*
                     ** We don't have a predefined error message, therefore
                     ** we expect TXT records.
                     */
                     if ((i=rfc1035_resolve_cname(&res,
                                   hostname,
                                   RFC1035_TYPE_TXT,
                                   RFC1035_CLASS_IN, &replyp, 0)) >= 0)
                     {
                            rfc1035_rr_gettxt(replyp->allrrs[i], 0,
                                   hostname);
                            mysetenv(varname, hostname);
                     }
              }
              else
              {
                     /*
                     ** A predefined error message has been supplied, so
                     ** just look for the IP address.  Perhaps the
                     ** blacklist does not provide TXT records, so query
                     ** for A records only.
                     */

                     if ((i=rfc1035_resolve_cname(&res,
                                   hostname,
                                   RFC1035_TYPE_A,
                                   RFC1035_CLASS_IN, &replyp, 0)) >= 0)
                     {
                            mkmymsg(varname, p->msg);
                     }
              }

              if (replyp)   rfc1035_replyfree(replyp);
              rfc1035_destroy_resolv(&res);
              return;
       }

       /*
       ** Looking for a specific A record in the blacklist.  Possibly due
       ** to different messages for different A records.
       ** See if all -block options for the same zone have predefined
       ** error messages, so we can be satisfied with an A query only.
       */

       hasnotxt=0;

       for (pp=p; pp; pp=pp->next)
       {
              if (strcmp(pp->zone, p->zone))     continue;
              if (pp->msg == 0 || *pp->msg == 0) hasnotxt=1;
       }

       /*
       ** If no text were provided, we need both A and TXT records, so
       ** issue an ANY query, and parse the results.
       */

       (void)rfc1035_resolve_cname(&res,
                     hostname,
                     hasnotxt ? RFC1035_TYPE_ANY:RFC1035_TYPE_A,
                     RFC1035_CLASS_IN, &replyp, 0);

       if (!replyp)
       {
              rfc1035_destroy_resolv(&res);
              return;
       }

       for (i=0; i<replyp->ancount+replyp->nscount+replyp->arcount; i++)
       {
       int    j;

              /*
              ** Go through the DNS response, and check every A record
              ** in there.
              */
              rfc1035_replyhostname(replyp, replyp->allrrs[i]->rrname, buf);
              if (rfc1035_hostnamecmp(buf, hostname))   continue;
              if (replyp->allrrs[i]->rrtype != RFC1035_TYPE_A)
                     continue;

              /*
              ** Go through the remaining blocklist, and set the environment
              ** variable for each block entry for this zone and IP address.
              */
              for (pp=p; pp; pp=pp->next)
              {
              const char *vvarname=pp->var;

                     if (strcmp(pp->zone, p->zone))     continue;

                     if (pp->ia.s_addr != replyp->allrrs[i]->rr.inaddr.s_addr)
                            continue;

                     if (!vvarname)       vvarname="BLOCK";

                     /*
                     ** The -block option was kind enough to supply the
                     ** error message.
                     */

                     if (pp->msg && *pp->msg)
                     {
                            mkmymsg(vvarname, pp->msg);
                            continue;
                     }

                     /* No predefined message, look for a TXT record. */

                     if ((j=rfc1035_replysearch_all(&res,
                                                 replyp, hostname,
                                                 RFC1035_TYPE_TXT,
                                                 RFC1035_CLASS_IN, 0)) >= 0)
                     {
                            rfc1035_rr_gettxt(replyp->allrrs[j], 0, buf);
                            mysetenv(vvarname, buf);
                     }
                     else   mysetenv(vvarname, "Access denied.");
              }
       }
       rfc1035_replyfree(replyp);
       rfc1035_destroy_resolv(&res);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int doit ( int  argn,
int  argc,
char **  argv 
) [static]

Definition at line 987 of file tcpd.c.

{
       char   **ptrs;
       int    pidptr;
       struct portinfo *pi;
       fd_set fdr, fdrcopy;
       int    dummy;

       ptrs=(char **)malloc((argc-argn+1) * sizeof(char *));
       if (!ptrs)
       {
              perror("malloc");
              return (-1);
       }
       for (dummy=0; dummy<argc-argn; dummy++)
       {
              ptrs[dummy]=argv[argn+dummy];
       }
       ptrs[dummy]=0;

       if (listenarg)
       {
              dummy=atoi(listenarg);
              if (dummy <= 0)
              {
                     fprintf(stderr, "Invalid -listen option.\n");
                     exit(1);
              }
       }

       FD_ZERO(&fdrcopy);
       for (pi=fdlist; pi; pi=pi->next)
       {
              if (pi->fd1 >= 0)
                     FD_SET(pi->fd1, &fdrcopy);

              if (pi->fd2 >= 0)
                     FD_SET(pi->fd2, &fdrcopy);
       }

       pidptr=0;

       signal(SIGCHLD, childsig);

#if    HAVE_SETPGRP
#if    SETPGRP_VOID
       setpgrp();
#else
       setpgrp(0, 0);
#endif
#else
#if    HAVE_SETPGID
       setpgid(0, 0);
#endif
#endif
#ifdef  TIOCNOTTY

       {
       int fd=open("/dev/tty", O_RDWR);

              if (fd >= 0)
              {
                     ioctl(fd, TIOCNOTTY, 0);
                     close(fd);
              }
       }
#endif

       signal(SIGPIPE, SIG_IGN);
       for (;;)
       {
              int n;
              int sockfd;
              RFC1035_NETADDR      sin;
              socklen_t     sinl;

              fdr=fdrcopy;

              if (select(maxfd+1, &fdr, NULL, NULL, NULL) <= 0)
              {
                     if (errno != EINTR)
                            perror("accept");
                     continue;
              }

              for (pi=fdlist; pi; pi=pi->next)
              {
                     if (pi->fd1 >= 0 && FD_ISSET(pi->fd1, &fdr) &&
                         ((n=getfreeslot(&pidptr)),
                          (sinl = sizeof(sin)),
                          (sockfd=sox_accept(pi->fd1,
                                          (struct sockaddr *)&sin,
                                          &sinl))) >= 0)
                     {
                            accepted(n, sockfd, &sin, sinl,
                                    argv[argn], ptrs);
                     }

                     if (pi->fd2 >= 0 && FD_ISSET(pi->fd2, &fdr) &&
                         ((n=getfreeslot(&pidptr)),
                          (sinl = sizeof(sin)), 
                          (sockfd=sox_accept(pi->fd2,
                                          (struct sockaddr *)&sin,
                                          &sinl))) >= 0)
                     {
                            accepted(n, sockfd, &sin, sinl,
                                    argv[argn], ptrs);
                     }
              }
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void doreap ( pid_t  p,
int  wait_stat 
) [static]

Definition at line 806 of file tcpd.c.

{
int    n;

       for (n=0; n<nprocs; n++)
              if (p == pids[n])
              {
                     pids[n]= -1;
                     break;
              }
}

Here is the caller graph for this function:

static int getfreeslot ( int *  pidptr) [static]

Definition at line 961 of file tcpd.c.

{
       int n;

       for (;;)
       {
              wait_block();

              for (n=0; n<nprocs; n++)
              {
                     if (pids[*pidptr] == (pid_t)-1)    break;
                     if (++*pidptr >= nprocs)    *pidptr=0;
              }
              if (pids[*pidptr] != (pid_t)-1)
              {
                     wait_forchild(doreap, childsig);
                     continue;
              }
              break;
       }
       wait_clear(childsig);
       return (*pidptr);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int init ( int  argc,
char **  argv 
) [static]

Definition at line 506 of file tcpd.c.

{
int    argn;

struct group *gr;
int    i;
gid_t  gid=0;
const  char *servname;
int    forced=0;
int    lockfd=-1;
 
       argn=argparse(argc, argv, arginfo);

       if ((stoparg || restartarg) && pidarg == 0)
       {
              fprintf(stderr, "%s: -pid argument is required.\n", argv[0]);
              return (-1);
       }

       if (pidarg)
       {
              lockfilename=malloc(strlen(pidarg)+sizeof(".lock"));
              if (!lockfilename)
              {
                     perror("malloc");
                     return (-1);
              }
              strcat(strcpy(lockfilename, pidarg), ".lock");
       }

       if (stoparg)
       {
              ll_daemon_stop(lockfilename, pidarg);
              exit(0);
       }

       if (restartarg)
       {
              ll_daemon_restart(lockfilename, pidarg);
              exit(0);
       }

       if (argc - argn < 2)
       {
              fprintf(stderr, "Usage: %s [options] port prog arg1 arg2...\n",
                     argv[0]);
              return (-1);
       }

       if (pidarg) { /* -start implied for backwards compatibility */
              lockfd=ll_daemon_start(lockfilename);
              if (lockfd < 0)
              {
                     perror("ll_daemon_start");
                     return (-1);
              }
       }

       servname=argv[argn++];

       if (parseaddr(servname))
       {
              close(lockfd);
              return (-1);
       }

       if (mksockets())
       {
              close(lockfd);
              return (-1);
       }

       signal(SIGINT, sigexit);
       signal(SIGHUP, sighup);
       signal(SIGTERM, sigexit);

#if 0
       {
       int    fd2;
       int    dummy;

              perror("bind");
              if (!forcebindarg || errno != EADDRINUSE)
              {
                     sox_close(fd);
                     return (-1);
              }

              /* Poke around */

              if ((fd2=rfc1035_mksocket(SOCK_STREAM, 0, &dummy)) < 0)
                     /* Better get same socket as fd */
              {
                     perror("socket");
                     sox_close(fd);
                     return (-1);
              }

              if (sox_connect(fd2, (struct sockaddr *)sinaddr,
                     sinaddrlen) == 0)
              {
                     sox_close(fd2);
                     sox_close(fd);
                     return (-1);
              }
              sox_close(fd2);
              savepid();
              sleep(60);
              forced=1;
       }
#endif

       if (pidarg)
              ll_daemon_started(pidarg, lockfd);

       if (grouparg)
       {
              if (isid(grouparg))
                     gid=atoi(grouparg);
              else if ((gr=getgrnam(grouparg)) == 0)
              {
                     fprintf(stderr, "Group not found: %s\n", grouparg);
                     close(lockfd);
                     return (-1);
              }
              else   gid=gr->gr_gid;

              libmail_changegroup(gid);
       }

       if (userarg)
       {
       uid_t  uid;

              if (isid(userarg))
              {
                     uid=atoi(userarg);
                     libmail_changeuidgid(uid, getgid());
              }
              else
              {
              gid_t  g=getgid(), *gp=0;

                     if (grouparg) gp= &g;
                     libmail_changeusername(userarg, gp);
              }
       }

       if (pidarg && ll_daemon_resetio())
       {
              perror("ll_daemon_resetio");
              close(lockfd);
              return (-1);
       }

       if (stderrloggerarg)
       {
       pid_t  p;
       int    waitstat;
       int    pipefd[2];
       const char *progname=argv[argn];

              if (pipe(pipefd) < 0)
              {
                     perror("pipe");
                     return (-1);
              }

              signal(SIGCHLD, SIG_DFL);
              while ((p=fork()) == -1)
              {
                     sleep(5);
              }

              if (p == 0)
              {
                     signal(SIGHUP, SIG_IGN);
                     sox_close(0);
                     sox_dup(pipefd[0]);
                     sox_close(pipefd[0]);
                     sox_close(pipefd[1]);
                     sox_close(1);
                     open("/dev/null", O_WRONLY);
                     sox_close(2);
                     sox_dup(1);
                     closeaccess();
                     while ((p=fork()) == -1)
                     {
                            sleep(5);
                     }
                     if (p == 0)
                     {
                     const char *p=strrchr(progname, '/');

                            if (p) ++p;
                            else p=progname;

                            if (stderrloggername && *stderrloggername)
                                   p=stderrloggername;

                            execl(stderrloggerarg, stderrloggerarg,
                                          p, (char *)0);
                            perror(stderrloggerarg);
                            _exit(5);
                     }
                     _exit(0);
              }
              sox_close(2);
              sox_dup(pipefd[1]);
              sox_close(pipefd[0]);
              sox_close(pipefd[1]);
              while (wait(&waitstat) != p)
                     ;
       }
       else if (stderrarg)
       {
       int    fd=open(stderrarg, O_WRONLY|O_APPEND|O_CREAT, 0660);

              if (!fd)
              {
                     perror(stderrarg);
                     return (-1);
              }
              sox_close(2);
              sox_dup(fd);
              sox_close(fd);
       }

       nprocs=40;
       if (maxprocsarg)
       {
              nprocs=atoi(maxprocsarg);
              if (nprocs <= 0)
              {
                     fprintf(stderr, "Invalid -maxprocsarg option.\n");
                     return (-1);
              }
       }

       nwarn= nprocs - (nprocs / 10 + 1);

       if (warnarg)
       {
              int c=atoi(warnarg);

              if (c >= 0 && c <= nprocs)
                     nwarn=c;
       }

       if ((pids=malloc(sizeof(*pids)*nprocs)) == 0)
       {
              perror("malloc");
              return (-1);
       }
       if ((addrs=malloc(sizeof(*addrs)*nprocs)) == 0)
       {
              free(pids);
              perror("malloc");
              return (-1);
       }


       for (i=0; i<nprocs; i++)
              pids[i]= -1;

       maxperc=nprocs;
       maxperip=4;

       if (maxpercarg)
       {
              maxperc=atoi(maxpercarg);
              if (maxperc <= 0)
              {
                     fprintf(stderr, "Invalid -maxperc option.\n");
                     free(pids);
                     free(addrs);
                     return (-1);
              }
       }
       if (maxperiparg)
       {
              maxperip=atoi(maxperiparg);
              if (maxperip <= 0)
              {
                     fprintf(stderr, "Invalid -maxperip option.\n");
                     free(pids);
                     free(addrs);
                     return (-1);
              }
       }
       if (forced)
       {
              fprintf(stderr, "couriertcpd: ready.\n");
              fflush(stderr);
       }
       return (argn);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void ip2host ( const RFC1035_ADDR *  addr,
const char *  env 
) [static]

Definition at line 1269 of file tcpd.c.

{
const char *remotehost="softdnserr";
char   buf[RFC1035_MAXNAMESIZE+1];

#if TCPDUSERFC1035
struct rfc1035_res res;
#endif

       if (nodnslookup)     return;

       rfc1035_ntoa(addr, buf);

#if TCPDUSERFC1035

       rfc1035_init_resolv(&res);

       if (rfc1035_ptr(&res, addr, buf) != 0)
       {
              if (errno == ENOENT)
                     remotehost=0;
       }
       else
       {
              RFC1035_ADDR *ias;
              unsigned nias, n;

              if (rfc1035_a(&res, buf, &ias, &nias) != 0)
              {
                     if (errno == ENOENT)
                            remotehost=0;
              }
              else
              {
                     remotehost=0;
                     for (n=0; n<nias; n++)
                     {
                     char   a[RFC1035_MAXNAMESIZE];
                     char   b[RFC1035_MAXNAMESIZE];

                            rfc1035_ntoa(&ias[n], a);
                            rfc1035_ntoa(addr, b);

                            if (strcmp(a, b) == 0)
                            {
                                   remotehost=buf;
                            }
                     }
              }
       }
       rfc1035_destroy_resolv(&res);

#else

       {
       struct hostent *he;
       unsigned n;
       struct in_addr in;

#if    RFC1035_IPV6

              if (IN6_IS_ADDR_V4MAPPED(addr))
                     memcpy(&in, (char *)addr + 12, 4);
              else   return;
#else
              in= *addr;
#endif

              he=gethostbyaddr( (char *)&in, sizeof(in), AF_INET);
              if (!he)
              {
                     switch (h_errno)     {
                     case HOST_NOT_FOUND:
                     case NO_DATA:
                            remotehost=0;
                            break;
                     }
              }
              else
              {
                     strcpy(buf, he->h_name);
                     he=gethostbyname(buf);
                     if (!he)
                     {
                            switch (h_errno)     {
                            case HOST_NOT_FOUND:
                            case NO_DATA:
                                   remotehost=0;
                                   break;
                            }
                     }
                     else for (n=0, remotehost=0; he->h_addr_list[n]; n++)
                     {
                     struct in_addr hin;

                            if (he->h_addrtype != AF_INET ||
                                   he->h_length < sizeof(hin))
                                   break;
                            memcpy((char *)&hin, he->h_addr_list[n],
                                   sizeof(hin));
                            if (hin.s_addr == in.s_addr)
                            {
                                   remotehost=buf;
                                   break;
                            }
                     }

              }
       }
#endif
       if (remotehost)
              mysetenv(env, remotehost);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int isid ( const char *  p) [static]

Definition at line 173 of file tcpd.c.

{
       while (*p)
       {
              if (*p < '0' || *p > '9')   return (0);
              ++p;
       }
       return (1);
}

Here is the caller graph for this function:

int main ( int  argc,
char **  argv 
)

Definition at line 1764 of file tcpd.c.

{
int argn=init(argc, argv);
int rc;

       if (argn < 0)
       {
              exit(1);
       }
       if (accessarg && openaccess(accessarg))
              perror(accessarg);
       if (accesslocal && !accessarg)
              fprintf(stderr,"-accesslocal requires -access\n");
       rc=doit(argn, argc, argv);
       kill( -getpid(), SIGTERM);
       exit(rc);
       return (0);
}

Here is the call graph for this function:

static void mkmymsg ( const char *  varname,
const char *  msg 
) [static]

Definition at line 1383 of file tcpd.c.

{
const char *p=getenv("TCPREMOTEIP");
char *q=malloc(strlen(msg)+1+strlen(p));
char *r;

       if (!q)
       {
              perror("malloc");
              exit(1);
       }

       for (r=q; *msg; msg++)
       {
              if (*msg == '@')
              {
                     strcpy(r, p);
                     while (*r)    r++;
                     ++msg;
                     break;
              }
              *r++=*msg;
       }
       while (*msg)
              *r++=*msg++;
       *r=0;
       mysetenv(varname, q);
       free(q);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int mksocket ( const char *  ipaddrarg,
const char *  servname,
int  flags 
) [static]

Definition at line 273 of file tcpd.c.

{
       struct servent *servptr;
       int    port;
       int    fd;

       RFC1035_ADDR addr;
       RFC1035_NETADDR  netaddr;
       const struct sockaddr *sinaddr;
       int    sinaddrlen;

#if    RFC1035_IPV6
       struct sockaddr_in6  sin6;
#endif

       struct sockaddr_in   sin4;

       int    af;

       servptr=getservbyname(servname, "tcp");
       if (servptr)
              port=servptr->s_port;
       else
       {
              port=atoi(servname);
              if (port <= 0 || port > 65535)
              {
                     fprintf(stderr, "Invalid port: %s\n", servname);
                     return (-1);
              }
              port=htons(port);
       }

       /* Create an IPv6 or an IPv4 socket */

#if    RFC1035_IPV6
       if (flags & MKS_USEAFINET4)
       {
              fd=socket(PF_INET, SOCK_STREAM, 0);
              af=AF_INET;
       }
       else
#endif
              fd=rfc1035_mksocket(SOCK_STREAM, 0, &af);

       if (fd < 0)
       {
              perror("socket");
              return (-1);
       }

       /* Figure out what to bind based on what socket we created */

       if (ipaddrarg && strcmp(ipaddrarg, "0"))
       {
              if (rfc1035_aton(ipaddrarg, &addr) < 0)
              {
                     fprintf(stderr,"Invalid IP address: %s\n", ipaddrarg);
                     close(fd);
                     return (-1);
              }

              if (rfc1035_mkaddress(af, &netaddr, &addr, port, &sinaddr,
                            &sinaddrlen))
              {
                     fprintf(stderr,"Unable to bind IP address: %s\n",
                            ipaddrarg);
                     close(fd);
                     return (-1);
              }
       }
       else   /* Bind default address */
       {
#if    RFC1035_IPV6
              if (af == AF_INET6)
              {
                     memset(&sin6, 0, sizeof(sin6));
                     sin6.sin6_family=AF_INET6;
                     sin6.sin6_addr=in6addr_any;
                     sin6.sin6_port=port;
                     sinaddr=(const struct sockaddr *)&sin6;
                     sinaddrlen=sizeof(sin6);
              }
              else
#endif
                     if (af == AF_INET)
                     {
                            sin4.sin_family=AF_INET;
                            sin4.sin_addr.s_addr=INADDR_ANY;
                            sin4.sin_port=port;
                            sinaddr=(const struct sockaddr *)&sin4;
                            sinaddrlen=sizeof(sin4);
                     }
                     else
                     {
                            errno=EAFNOSUPPORT;
                            perror("socket");
                            close(fd);
                            return (-1);
                     }
       }

       {
              int dummy=1;

              if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
                     (const char *)&dummy, sizeof(dummy)) < 0)
              {
                     perror("setsockopt");
              }
       }

       if (fcntl(fd, F_SETFD, FD_CLOEXEC))
       {
              perror("fcntl");
              close(fd);
              return (-1);
       }

       if (fcntl(fd, F_SETFL, O_NONBLOCK))
       {
              perror("fcntl");
              close(fd);
              return (-1);
       }

       if (sox_bind(fd, (struct sockaddr *)sinaddr, sinaddrlen) < 0)
       {
              if (flags & MKS_ERROK)
              {
                     close(fd);
                     return (-2);
              }

              perror("bind");
              close(fd);
              return (-1);
       }

       if (sox_listen(fd,
#ifdef SOMAXCONN
                     SOMAXCONN
#else
                     5
#endif
                     ))
       {
              if (flags && MKS_ERROK)
              {
                     close(fd);
                     return (-2);
              }
              perror("listen");
              close(fd);
              return (-1);
       }
       return (fd);
}

Here is the call graph for this function:

static int mksockets ( ) [static]

Definition at line 438 of file tcpd.c.

{
       struct portinfo *p;

       maxfd= -1;

       for (p=fdlist; p; p=p->next)
       {
              int fd;
              struct in_addr addr;
              int fd_flag=0;

              if (p->ipaddr && strcmp(p->ipaddr, "0"))
              {
                     /* FreeBSD needs AF_INET binds for IPv4 addys */

                     if (rfc1035_aton_ipv4(p->ipaddr, &addr) == 0)
                     {
                            fd_flag=MKS_USEAFINET4;
                     }
              }

              fd=mksocket(p->ipaddr, p->servname, fd_flag);

              if (fd < 0)
                     break;

              p->fd1=fd;

              if (fd > maxfd)
                     maxfd=fd;

              /* BSD requires both an IPv6 and an IPv4 socket */

#if    RFC1035_IPV6
              if (p->ipaddr == 0 || strcmp(p->ipaddr, "0") == 0)
              {
                     fd=mksocket(p->ipaddr, p->servname,
                                (MKS_USEAFINET4|MKS_ERROK));

                     if (fd == -2)
                            continue;     /* Ok if bind failed */
                     if (fd < 0)
                            break;

                     if (fd > maxfd)
                            maxfd=fd;
                     p->fd2=fd;
              }
#endif

       }

       if (p) /* Clean up after ourselves, after an error */
       {
              for (p=fdlist; p; p=p->next)
              {
                     if (p->fd1 >= 0)
                            close(p->fd1);
                     if (p->fd2 >= 0)
                            close(p->fd2);
              }
              return (-1);
       }

       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void mysetenv ( const char *  name,
const char *  val 
) [static]

Definition at line 1252 of file tcpd.c.

{
char   *p=malloc(strlen(name)+strlen(val)+2);

       if (!p)
       {
              perror("malloc");
              _exit(1);
       }
       putenv(strcat(strcat(strcpy(p, name), "="), val));
}

Here is the caller graph for this function:

int openaccess ( const char *  )

Definition at line 20 of file tcpdaccess.c.

{
       if (!db_isinit)
       {
              dbobj_init(&db);
              db_isinit=1;
       }
       if (db_isopen)
       {
              dbobj_close(&db);
              db_isopen=0;
       }

       if (dbobj_open(&db, filename, "R"))
              return (-1);
       db_isopen=1;
       return (0);
}

Here is the caller graph for this function:

static int parseaddr ( const char *  p) [static]

Definition at line 226 of file tcpd.c.

{
       char *buf=strdup(p);
       char *q, *a, *s;

       if (!buf)
       {
              perror("malloc");
              return (-1);
       }

       for (q=buf; (q=strtok(q, ",")) != NULL; q=0)
       {
              if ((s=strrchr(q, '.')) != 0)
              {
                     *s++=0;
                     a=q;
              }
              else
              {
                     a=0;
                     s=q;
              }

              if (createport(a, s) == NULL)
                     return (-1);
       }

       if (ipaddrarg)
       {
              struct portinfo *p;

              for (p=fdlist; p; p=p->next)
              {
                     if (p->ipaddr && strcmp(p->ipaddr, "0"))
                            continue;
                     p->ipaddr=ipaddrarg;
              }
       }

       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void proxy ( ) [static]

Definition at line 1785 of file tcpd.c.

{
}

Here is the caller graph for this function:

static void run ( int  fd,
const RFC1035_ADDR *  addr,
int  addrport,
const char *  prog,
char **  argv 
) [static]

Definition at line 1655 of file tcpd.c.

{
RFC1035_NETADDR lsin;
RFC1035_ADDR laddr;
int    lport;

socklen_t     i;
int    ipcnt, ccnt;
char   buf[RFC1035_MAXNAMESIZE+128];
struct blocklist_s *bl;
const char *remoteinfo;
const char *p;

       i=sizeof(lsin);
       if (sox_getsockname(fd, (struct sockaddr *)&lsin, &i) ||
              rfc1035_sockaddrip(&lsin, i, &laddr) ||
              rfc1035_sockaddrport(&lsin, i, &lport))
       {
              fprintf(stderr, "getsockname failed.\n");
              exit(1);
       }

       if (!noidentlookup && (remoteinfo=tcpremoteinfo(
              &laddr, lport,
              addr, addrport, 0)) != 0)
       {
       char   *q=malloc(sizeof("TCPREMOTEINFO=")+strlen(remoteinfo));

              if (!q)
              {
                     perror("malloc");
                     _exit(1);
              }

              strcat(strcpy(q, "TCPREMOTEINFO="), remoteinfo);
              putenv(q);
       }

/* check if it's an exception to the global ip limit */
       if( (p=getenv("MAXCPERIP")) != NULL )
       {
              int j = atoi(p);

              if( j > 0 )
                     maxperip = j;
       }

       for (i=0, ipcnt=ccnt=0; i<nprocs; i++)
       {
       RFC1035_ADDR *psin;
       int    j;

              if (pids[i] == (pid_t)-1)   continue;

              psin=addrs+i;

              for (j=0; j<sizeof(*addr); j++)
                     if ( ((char *)addr)[j] != ((char *)psin)[j])
                            break;

              if (j >= sizeof(*addr) &&
                     ++ipcnt >= maxperip)
              {
                     rfc1035_ntoa(addr, buf);
                     fprintf(stderr,"ALERT: Maximum connection limit reached for %s\n",buf);
                     _exit(0);     /* Too many from same IP address */
              }

              if ( j >= sizeof(*addr)-1 &&
                     ++ccnt >= maxperc)
                     _exit(0);     /* Too many from same netblock */

       }

       rfc1035_ntoa(addr, buf);
       mysetenv("TCPREMOTEIP", buf);
       sprintf(buf, "%d", ntohs(addrport));
       mysetenv("TCPREMOTEPORT", buf);
       ip2host(addr, "TCPREMOTEHOST");

       rfc1035_ntoa(&laddr, buf);
       mysetenv("TCPLOCALIP", buf);
       sprintf(buf, "%d", ntohs(lport));
       mysetenv("TCPLOCALPORT", buf);
       ip2host(&laddr, "TCPLOCALHOST");

       for (bl=blocklist; bl; bl=bl->next)
              check_blocklist(bl, addr);

       check_drop(fd);
       sox_close(0);
       sox_close(1);
       sox_dup(fd);
       sox_dup(fd);
       sox_close(fd);
       if (stderrarg && strcmp(stderrarg, "socket") == 0)
       {
              sox_close(2);
              sox_dup(1);
       }
       proxy();
       signal(SIGPIPE, SIG_DFL);

       execv(prog, argv);
       perror(prog);
       exit(1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void setup_block ( const char *  blockinfo) [static]

Definition at line 138 of file tcpd.c.

{
struct blocklist_s *newbl=(struct blocklist_s *)malloc(sizeof(*blocklist));
char   *p;
struct blocklist_s **blptr;

       for (blptr= &blocklist; *blptr; blptr=&(*blptr)->next)
              ;

       if (!newbl || (newbl->zone=malloc(strlen(blockinfo)+1)) == 0)
       {
              perror("malloc");
              exit(1);
       }

       *blptr=newbl;
       newbl->next=0;
       strcpy(newbl->zone, blockinfo);
       newbl->var=strchr(newbl->zone, ',');
       newbl->msg=0;
       newbl->ia.s_addr=INADDR_ANY;

       if (newbl->var)
              *newbl->var++=0;
       if (newbl->var && *newbl->var)
              newbl->msg=strchr(newbl->var, ',');
       if (newbl->msg)
              *newbl->msg++=0;
       if (newbl->var && (p=strchr(newbl->var, '/')) != 0)
       {
              *p++=0;
              rfc1035_aton_ipv4(p, &newbl->ia);
       }
}

Here is the call graph for this function:

static RETSIGTYPE sigexit ( int  n) [static]

Definition at line 183 of file tcpd.c.

{
       kill( -getpid(), SIGTERM);
       _exit(0);

#if RETSIGTYPE != void
       return (0)
#endif
}

Here is the caller graph for this function:

static RETSIGTYPE sighup ( int  n) [static]

Definition at line 193 of file tcpd.c.

{
       sighup_received=1;

       signal(SIGHUP, sighup);

#if RETSIGTYPE != void
       return (0)
#endif
}

Here is the caller graph for this function:


Variable Documentation

const char* accessarg = 0 [static]

Definition at line 56 of file tcpd.c.

const char* accesslocal = 0 [static]

Definition at line 57 of file tcpd.c.

RFC1035_ADDR* addrs [static]

Definition at line 122 of file tcpd.c.

struct args[] [static]
Initial value:
{
       {"access", &accessarg},
       {"accesslocal", &accesslocal},
       {"denymsg", &denymsgarg},
       {"drop", &droparg},
       {"address", &ipaddrarg},
       {"block", 0, setup_block},
       {"group", &grouparg},
       {"listen", &listenarg},
       {"maxperc", &maxpercarg},
       {"maxperip", &maxperiparg},
       {"maxprocs", &maxprocsarg},
       {"warn", &warnarg},
       {"nodnslookup", &nodnslookup},
       {"noidentlookup", &noidentlookup},
       {"pid", &pidarg},
       {"restart", &restartarg},
       {"stderr", &stderrarg},
       {"stderrlogger", &stderrloggerarg},
       {"stderrloggername", &stderrloggername},
       {"stop", &stoparg},
       {"user", &userarg},
       {"proxy", &proxyarg},
       {0}
       }

Definition at line 82 of file tcpd.c.

const char* denymsgarg = 0 [static]

Definition at line 58 of file tcpd.c.

const char* droparg = 0 [static]

Definition at line 67 of file tcpd.c.

struct portinfo * fdlist [static]
const char* grouparg = 0 [static]

Definition at line 62 of file tcpd.c.

const char* ipaddrarg = 0 [static]

Definition at line 60 of file tcpd.c.

time_t last_alert = 0 [static]

Definition at line 121 of file tcpd.c.

time_t last_warn = 0 [static]

Definition at line 121 of file tcpd.c.

const char* listenarg = 0 [static]

Definition at line 59 of file tcpd.c.

char* lockfilename [static]

Definition at line 78 of file tcpd.c.

int maxfd [static]

Definition at line 117 of file tcpd.c.

int maxperc [static]

Definition at line 119 of file tcpd.c.

const char* maxpercarg = 0 [static]

Definition at line 66 of file tcpd.c.

int maxperip [static]

Definition at line 119 of file tcpd.c.

const char* maxperiparg = 0 [static]

Definition at line 65 of file tcpd.c.

const char* maxprocsarg = 0 [static]

Definition at line 63 of file tcpd.c.

const char* nodnslookup = 0 [static]

Definition at line 68 of file tcpd.c.

const char* noidentlookup = 0 [static]

Definition at line 69 of file tcpd.c.

int nprocs [static]

Definition at line 119 of file tcpd.c.

int nwarn [static]

Definition at line 119 of file tcpd.c.

const char* pidarg = 0 [static]

Definition at line 72 of file tcpd.c.

pid_t* pids [static]

Definition at line 120 of file tcpd.c.

const char* proxyarg = 0 [static]

Definition at line 73 of file tcpd.c.

const char* restartarg = 0 [static]

Definition at line 74 of file tcpd.c.

int sighup_received = 0 [static]

Definition at line 124 of file tcpd.c.

const char* stderrarg = 0 [static]

Definition at line 70 of file tcpd.c.

const char* stderrloggerarg = 0 [static]

Definition at line 71 of file tcpd.c.

const char* stderrloggername = 0 [static]

Definition at line 76 of file tcpd.c.

const char* stoparg = 0 [static]

Definition at line 75 of file tcpd.c.

const char* userarg = 0 [static]

Definition at line 61 of file tcpd.c.

const char* warnarg = 0 [static]

Definition at line 64 of file tcpd.c.