summaryrefslogtreecommitdiff
path: root/makemap
diff options
context:
space:
mode:
authorGregory Neil Shapiro <gshapiro@FreeBSD.org>2020-07-14 21:40:53 +0000
committerGregory Neil Shapiro <gshapiro@FreeBSD.org>2020-07-14 21:40:53 +0000
commitcee0d44ab388e12fbd62fdb134d295c58901148a (patch)
treefbe464b241337077b941be7126ad3f3f78b19f7f /makemap
parent1c3e417caf2d11608f10043b7e70b6e7ed8711ff (diff)
Diffstat (limited to 'makemap')
-rw-r--r--makemap/Makefile2
-rw-r--r--makemap/Makefile.m41
-rw-r--r--makemap/makemap.088
-rw-r--r--makemap/makemap.815
-rw-r--r--makemap/makemap.c316
5 files changed, 311 insertions, 111 deletions
diff --git a/makemap/Makefile b/makemap/Makefile
index 953d28b37e7e..301a639d437e 100644
--- a/makemap/Makefile
+++ b/makemap/Makefile
@@ -8,6 +8,8 @@ all: FRC
$(SHELL) $(BUILD) $(OPTIONS) $@
clean: FRC
$(SHELL) $(BUILD) $(OPTIONS) $@
+check: FRC
+ $(SHELL) $(BUILD) $(OPTIONS) $@
install: FRC
$(SHELL) $(BUILD) $(OPTIONS) $@
diff --git a/makemap/Makefile.m4 b/makemap/Makefile.m4
index c6dffd0f57f5..9ff01cd25491 100644
--- a/makemap/Makefile.m4
+++ b/makemap/Makefile.m4
@@ -21,4 +21,5 @@ bldPRODUCT_START(`manpage', `makemap')
define(`bldSOURCES', `makemap.8')
bldPRODUCT_END
+
bldFINISH
diff --git a/makemap/makemap.0 b/makemap/makemap.0
index 73d6ef09a37e..61f4d6f868dc 100644
--- a/makemap/makemap.0
+++ b/makemap/makemap.0
@@ -2,20 +2,20 @@ MAKEMAP(8) MAKEMAP(8)
-NNAAMMEE
+NAME
makemap - create database maps for sendmail
-SSYYNNOOPPSSIISS
- mmaakkeemmaapp [--CC _f_i_l_e] [--NN] [--cc _c_a_c_h_e_s_i_z_e] [--dd] [--DD _c_o_m_m_e_n_t_c_h_a_r] [--ee] [--ff]
- [--ll] [--oo] [--rr] [--ss] [--tt _d_e_l_i_m] [--uu] [--vv] _m_a_p_t_y_p_e _m_a_p_n_a_m
+SYNOPSIS
+ makemap [-C file] [-N] [-c cachesize] [-d] [-D commentchar] [-e] [-f]
+ [-l] [-o] [-r] [-s] [-t delim] [-u] [-v] maptype mapnam
-DDEESSCCRRIIPPTTIIOONN
- MMaakkeemmaapp creates the database maps used by the keyed map lookups in
+DESCRIPTION
+ Makemap creates the database maps used by the keyed map lookups in
sendmail(8). It reads input from the standard input and outputs them
- to the indicated _m_a_p_n_a_m_e_.
+ to the indicated mapname.
- Depending on how it is compiled, mmaakkeemmaapp handles up to three different
- database formats, selected using the _m_a_p_t_y_p_e parameter. They may be
+ Depending on how it is compiled, makemap handles different database
+ formats, selected using the maptype parameter. They may be
dbm DBM format maps. This requires the ndbm(3) library.
@@ -23,67 +23,79 @@ DDEESSCCRRIIPPTTIIOONN
hash Hash format maps. This also requires the Berkeley DB library.
- In all cases, mmaakkeemmaapp reads lines from the standard input consisting of
+ cdb CDB (Constant DataBase) format maps. This requires the tinycdb
+ library.
+
+ implicit
+ The first available format in the following order: hash, dbm,
+ and cdb.
+
+ In all cases, makemap reads lines from the standard input consisting of
two words separated by white space. The first is the database key, the
- second is the value. The value may contain ``%_n'' strings to indicate
+ second is the value. The value may contain ``%n'' strings to indicate
parameter substitution. Literal percents should be doubled (``%%'').
Blank lines and lines beginning with ``#'' are ignored.
- Notice: do nnoott use mmaakkeemmaapp to create the aliases data base, but
- nneewwaalliiaasseess which puts a special token into the data base that is
- required by sseennddmmaaiill..
+ Notice: do not use makemap to create the aliases data base, but
+ newaliases which puts a special token into the data base that is
+ required by sendmail.
- If the _T_r_u_s_t_e_d_U_s_e_r option is set in the sendmail configuration file and
- mmaakkeemmaapp is invoked as root, the generated files will be owned by the
- specified _T_r_u_s_t_e_d_U_s_e_r_.
+ If the TrustedUser option is set in the sendmail configuration file and
+ makemap is invoked as root, the generated files will be owned by the
+ specified TrustedUser.
- FFllaaggss
- --CC Use the specified sseennddmmaaiill configuration file for looking up the
+ Flags
+ -C Use the specified sendmail configuration file for looking up the
TrustedUser option.
- --NN Include the null byte that terminates strings in the map. This
+ -N Include the null byte that terminates strings in the map. This
must match the -N flag in the sendmail.cf ``K'' line.
- --cc Use the specified hash and B-Tree cache size.
+ -c Use the specified hash and B-Tree cache size.
- --DD Use to specify the character to use to indicate a comment (which
+ -D Use to specify the character to use to indicate a comment (which
is ignored) instead of the default of '#'.
- --dd Allow duplicate keys in the map. This is only allowed on B-Tree
+ -d Allow duplicate keys in the map. This is only allowed on B-Tree
format maps. If two identical keys are read, they will both be
inserted into the map.
- --ee Allow empty value (right hand side).
+ -e Allow empty value (right hand side).
- --ff Normally all upper case letters in the key are folded to lower
+ -f Normally all upper case letters in the key are folded to lower
case. This flag disables that behaviour. This is intended to
- mesh with the -f flag in the KK line in sendmail.cf. The value
+ mesh with the -f flag in the K line in sendmail.cf. The value
is never case folded.
- --ll List supported map types.
+ -l List supported map types.
- --oo Append to an old file. This allows you to augment an existing
- file.
+ -o Append to an old file. This allows you to augment an existing
+ file. Note: this might not be supported by all database types,
+ e.g., cdb.
- --rr Allow replacement of existing keys. Normally mmaakkeemmaapp complains
+ -r Allow replacement of existing keys. Normally makemap complains
if you repeat a key, and does not do the insert.
- --ss Ignore safety checks on maps being created. This includes
- checking for hard or symbolic links in world writable directo-
+ -s Ignore safety checks on maps being created. This includes
+ checking for hard or symbolic links in world writable directo-
ries.
- --tt Use the specified delimiter instead of white space (also for
+ -t Use the specified delimiter instead of white space (also for
dumping a map).
- --uu dump (unmap) the content of the database to standard output.
+ -u dump (unmap) the content of the database to standard output.
+
+ -v Verbosely print what it is doing.
+
- --vv Verbosely print what it is doing.
+Example
+ makemap hash /etc/mail/access < /etc/mail/access
-SSEEEE AALLSSOO
+SEE ALSO
sendmail(8), newaliases(1)
-HHIISSTTOORRYY
- The mmaakkeemmaapp command appeared in 4.4BSD.
+HISTORY
+ The makemap command appeared in 4.4BSD.
diff --git a/makemap/makemap.8 b/makemap/makemap.8
index a6bfd21462c4..fa250109b842 100644
--- a/makemap/makemap.8
+++ b/makemap/makemap.8
@@ -46,7 +46,7 @@ and outputs them to the indicated
.PP
Depending on how it is compiled,
.B makemap
-handles up to three different database formats,
+handles different database formats,
selected using the
.I maptype
parameter.
@@ -67,6 +67,14 @@ hash
Hash format maps.
This also requires the Berkeley DB
library.
+.TP
+cdb
+CDB (Constant DataBase) format maps.
+This requires the tinycdb library.
+.TP
+implicit
+The first available format in the following order:
+hash, dbm, and cdb.
.PP
In all cases,
.B makemap
@@ -142,6 +150,8 @@ List supported map types.
.B \-o
Append to an old file.
This allows you to augment an existing file.
+Note: this might not be supported by all database types,
+e.g., cdb.
.TP
.B \-r
Allow replacement of existing keys.
@@ -164,6 +174,9 @@ dump (unmap) the content of the database to standard output.
.TP
.B \-v
Verbosely print what it is doing.
+.P
+.SH Example
+makemap hash /etc/mail/access < /etc/mail/access
.SH SEE ALSO
sendmail(8), newaliases(1)
.SH HISTORY
diff --git a/makemap/makemap.c b/makemap/makemap.c
index cf1f62c8ea9e..4aa8d6ddab38 100644
--- a/makemap/makemap.c
+++ b/makemap/makemap.c
@@ -26,15 +26,16 @@ SM_IDSTR(id, "@(#)$Id: makemap.c,v 8.183 2013-11-22 20:51:52 ca Exp $")
#include <sys/types.h>
#ifndef ISC_UNIX
# include <sys/file.h>
-#endif /* ! ISC_UNIX */
+#endif
#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 */
+#endif
#include <sysexits.h>
#include <sendmail/sendmail.h>
+#include <sm/path.h>
#include <sendmail/pathnames.h>
#include <libsmdb/smdb.h>
@@ -50,13 +51,15 @@ uid_t TrustedUid = 0;
BITMAP256 DontBlameSendmail;
#define BUFSIZE 1024
-#define ISSEP(c) (sep == '\0' ? isascii(c) && isspace(c) : (c) == sep)
+#define ISASCII(c) isascii((unsigned char)(c))
+#define ISSEP(c) (sep == '\0' ? ISASCII(c) && isspace(c) : (c) == sep)
-static void usage __P((char *));
+static void usage __P((const char *));
+static char *readcf __P((const char *, char *, bool));
static void
usage(progname)
- char *progname;
+ const char *progname;
{
sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
"Usage: %s [-C cffile] [-N] [-c cachesize] [-D commentchar]\n",
@@ -70,6 +73,181 @@ usage(progname)
exit(EX_USAGE);
}
+/*
+** READCF -- read some settings from configuration file.
+**
+** Parameters:
+** cfile -- configuration file name.
+** mapfile -- file name of map to look up (if not NULL/empty)
+** Note: this finds the first match, so in case someone
+** uses the same map file for different maps, they are
+** hopefully using the same map type.
+** fullpath -- compare the full paths or just the "basename"s?
+** (even excluding any .ext !)
+**
+** Returns:
+** pointer to map class name (static!)
+*/
+
+static char *
+readcf(cfile, mapfile, fullpath)
+ const char *cfile;
+ char *mapfile;
+ bool fullpath;
+{
+ SM_FILE_T *cfp;
+ char buf[MAXLINE];
+ static char classbuf[MAXLINE];
+ char *classname;
+ char *p;
+
+ 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\n",
+ cfile, sm_errstring(errno));
+ exit(EX_NOINPUT);
+ }
+ classname = NULL;
+ classbuf[0] = '\0';
+
+ if (!fullpath && mapfile != NULL)
+ {
+ p = strrchr(mapfile, '/');
+ if (p != NULL)
+ mapfile = ++p;
+ p = strrchr(mapfile, '.');
+ if (p != NULL)
+ *p = '\0';
+ }
+
+ while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0)
+ {
+ char *b;
+
+ if ((b = strchr(buf, '\n')) != NULL)
+ *b = '\0';
+
+ b = buf;
+ switch (*b++)
+ {
+ case 'O': /* option */
+#if HASFCHOWN
+ 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
+ {
+ struct passwd *pw;
+
+ 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 */
+ }
+#endif /* HASFCHOWN */
+ break;
+
+ case 'K': /* Keyfile (map) */
+ if (classname != NULL) /* found it already */
+ continue;
+ if (mapfile == NULL || *mapfile == '\0')
+ continue;
+
+ /* cut off trailing spaces */
+ for (p = buf + strlen(buf) - 1; ISASCII(*p) && isspace(*p) && p > buf; p--)
+ *p = '\0';
+
+ /* find the last argument */
+ p = strrchr(buf, ' ');
+ if (p == NULL)
+ continue;
+ b = strstr(p, mapfile);
+ if (b == NULL)
+ continue;
+ if (b <= buf)
+ continue;
+ if (!fullpath)
+ {
+ p = strrchr(b, '.');
+ if (p != NULL)
+ *p = '\0';
+ }
+
+ /* allow trailing white space? */
+ if (strcmp(mapfile, b) != 0)
+ continue;
+ /* SM_ASSERT(b > buf); */
+ --b;
+ if (!ISASCII(*b))
+ continue;
+ if (!isspace(*b) && fullpath)
+ continue;
+ if (!fullpath && !(SM_IS_DIR_DELIM(*b) || isspace(*b)))
+ continue;
+
+ /* basically from readcf.c */
+ for (b = buf + 1; ISASCII(*b) && isspace(*b); b++)
+ ;
+ if (!(ISASCII(*b) && isalnum(*b)))
+ {
+ /* syserr("readcf: config K line: no map name"); */
+ return NULL;
+ }
+
+ while ((ISASCII(*++b) && isalnum(*b)) || *b == '_' || *b == '.')
+ ;
+ if (*b != '\0')
+ *b++ = '\0';
+ while (ISASCII(*b) && isspace(*b))
+ b++;
+ if (!(ISASCII(*b) && isalnum(*b)))
+ {
+ /* syserr("readcf: config K line, map %s: no map class", b); */
+ return NULL;
+ }
+ classname = b;
+ while (ISASCII(*++b) && isalnum(*b))
+ ;
+ if (*b != '\0')
+ *b++ = '\0';
+ (void) sm_strlcpy(classbuf, classname, sizeof classbuf);
+ break;
+
+ default:
+ continue;
+ }
+ }
+ (void) sm_io_close(cfp, SM_TIME_DEFAULT);
+
+ return classbuf;
+}
+
int
main(argc, argv)
int argc;
@@ -84,11 +262,13 @@ main(argc, argv)
bool verbose = false;
bool foldcase = true;
bool unmake = false;
+ bool didreadcf = false;
char sep = '\0';
char comment = '#';
int exitstat;
int opt;
char *typename = NULL;
+ char *fallback = NULL;
char *mapname = NULL;
unsigned int lineno;
int st;
@@ -103,10 +283,6 @@ main(argc, argv)
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;
@@ -136,7 +312,7 @@ main(argc, argv)
(void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
SMDB_MAX_USER_NAME_LEN);
-#define OPTIONS "C:D:Nc:deflorst:uv"
+#define OPTIONS "C:D:Nc:defi:Llorst:uvx"
while ((opt = getopt(argc, argv, OPTIONS)) != -1)
{
switch (opt)
@@ -165,12 +341,23 @@ main(argc, argv)
foldcase = false;
break;
+ case 'i':
+ fallback =optarg;
+ break;
+
case 'D':
comment = *optarg;
break;
+ case 'L':
+ smdb_print_available_types(false);
+ sm_io_fprintf(smioout, SM_TIME_DEFAULT,
+ "cf\nCF\n");
+ exit(EX_OK);
+ break;
+
case 'l':
- smdb_print_available_types();
+ smdb_print_available_types(false);
exit(EX_OK);
break;
@@ -206,6 +393,11 @@ main(argc, argv)
case 'v':
verbose = true;
break;
+
+ case 'x':
+ smdb_print_available_types(true);
+ exit(EX_OK);
+ break;
default:
usage(progname);
@@ -233,68 +425,18 @@ main(argc, argv)
mapname = argv[1];
}
+#define TYPEFROMCF (strcasecmp(typename, "cf") == 0)
+#define FULLPATHFROMCF (strcmp(typename, "cf") == 0)
+
#if HASFCHOWN
- /* Find TrustedUser value in sendmail.cf */
- if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY,
- NULL)) == NULL)
+ if (geteuid() == 0)
{
- sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "makemap: %s: %s\n",
- cfile, sm_errstring(errno));
- exit(EX_NOINPUT);
- }
- while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0)
- {
- 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;
- }
+ if (TYPEFROMCF)
+ typename = readcf(cfile, mapname, FULLPATHFROMCF);
+ else
+ (void) readcf(cfile, NULL, false);
+ didreadcf = true;
}
- (void) sm_io_close(cfp, SM_TIME_DEFAULT);
#endif /* HASFCHOWN */
if (!params.smdbp_allow_dup && !allowreplace)
@@ -318,6 +460,36 @@ main(argc, argv)
params.smdbp_num_elements = 4096;
+ if (!didreadcf && TYPEFROMCF)
+ {
+ typename = readcf(cfile, mapname, FULLPATHFROMCF);
+ didreadcf = true;
+ }
+ if (didreadcf && (typename == NULL || *typename == '\0'))
+ {
+ if (fallback != NULL && *fallback != '\0')
+ {
+ typename = fallback;
+ if (verbose)
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: mapfile %s: not found in %s, using fallback %s\n",
+ progname, mapname, cfile, fallback);
+ }
+ else
+ {
+ (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
+ "%s: mapfile %s: not found in %s\n",
+ progname, mapname, cfile);
+ exit(EX_DATAERR);
+ }
+ }
+
+ /*
+ ** Note: if "implicit" is selected it does not work like
+ ** sendmail: it will just use the first available DB type,
+ ** it won't try several (for -u) to find one that "works".
+ */
+
errno = smdb_open_database(&database, mapname, mode, smode, sff,
typename, &user_info, &params);
if (errno != SMDBE_OK)
@@ -417,7 +589,7 @@ main(argc, argv)
if (ibuf[0] == '\0' || ibuf[0] == comment)
continue;
- if (sep == '\0' && isascii(ibuf[0]) && isspace(ibuf[0]))
+ 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",
@@ -432,7 +604,7 @@ main(argc, argv)
for (p = ibuf; *p != '\0' && !(ISSEP(*p)); p++)
{
- if (foldcase && isascii(*p) && isupper(*p))
+ if (foldcase && ISASCII(*p) && isupper(*p))
*p = tolower(*p);
}
db_key.size = p - ibuf;