2 * Copyright (c) 1998-2002, 2004, 2008 Proofpoint, Inc. and its suppliers.
4 * Copyright (c) 1992 Eric P. Allman. All rights reserved.
5 * Copyright (c) 1992, 1993
6 * The Regents of the University of California. All rights reserved.
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.
17 "@(#) Copyright (c) 1998-2002, 2004 Proofpoint, Inc. and its suppliers.\n\
18 All rights reserved.\n\
19 Copyright (c) 1992 Eric P. Allman. All rights reserved.\n\
20 Copyright (c) 1992, 1993\n\
21 The Regents of the University of California. All rights reserved.\n")
23 SM_IDSTR(id, "@(#)$Id: makemap.c,v 8.183 2013-11-22 20:51:52 ca Exp $")
26 #include <sys/types.h>
28 # include <sys/file.h>
34 # undef EX_OK /* unistd.h may have another use for this */
37 #include <sendmail/sendmail.h>
39 #include <sendmail/pathnames.h>
40 #include <libsmdb/smdb.h>
49 bool DontInitGroups = false;
51 BITMAP256 DontBlameSendmail;
54 #define ISASCII(c) isascii((unsigned char)(c))
55 #define ISSEP(c) (sep == '\0' ? ISASCII(c) && isspace(c) : (c) == sep)
57 static void usage __P((const char *));
58 static char *readcf __P((const char *, char *, bool));
64 sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
65 "Usage: %s [-C cffile] [-N] [-c cachesize] [-D commentchar]\n",
67 sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
68 " %*s [-d] [-e] [-f] [-l] [-o] [-r] [-s] [-t delimiter]\n",
69 (int) strlen(progname), "");
70 sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
71 " %*s [-u] [-v] type mapname\n",
72 (int) strlen(progname), "");
77 ** READCF -- read some settings from configuration file.
80 ** cfile -- configuration file name.
81 ** mapfile -- file name of map to look up (if not NULL/empty)
82 ** Note: this finds the first match, so in case someone
83 ** uses the same map file for different maps, they are
84 ** hopefully using the same map type.
85 ** fullpath -- compare the full paths or just the "basename"s?
86 ** (even excluding any .ext !)
89 ** pointer to map class name (static!)
93 readcf(cfile, mapfile, fullpath)
100 static char classbuf[MAXLINE];
104 if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile,
105 SM_IO_RDONLY, NULL)) == NULL)
107 sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
109 cfile, sm_errstring(errno));
115 if (!fullpath && mapfile != NULL)
117 p = strrchr(mapfile, '/');
120 p = strrchr(mapfile, '.');
125 while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0)
129 if ((b = strchr(buf, '\n')) != NULL)
135 case 'O': /* option */
137 if (strncasecmp(b, " TrustedUser", 12) == 0 &&
138 !(ISASCII(b[12]) && isalnum(b[12])))
143 while (ISASCII(*++b) && isspace(*b))
145 if (ISASCII(*b) && isdigit(*b))
146 TrustedUid = atoi(b);
154 (void) sm_io_fprintf(smioerr,
156 "TrustedUser: unknown user %s\n", b);
158 TrustedUid = pw->pw_uid;
162 if (TrustedUid > UID_MAX)
164 (void) sm_io_fprintf(smioerr,
166 "TrustedUser: uid value (%ld) > UID_MAX (%ld)",
171 # endif /* UID_MAX */
173 #endif /* HASFCHOWN */
176 case 'K': /* Keyfile (map) */
177 if (classname != NULL) /* found it already */
179 if (mapfile == NULL || *mapfile == '\0')
182 /* cut off trailing spaces */
183 for (p = buf + strlen(buf) - 1; ISASCII(*p) && isspace(*p) && p > buf; p--)
186 /* find the last argument */
187 p = strrchr(buf, ' ');
190 b = strstr(p, mapfile);
202 /* allow trailing white space? */
203 if (strcmp(mapfile, b) != 0)
205 /* SM_ASSERT(b > buf); */
209 if (!isspace(*b) && fullpath)
211 if (!fullpath && !(SM_IS_DIR_DELIM(*b) || isspace(*b)))
214 /* basically from readcf.c */
215 for (b = buf + 1; ISASCII(*b) && isspace(*b); b++)
217 if (!(ISASCII(*b) && isalnum(*b)))
219 /* syserr("readcf: config K line: no map name"); */
223 while ((ISASCII(*++b) && isalnum(*b)) || *b == '_' || *b == '.')
227 while (ISASCII(*b) && isspace(*b))
229 if (!(ISASCII(*b) && isalnum(*b)))
231 /* syserr("readcf: config K line, map %s: no map class", b); */
235 while (ISASCII(*++b) && isalnum(*b))
239 (void) sm_strlcpy(classbuf, classname, sizeof classbuf);
246 (void) sm_io_close(cfp, SM_TIME_DEFAULT);
258 bool inclnull = false;
259 bool notrunc = false;
260 bool allowreplace = false;
261 bool allowempty = false;
262 bool verbose = false;
263 bool foldcase = true;
265 bool didreadcf = false;
270 char *typename = NULL;
271 char *fallback = NULL;
272 char *mapname = NULL;
278 long sff = SFF_ROOTOK|SFF_REGONLY;
280 SMDB_DATABASE *database;
282 SMDB_DBENT db_key, db_val;
283 SMDB_DBPARAMS params;
284 SMDB_USER_INFO user_info;
286 static char rnamebuf[MAXNAME]; /* holds RealUserName */
290 memset(¶ms, '\0', sizeof params);
291 params.smdbp_cache_size = 1024 * 1024;
293 progname = strrchr(argv[0], '/');
294 if (progname != NULL)
298 cfile = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL);
300 clrbitmap(DontBlameSendmail);
301 RunAsUid = RealUid = getuid();
302 RunAsGid = RealGid = getgid();
303 pw = getpwuid(RealUid);
305 (void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf);
307 (void) sm_snprintf(rnamebuf, sizeof rnamebuf,
308 "Unknown UID %d", (int) RealUid);
309 RunAsUserName = RealUserName = rnamebuf;
310 user_info.smdbu_id = RunAsUid;
311 user_info.smdbu_group_id = RunAsGid;
312 (void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
313 SMDB_MAX_USER_NAME_LEN);
315 #define OPTIONS "C:D:Nc:defi:Llorst:uvx"
316 while ((opt = getopt(argc, argv, OPTIONS)) != -1)
329 params.smdbp_cache_size = atol(optarg);
333 params.smdbp_allow_dup = true;
353 smdb_print_available_types(false);
354 sm_io_fprintf(smioout, SM_TIME_DEFAULT,
360 smdb_print_available_types(false);
373 setbitn(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail);
374 setbitn(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail);
375 setbitn(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail);
376 setbitn(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail);
380 if (optarg == NULL || *optarg == '\0')
382 sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
383 "Invalid separator\n");
398 smdb_print_available_types(true);
408 if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
410 if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
412 if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
428 #define TYPEFROMCF (strcasecmp(typename, "cf") == 0)
429 #define FULLPATHFROMCF (strcmp(typename, "cf") == 0)
435 typename = readcf(cfile, mapname, FULLPATHFROMCF);
437 (void) readcf(cfile, NULL, false);
440 #endif /* HASFCHOWN */
442 if (!params.smdbp_allow_dup && !allowreplace)
443 putflags = SMDBF_NO_OVERWRITE;
455 mode |= O_CREAT|O_TRUNC;
461 params.smdbp_num_elements = 4096;
463 if (!didreadcf && TYPEFROMCF)
465 typename = readcf(cfile, mapname, FULLPATHFROMCF);
468 if (didreadcf && (typename == NULL || *typename == '\0'))
470 if (fallback != NULL && *fallback != '\0')
474 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
475 "%s: mapfile %s: not found in %s, using fallback %s\n",
476 progname, mapname, cfile, fallback);
480 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
481 "%s: mapfile %s: not found in %s\n",
482 progname, mapname, cfile);
488 ** Note: if "implicit" is selected it does not work like
489 ** sendmail: it will just use the first available DB type,
490 ** it won't try several (for -u) to find one that "works".
493 errno = smdb_open_database(&database, mapname, mode, smode, sff,
494 typename, &user_info, ¶ms);
495 if (errno != SMDBE_OK)
499 if (errno == SMDBE_UNSUPPORTED_DB_TYPE &&
500 (hint = smdb_db_definition(typename)) != NULL)
501 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
502 "%s: Need to recompile with -D%s for %s support\n",
503 progname, hint, typename);
505 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
506 "%s: error opening type %s map %s: %s\n",
507 progname, typename, mapname,
508 sm_errstring(errno));
512 (void) database->smdb_sync(database, 0);
514 if (!unmake && geteuid() == 0 && TrustedUid != 0)
516 errno = database->smdb_set_owner(database, TrustedUid, -1);
517 if (errno != SMDBE_OK)
519 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
520 "WARNING: ownership change on %s failed %s",
521 mapname, sm_errstring(errno));
532 errno = database->smdb_cursor(database, &cursor, 0);
533 if (errno != SMDBE_OK)
536 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
537 "%s: cannot make cursor for type %s map %s\n",
538 progname, typename, mapname);
542 memset(&db_key, '\0', sizeof db_key);
543 memset(&db_val, '\0', sizeof db_val);
545 for (lineno = 0; ; lineno++)
547 errno = cursor->smdbc_get(cursor, &db_key, &db_val,
548 SMDB_CURSOR_GET_NEXT);
549 if (errno != SMDBE_OK)
552 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
555 (char *) db_key.data,
556 (sep != '\0') ? sep : '\t',
558 (char *)db_val.data);
561 (void) cursor->smdbc_close(cursor);
566 while (sm_io_fgets(smioin, SM_TIME_DEFAULT, ibuf, sizeof ibuf)
577 p = strchr(ibuf, '\n');
580 else if (!sm_io_eof(smioin))
582 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
583 "%s: %s: line %u: line too long (%ld bytes max)\n",
584 progname, mapname, lineno,
586 exitstat = EX_DATAERR;
590 if (ibuf[0] == '\0' || ibuf[0] == comment)
592 if (sep == '\0' && ISASCII(ibuf[0]) && isspace(ibuf[0]))
594 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
595 "%s: %s: line %u: syntax error (leading space)\n",
596 progname, mapname, lineno);
597 exitstat = EX_DATAERR;
601 memset(&db_key, '\0', sizeof db_key);
602 memset(&db_val, '\0', sizeof db_val);
605 for (p = ibuf; *p != '\0' && !(ISSEP(*p)); p++)
607 if (foldcase && ISASCII(*p) && isupper(*p))
610 db_key.size = p - ibuf;
616 while (*p != '\0' && ISSEP(*p))
618 if (!allowempty && *p == '\0')
620 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
621 "%s: %s: line %u: no RHS for LHS %s\n",
622 progname, mapname, lineno,
623 (char *) db_key.data);
624 exitstat = EX_DATAERR;
629 db_val.size = strlen(p);
634 ** Do the database insert.
639 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
640 "key=`%s', val=`%s'\n",
641 (char *) db_key.data,
642 (char *) db_val.data);
645 errno = database->smdb_put(database, &db_key, &db_val,
649 case SMDBE_KEY_EXIST:
664 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
665 "%s: %s: line %u: key %s: put error: %s\n",
666 progname, mapname, lineno,
667 (char *) db_key.data,
668 sm_errstring(errno));
673 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
674 "%s: %s: line %u: key %s: duplicate key\n",
677 (char *) db_key.data);
678 exitstat = EX_DATAERR;
684 ** Now close the database.
687 errno = database->smdb_close(database);
688 if (errno != SMDBE_OK)
690 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
691 "%s: close(%s): %s\n",
692 progname, mapname, sm_errstring(errno));
695 smdb_free_database(database);