summaryrefslogtreecommitdiffstats
path: root/sendmail/makemap/makemap.c
diff options
context:
space:
mode:
Diffstat (limited to 'sendmail/makemap/makemap.c')
-rw-r--r--sendmail/makemap/makemap.c528
1 files changed, 528 insertions, 0 deletions
diff --git a/sendmail/makemap/makemap.c b/sendmail/makemap/makemap.c
new file mode 100644
index 0000000..7302748
--- /dev/null
+++ b/sendmail/makemap/makemap.c
@@ -0,0 +1,528 @@
+/*
+ * Copyright (c) 1998-2002, 2004 Sendmail, Inc. and its suppliers.
+ * All rights reserved.
+ * Copyright (c) 1992 Eric P. Allman. All rights reserved.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * By using this file, you agree to the terms and conditions set
+ * forth in the LICENSE file which can be found at the top level of
+ * the sendmail distribution.
+ *
+ */
+
+#include <sm/gen.h>
+
+SM_IDSTR(copyright,
+"@(#) Copyright (c) 1998-2002, 2004 Sendmail, Inc. and its suppliers.\n\
+ All rights reserved.\n\
+ Copyright (c) 1992 Eric P. Allman. All rights reserved.\n\
+ Copyright (c) 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n")
+
+SM_IDSTR(id, "@(#)$Id: makemap.c,v 8.178 2007/05/11 18:45:39 ca Exp $")
+
+
+#include <sys/types.h>
+#ifndef ISC_UNIX
+# include <sys/file.h>
+#endif /* ! ISC_UNIX */
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#ifdef EX_OK
+# undef EX_OK /* unistd.h may have another use for this */
+#endif /* EX_OK */
+#include <sysexits.h>
+#include <sendmail/sendmail.h>
+#include <sendmail/pathnames.h>
+#include <libsmdb/smdb.h>
+
+uid_t RealUid;
+gid_t RealGid;
+char *RealUserName;
+uid_t RunAsUid;
+gid_t RunAsGid;
+char *RunAsUserName;
+int Verbose = 2;
+bool DontInitGroups = false;
+uid_t TrustedUid = 0;
+BITMAP256 DontBlameSendmail;
+
+#define BUFSIZE 1024
+#define ISSEP(c) (sep == '\0' ? isascii(c) && isspace(c) : (c) == sep)
+
+static void usage __P((char *));
+
+static void
+usage(progname)
+ char *progname;
+{
+ sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "Usage: %s [-C cffile] [-N] [-c cachesize] [-D commentchar]\n",
+ progname);
+ sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ " %*s [-d] [-e] [-f] [-l] [-o] [-r] [-s] [-t delimiter]\n",
+ (int) strlen(progname), "");
+ sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ " %*s [-u] [-v] type mapname\n",
+ (int) strlen(progname), "");
+ exit(EX_USAGE);
+}
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *progname;
+ char *cfile;
+ bool inclnull = false;
+ bool notrunc = false;
+ bool allowreplace = false;
+ bool allowempty = false;
+ bool verbose = false;
+ bool foldcase = true;
+ bool unmake = false;
+ char sep = '\0';
+ char comment = '#';
+ int exitstat;
+ int opt;
+ char *typename = NULL;
+ char *mapname = NULL;
+ unsigned int lineno;
+ int st;
+ int mode;
+ int smode;
+ int putflags = 0;
+ long sff = SFF_ROOTOK|SFF_REGONLY;
+ struct passwd *pw;
+ SMDB_DATABASE *database;
+ SMDB_CURSOR *cursor;
+ SMDB_DBENT db_key, db_val;
+ SMDB_DBPARAMS params;
+ SMDB_USER_INFO user_info;
+ char ibuf[BUFSIZE];
+#if HASFCHOWN
+ SM_FILE_T *cfp;
+ char buf[MAXLINE];
+#endif /* HASFCHOWN */
+ static char rnamebuf[MAXNAME]; /* holds RealUserName */
+ extern char *optarg;
+ extern int optind;
+
+ memset(&params, '\0', sizeof params);
+ params.smdbp_cache_size = 1024 * 1024;
+
+ progname = strrchr(argv[0], '/');
+ if (progname != NULL)
+ progname++;
+ else
+ progname = argv[0];
+ cfile = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL);
+
+ clrbitmap(DontBlameSendmail);
+ RunAsUid = RealUid = getuid();
+ RunAsGid = RealGid = getgid();
+ pw = getpwuid(RealUid);
+ if (pw != NULL)
+ (void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf);
+ else
+ (void) sm_snprintf(rnamebuf, sizeof rnamebuf,
+ "Unknown UID %d", (int) RealUid);
+ RunAsUserName = RealUserName = rnamebuf;
+ user_info.smdbu_id = RunAsUid;
+ user_info.smdbu_group_id = RunAsGid;
+ (void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
+ SMDB_MAX_USER_NAME_LEN);
+
+#define OPTIONS "C:D:Nc:deflorst:uv"
+ while ((opt = getopt(argc, argv, OPTIONS)) != -1)
+ {
+ switch (opt)
+ {
+ case 'C':
+ cfile = optarg;
+ break;
+
+ case 'N':
+ inclnull = true;
+ break;
+
+ case 'c':
+ params.smdbp_cache_size = atol(optarg);
+ break;
+
+ case 'd':
+ params.smdbp_allow_dup = true;
+ break;
+
+ case 'e':
+ allowempty = true;
+ break;
+
+ case 'f':
+ foldcase = false;
+ break;
+
+ case 'D':
+ comment = *optarg;
+ break;
+
+ case 'l':
+ smdb_print_available_types();
+ exit(EX_OK);
+ break;
+
+ case 'o':
+ notrunc = true;
+ break;
+
+ case 'r':
+ allowreplace = true;
+ break;
+
+ case 's':
+ setbitn(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail);
+ setbitn(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail);
+ setbitn(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail);
+ setbitn(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail);
+ break;
+
+ case 't':
+ if (optarg == NULL || *optarg == '\0')
+ {
+ sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "Invalid separator\n");
+ break;
+ }
+ sep = *optarg;
+ break;
+
+ case 'u':
+ unmake = true;
+ break;
+
+ case 'v':
+ verbose = true;
+ break;
+
+ default:
+ usage(progname);
+ /* NOTREACHED */
+ }
+ }
+
+ if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
+ sff |= SFF_NOSLINK;
+ if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
+ sff |= SFF_NOHLINK;
+ if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
+ sff |= SFF_NOWLINK;
+
+ argc -= optind;
+ argv += optind;
+ if (argc != 2)
+ {
+ usage(progname);
+ /* NOTREACHED */
+ }
+ else
+ {
+ typename = argv[0];
+ mapname = argv[1];
+ }
+
+#if HASFCHOWN
+ /* Find TrustedUser value in sendmail.cf */
+ if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY,
+ NULL)) == NULL)
+ {
+ sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "makemap: %s: %s",
+ cfile, sm_errstring(errno));
+ exit(EX_NOINPUT);
+ }
+ while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL)
+ {
+ register char *b;
+
+ if ((b = strchr(buf, '\n')) != NULL)
+ *b = '\0';
+
+ b = buf;
+ switch (*b++)
+ {
+ case 'O': /* option */
+ if (strncasecmp(b, " TrustedUser", 12) == 0 &&
+ !(isascii(b[12]) && isalnum(b[12])))
+ {
+ b = strchr(b, '=');
+ if (b == NULL)
+ continue;
+ while (isascii(*++b) && isspace(*b))
+ continue;
+ if (isascii(*b) && isdigit(*b))
+ TrustedUid = atoi(b);
+ else
+ {
+ TrustedUid = 0;
+ pw = getpwnam(b);
+ if (pw == NULL)
+ (void) sm_io_fprintf(smioerr,
+ SM_TIME_DEFAULT,
+ "TrustedUser: unknown user %s\n", b);
+ else
+ TrustedUid = pw->pw_uid;
+ }
+
+# ifdef UID_MAX
+ if (TrustedUid > UID_MAX)
+ {
+ (void) sm_io_fprintf(smioerr,
+ SM_TIME_DEFAULT,
+ "TrustedUser: uid value (%ld) > UID_MAX (%ld)",
+ (long) TrustedUid,
+ (long) UID_MAX);
+ TrustedUid = 0;
+ }
+# endif /* UID_MAX */
+ break;
+ }
+
+
+ default:
+ continue;
+ }
+ }
+ (void) sm_io_close(cfp, SM_TIME_DEFAULT);
+#endif /* HASFCHOWN */
+
+ if (!params.smdbp_allow_dup && !allowreplace)
+ putflags = SMDBF_NO_OVERWRITE;
+
+ if (unmake)
+ {
+ mode = O_RDONLY;
+ smode = S_IRUSR;
+ }
+ else
+ {
+ mode = O_RDWR;
+ if (!notrunc)
+ {
+ mode |= O_CREAT|O_TRUNC;
+ sff |= SFF_CREAT;
+ }
+ smode = S_IWUSR;
+ }
+
+ params.smdbp_num_elements = 4096;
+
+ errno = smdb_open_database(&database, mapname, mode, smode, sff,
+ typename, &user_info, &params);
+ if (errno != SMDBE_OK)
+ {
+ char *hint;
+
+ if (errno == SMDBE_UNSUPPORTED_DB_TYPE &&
+ (hint = smdb_db_definition(typename)) != NULL)
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: Need to recompile with -D%s for %s support\n",
+ progname, hint, typename);
+ else
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: error opening type %s map %s: %s\n",
+ progname, typename, mapname,
+ sm_errstring(errno));
+ exit(EX_CANTCREAT);
+ }
+
+ (void) database->smdb_sync(database, 0);
+
+ if (!unmake && geteuid() == 0 && TrustedUid != 0)
+ {
+ errno = database->smdb_set_owner(database, TrustedUid, -1);
+ if (errno != SMDBE_OK)
+ {
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "WARNING: ownership change on %s failed %s",
+ mapname, sm_errstring(errno));
+ }
+ }
+
+ /*
+ ** Copy the data
+ */
+
+ exitstat = EX_OK;
+ if (unmake)
+ {
+ errno = database->smdb_cursor(database, &cursor, 0);
+ if (errno != SMDBE_OK)
+ {
+
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: cannot make cursor for type %s map %s\n",
+ progname, typename, mapname);
+ exit(EX_SOFTWARE);
+ }
+
+ memset(&db_key, '\0', sizeof db_key);
+ memset(&db_val, '\0', sizeof db_val);
+
+ for (lineno = 0; ; lineno++)
+ {
+ errno = cursor->smdbc_get(cursor, &db_key, &db_val,
+ SMDB_CURSOR_GET_NEXT);
+ if (errno != SMDBE_OK)
+ break;
+
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "%.*s\t%.*s\n",
+ (int) db_key.size,
+ (char *) db_key.data,
+ (int) db_val.size,
+ (char *)db_val.data);
+
+ }
+ (void) cursor->smdbc_close(cursor);
+ }
+ else
+ {
+ lineno = 0;
+ while (sm_io_fgets(smioin, SM_TIME_DEFAULT, ibuf, sizeof ibuf)
+ != NULL)
+ {
+ register char *p;
+
+ lineno++;
+
+ /*
+ ** Parse the line.
+ */
+
+ p = strchr(ibuf, '\n');
+ if (p != NULL)
+ *p = '\0';
+ else if (!sm_io_eof(smioin))
+ {
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: %s: line %u: line too long (%ld bytes max)\n",
+ progname, mapname, lineno,
+ (long) sizeof ibuf);
+ exitstat = EX_DATAERR;
+ continue;
+ }
+
+ if (ibuf[0] == '\0' || ibuf[0] == comment)
+ continue;
+ if (sep == '\0' && isascii(ibuf[0]) && isspace(ibuf[0]))
+ {
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: %s: line %u: syntax error (leading space)\n",
+ progname, mapname, lineno);
+ exitstat = EX_DATAERR;
+ continue;
+ }
+
+ memset(&db_key, '\0', sizeof db_key);
+ memset(&db_val, '\0', sizeof db_val);
+ db_key.data = ibuf;
+
+ for (p = ibuf; *p != '\0' && !(ISSEP(*p)); p++)
+ {
+ if (foldcase && isascii(*p) && isupper(*p))
+ *p = tolower(*p);
+ }
+ db_key.size = p - ibuf;
+ if (inclnull)
+ db_key.size++;
+
+ if (*p != '\0')
+ *p++ = '\0';
+ while (*p != '\0' && ISSEP(*p))
+ p++;
+ if (!allowempty && *p == '\0')
+ {
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: %s: line %u: no RHS for LHS %s\n",
+ progname, mapname, lineno,
+ (char *) db_key.data);
+ exitstat = EX_DATAERR;
+ continue;
+ }
+
+ db_val.data = p;
+ db_val.size = strlen(p);
+ if (inclnull)
+ db_val.size++;
+
+ /*
+ ** Do the database insert.
+ */
+
+ if (verbose)
+ {
+ (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "key=`%s', val=`%s'\n",
+ (char *) db_key.data,
+ (char *) db_val.data);
+ }
+
+ errno = database->smdb_put(database, &db_key, &db_val,
+ putflags);
+ switch (errno)
+ {
+ case SMDBE_KEY_EXIST:
+ st = 1;
+ break;
+
+ case 0:
+ st = 0;
+ break;
+
+ default:
+ st = -1;
+ break;
+ }
+
+ if (st < 0)
+ {
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: %s: line %u: key %s: put error: %s\n",
+ progname, mapname, lineno,
+ (char *) db_key.data,
+ sm_errstring(errno));
+ exitstat = EX_IOERR;
+ }
+ else if (st > 0)
+ {
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: %s: line %u: key %s: duplicate key\n",
+ progname, mapname,
+ lineno,
+ (char *) db_key.data);
+ exitstat = EX_DATAERR;
+ }
+ }
+ }
+
+ /*
+ ** Now close the database.
+ */
+
+ errno = database->smdb_close(database);
+ if (errno != SMDBE_OK)
+ {
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: close(%s): %s\n",
+ progname, mapname, sm_errstring(errno));
+ exitstat = EX_IOERR;
+ }
+ smdb_free_database(database);
+
+ exit(exitstat);
+
+ /* NOTREACHED */
+ return exitstat;
+}
OpenPOWER on IntegriCloud