implement Fx|prog and "program" map class
authorEric Allman <eric@ucbvax.Berkeley.EDU>
Sun, 14 May 1995 23:43:00 +0000 (15:43 -0800)
committerEric Allman <eric@ucbvax.Berkeley.EDU>
Sun, 14 May 1995 23:43:00 +0000 (15:43 -0800)
SCCS-vsn: usr.sbin/sendmail/src/util.c 8.67
SCCS-vsn: usr.sbin/sendmail/src/readcf.c 8.89
SCCS-vsn: usr.sbin/sendmail/src/conf.c 8.160
SCCS-vsn: usr.sbin/sendmail/src/map.c 8.59

usr/src/usr.sbin/sendmail/src/conf.c
usr/src/usr.sbin/sendmail/src/map.c
usr/src/usr.sbin/sendmail/src/readcf.c
usr/src/usr.sbin/sendmail/src/util.c

index e2014d6..d532b88 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)conf.c     8.159 (Berkeley) %G%";
+static char sccsid[] = "@(#)conf.c     8.160 (Berkeley) %G%";
 #endif /* not lint */
 
 # include "sendmail.h"
 #endif /* not lint */
 
 # include "sendmail.h"
@@ -380,6 +380,11 @@ setupmaps()
                udb_map_lookup, null_map_store);
 #endif
 
                udb_map_lookup, null_map_store);
 #endif
 
+       /* arbitrary programs */
+       MAPDEF("program", NULL, 0,
+               map_parseargs, null_map_open, null_map_close,
+               prog_map_lookup, null_map_store);
+
        /* sequenced maps */
        MAPDEF("sequence", NULL, MCF_ALIASOK,
                seq_map_parse, null_map_open, null_map_close,
        /* sequenced maps */
        MAPDEF("sequence", NULL, MCF_ALIASOK,
                seq_map_parse, null_map_open, null_map_close,
index 939cf79..6d603ae 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)map.c      8.58 (Berkeley) %G%";
+static char sccsid[] = "@(#)map.c      8.59 (Berkeley) %G%";
 #endif /* not lint */
 
 #include "sendmail.h"
 #endif /* not lint */
 
 #include "sendmail.h"
@@ -2429,6 +2429,86 @@ bestmx_map_lookup(map, name, av, statp)
 
 #endif
 \f/*
 
 #endif
 \f/*
+**  Program map type.
+**
+**     This provides access to arbitrary programs.  It should be used
+**     only very sparingly, since there is no way to bound the cost
+**     of invoking an arbitrary program.
+*/
+
+char *
+prog_map_lookup(map, name, av, statp)
+       MAP *map;
+       char *name;
+       char **av;
+       int *statp;
+{
+       int i;
+       register char *p;
+       int fd;
+       auto pid_t pid;
+       char *argv[MAXPV + 1];
+       char buf[MAXLINE];
+
+       if (tTd(38, 20))
+               printf("prog_map_lookup(%s, %s) %s\n",
+                       map->map_mname, name, map->map_file);
+
+       i = 0;
+       argv[i++] = map->map_file;
+       strcpy(buf, map->map_rebuild);
+       for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t"))
+       {
+               if (i >= MAXPV - 1)
+                       break;
+               argv[i++] = p;
+       }
+       argv[i++] = name;
+       argv[i] = NULL;
+       pid = prog_open(argv, &fd, CurEnv);
+       if (pid < 0)
+       {
+               if (tTd(38, 9))
+                       printf("prog_map_lookup(%s) failed (%s) -- closing",
+                               map->map_mname, errstring(errno));
+               map->map_mflags &= ~(MF_VALID|MF_OPEN);
+               return NULL;
+       }
+       i = read(fd, buf, sizeof buf - 1);
+       if (i <= 0 && tTd(38, 2))
+               printf("prog_map_lookup(%s): read error %s\n",
+                       map->map_mname, strerror(errno));
+       if (i > 0)
+       {
+               char *rval;
+
+               buf[i] = '\0';
+               p = strchr(buf, '\n');
+               if (p != NULL)
+                       *p = '\0';
+
+               /* collect the return value */
+               if (bitset(MF_MATCHONLY, map->map_mflags))
+                       rval = map_rewrite(map, name, strlen(name), NULL);
+               else
+                       rval = map_rewrite(map, buf, strlen(buf), NULL);
+
+               /* now flush any additional output */
+               while ((i = read(fd, buf, sizeof buf)) > 0)
+                       continue;
+               close(fd);
+
+               /* and wait for the process to terminate */
+               *statp = waitfor(pid);
+
+               return rval;
+       }
+
+       close(fd);
+       *statp = waitfor(pid);
+       return NULL;
+}
+\f/*
 **  Sequenced map type.
 **
 **     Tries each map in order until something matches, much like
 **  Sequenced map type.
 **
 **     Tries each map in order until something matches, much like
index 7a25a51..ca68bb9 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)readcf.c   8.88 (Berkeley) %G%";
+static char sccsid[] = "@(#)readcf.c   8.89 (Berkeley) %G%";
 #endif /* not lint */
 
 # include "sendmail.h"
 #endif /* not lint */
 
 # include "sendmail.h"
@@ -674,6 +674,8 @@ fileclass(class, filename, fmt, safe, optional)
 {
        FILE *f;
        int sff;
 {
        FILE *f;
        int sff;
+       int pid;
+       register char *p;
        char buf[MAXLINE];
 
        if (tTd(37, 2))
        char buf[MAXLINE];
 
        if (tTd(37, 2))
@@ -681,14 +683,32 @@ fileclass(class, filename, fmt, safe, optional)
 
        if (filename[0] == '|')
        {
 
        if (filename[0] == '|')
        {
-               syserr("fileclass: pipes (F%c%s) not supported due to security problems",
-                       class, filename);
-               return;
+               auto int fd;
+               int i;
+               char *argv[MAXPV + 1];
+
+               i = 0;
+               for (p = strtok(&filename[1], " \t"); p != NULL; p = strtok(NULL, " \t"))
+               {
+                       if (i >= MAXPV)
+                               break;
+                       argv[i++] = p;
+               }
+               argv[i] = NULL;
+               pid = prog_open(argv, &fd, CurEnv);
+               if (pid < 0)
+                       f = NULL;
+               else
+                       f = fdopen(fd, "r");
+       }
+       else
+       {
+               pid = -1;
+               sff = SFF_REGONLY;
+               if (safe)
+                       sff |= SFF_OPENASROOT;
+               f = safefopen(filename, O_RDONLY, 0, sff);
        }
        }
-       sff = SFF_REGONLY;
-       if (safe)
-               sff |= SFF_OPENASROOT;
-       f = safefopen(filename, O_RDONLY, 0, sff);
        if (f == NULL)
        {
                if (!optional)
        if (f == NULL)
        {
                if (!optional)
@@ -737,6 +757,8 @@ fileclass(class, filename, fmt, safe, optional)
        }
 
        (void) fclose(f);
        }
 
        (void) fclose(f);
+       if (pid > 0)
+               (void) waitfor(pid);
 }
 \f/*
 **  MAKEMAILER -- define a new mailer.
 }
 \f/*
 **  MAKEMAILER -- define a new mailer.
index 5af40fa..1384024 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)util.c     8.66 (Berkeley) %G%";
+static char sccsid[] = "@(#)util.c     8.67 (Berkeley) %G%";
 #endif /* not lint */
 
 # include "sendmail.h"
 #endif /* not lint */
 
 # include "sendmail.h"
@@ -1701,6 +1701,140 @@ shorten_hostname(host)
                *--p = '\0';
 }
 \f/*
                *--p = '\0';
 }
 \f/*
+**  PROG_OPEN -- open a program for reading
+**
+**     Parameters:
+**             argv -- the argument list.
+**             pfd -- pointer to a place to store the file descriptor.
+**             e -- the current envelope.
+**
+**     Returns:
+**             pid of the process -- -1 if it failed.
+*/
+
+int
+prog_open(argv, pfd, e)
+       char **argv;
+       int *pfd;
+       ENVELOPE *e;
+{
+       int pid;
+       int i;
+       int saveerrno;
+       char **ep;
+       int fdv[2];
+       char *p, *q;
+       char buf[MAXLINE + 1];
+       char *env[MAXUSERENVIRON];
+       extern char **environ;
+       extern int DtableSize;
+
+       if (pipe(fdv) < 0)
+       {
+               syserr("%s: cannot create pipe for stdout", argv[0]);
+               return -1;
+       }
+       pid = fork();
+       if (pid < 0)
+       {
+               syserr("%s: cannot fork", argv[0]);
+               close(fdv[0]);
+               close(fdv[1]);
+               return -1;
+       }
+       if (pid > 0)
+       {
+               /* parent */
+               close(fdv[1]);
+               *pfd = fdv[0];
+               return pid;
+       }
+
+       /* child -- close stdin */
+       close(0);
+
+       /* stdout goes back to parent */
+       close(fdv[0]);
+       if (dup2(fdv[1], 1) < 0)
+       {
+               syserr("%s: cannot dup2 for stdout", argv[0]);
+               _exit(EX_OSERR);
+       }
+       close(fdv[1]);
+
+       /* stderr goes to transcript if available */
+       if (e->e_xfp != NULL)
+       {
+               if (dup2(fileno(e->e_xfp), 2) < 0)
+               {
+                       syserr("%s: cannot dup2 for stderr", argv[0]);
+                       _exit(EX_OSERR);
+               }
+       }
+
+       /* this process has no right to the queue file */
+       if (e->e_lockfp != NULL)
+               close(fileno(e->e_lockfp));
+
+       /* run as default user */
+       setgid(DefGid);
+       setuid(DefUid);
+
+       /* run in some directory */
+       if (ProgMailer != NULL)
+               p = ProgMailer->m_execdir;
+       else
+               p = NULL;
+       for (; p != NULL; p = q)
+       {
+               q = strchr(p, ':');
+               if (q != NULL)
+                       *q = '\0';
+               expand(p, buf, sizeof buf, e);
+               if (q != NULL)
+                       *q++ = ':';
+               if (buf[0] != '\0' && chdir(buf) >= 0)
+                       break;
+       }
+       if (p == NULL)
+       {
+               /* backup directories */
+               if (chdir("/tmp") < 0)
+                       (void) chdir("/");
+       }
+
+       /* arrange for all the files to be closed */
+       for (i = 3; i < DtableSize; i++)
+       {
+               register int j;
+
+               if ((j = fcntl(i, F_GETFD, 0)) != -1)
+                       (void) fcntl(i, F_SETFD, j | 1);
+       }
+
+       /* set up the environment */
+       i = 0;
+       env[i++] = "AGENT=sendmail";
+       for (ep = environ; *ep != NULL; ep++)
+       {
+               if (strncmp(*ep, "TZ=", 3) == 0 ||
+                   strncmp(*ep, "ISP=", 4) == 0 ||
+                   strncmp(*ep, "SYSTYPE=", 8) == 0)
+                       env[i++] = *ep;
+       }
+       env[i] = NULL;
+
+       /* now exec the process */
+       execve(argv[0], (ARGV_T) argv, (ARGV_T) env);
+
+       /* woops!  failed */
+       saveerrno = errno;
+       syserr("%s: cannot exec", argv[0]);
+       if (transienterror(saveerrno))
+               _exit(EX_OSERR);
+       _exit(EX_CONFIG);
+}
+\f/*
 **  GET_COLUMN  -- look up a Column in a line buffer
 **
 **     Parameters:
 **  GET_COLUMN  -- look up a Column in a line buffer
 **
 **     Parameters: