MFC: following 4 commits:
[dragonfly.git] / contrib / sendmail-8.14 / makemap / makemap.c
blob730274848a7bc00649d243662acb9d093daf7fec
1 /*
2 * Copyright (c) 1998-2002, 2004 Sendmail, Inc. and its suppliers.
3 * All rights reserved.
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.
14 #include <sm/gen.h>
16 SM_IDSTR(copyright,
17 "@(#) Copyright (c) 1998-2002, 2004 Sendmail, 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.178 2007/05/11 18:45:39 ca Exp $")
26 #include <sys/types.h>
27 #ifndef ISC_UNIX
28 # include <sys/file.h>
29 #endif /* ! ISC_UNIX */
30 #include <ctype.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #ifdef EX_OK
34 # undef EX_OK /* unistd.h may have another use for this */
35 #endif /* EX_OK */
36 #include <sysexits.h>
37 #include <sendmail/sendmail.h>
38 #include <sendmail/pathnames.h>
39 #include <libsmdb/smdb.h>
41 uid_t RealUid;
42 gid_t RealGid;
43 char *RealUserName;
44 uid_t RunAsUid;
45 gid_t RunAsGid;
46 char *RunAsUserName;
47 int Verbose = 2;
48 bool DontInitGroups = false;
49 uid_t TrustedUid = 0;
50 BITMAP256 DontBlameSendmail;
52 #define BUFSIZE 1024
53 #define ISSEP(c) (sep == '\0' ? isascii(c) && isspace(c) : (c) == sep)
55 static void usage __P((char *));
57 static void
58 usage(progname)
59 char *progname;
61 sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
62 "Usage: %s [-C cffile] [-N] [-c cachesize] [-D commentchar]\n",
63 progname);
64 sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
65 " %*s [-d] [-e] [-f] [-l] [-o] [-r] [-s] [-t delimiter]\n",
66 (int) strlen(progname), "");
67 sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
68 " %*s [-u] [-v] type mapname\n",
69 (int) strlen(progname), "");
70 exit(EX_USAGE);
73 int
74 main(argc, argv)
75 int argc;
76 char **argv;
78 char *progname;
79 char *cfile;
80 bool inclnull = false;
81 bool notrunc = false;
82 bool allowreplace = false;
83 bool allowempty = false;
84 bool verbose = false;
85 bool foldcase = true;
86 bool unmake = false;
87 char sep = '\0';
88 char comment = '#';
89 int exitstat;
90 int opt;
91 char *typename = NULL;
92 char *mapname = NULL;
93 unsigned int lineno;
94 int st;
95 int mode;
96 int smode;
97 int putflags = 0;
98 long sff = SFF_ROOTOK|SFF_REGONLY;
99 struct passwd *pw;
100 SMDB_DATABASE *database;
101 SMDB_CURSOR *cursor;
102 SMDB_DBENT db_key, db_val;
103 SMDB_DBPARAMS params;
104 SMDB_USER_INFO user_info;
105 char ibuf[BUFSIZE];
106 #if HASFCHOWN
107 SM_FILE_T *cfp;
108 char buf[MAXLINE];
109 #endif /* HASFCHOWN */
110 static char rnamebuf[MAXNAME]; /* holds RealUserName */
111 extern char *optarg;
112 extern int optind;
114 memset(&params, '\0', sizeof params);
115 params.smdbp_cache_size = 1024 * 1024;
117 progname = strrchr(argv[0], '/');
118 if (progname != NULL)
119 progname++;
120 else
121 progname = argv[0];
122 cfile = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL);
124 clrbitmap(DontBlameSendmail);
125 RunAsUid = RealUid = getuid();
126 RunAsGid = RealGid = getgid();
127 pw = getpwuid(RealUid);
128 if (pw != NULL)
129 (void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf);
130 else
131 (void) sm_snprintf(rnamebuf, sizeof rnamebuf,
132 "Unknown UID %d", (int) RealUid);
133 RunAsUserName = RealUserName = rnamebuf;
134 user_info.smdbu_id = RunAsUid;
135 user_info.smdbu_group_id = RunAsGid;
136 (void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
137 SMDB_MAX_USER_NAME_LEN);
139 #define OPTIONS "C:D:Nc:deflorst:uv"
140 while ((opt = getopt(argc, argv, OPTIONS)) != -1)
142 switch (opt)
144 case 'C':
145 cfile = optarg;
146 break;
148 case 'N':
149 inclnull = true;
150 break;
152 case 'c':
153 params.smdbp_cache_size = atol(optarg);
154 break;
156 case 'd':
157 params.smdbp_allow_dup = true;
158 break;
160 case 'e':
161 allowempty = true;
162 break;
164 case 'f':
165 foldcase = false;
166 break;
168 case 'D':
169 comment = *optarg;
170 break;
172 case 'l':
173 smdb_print_available_types();
174 exit(EX_OK);
175 break;
177 case 'o':
178 notrunc = true;
179 break;
181 case 'r':
182 allowreplace = true;
183 break;
185 case 's':
186 setbitn(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail);
187 setbitn(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail);
188 setbitn(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail);
189 setbitn(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail);
190 break;
192 case 't':
193 if (optarg == NULL || *optarg == '\0')
195 sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
196 "Invalid separator\n");
197 break;
199 sep = *optarg;
200 break;
202 case 'u':
203 unmake = true;
204 break;
206 case 'v':
207 verbose = true;
208 break;
210 default:
211 usage(progname);
212 /* NOTREACHED */
216 if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
217 sff |= SFF_NOSLINK;
218 if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
219 sff |= SFF_NOHLINK;
220 if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
221 sff |= SFF_NOWLINK;
223 argc -= optind;
224 argv += optind;
225 if (argc != 2)
227 usage(progname);
228 /* NOTREACHED */
230 else
232 typename = argv[0];
233 mapname = argv[1];
236 #if HASFCHOWN
237 /* Find TrustedUser value in sendmail.cf */
238 if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY,
239 NULL)) == NULL)
241 sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "makemap: %s: %s",
242 cfile, sm_errstring(errno));
243 exit(EX_NOINPUT);
245 while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL)
247 register char *b;
249 if ((b = strchr(buf, '\n')) != NULL)
250 *b = '\0';
252 b = buf;
253 switch (*b++)
255 case 'O': /* option */
256 if (strncasecmp(b, " TrustedUser", 12) == 0 &&
257 !(isascii(b[12]) && isalnum(b[12])))
259 b = strchr(b, '=');
260 if (b == NULL)
261 continue;
262 while (isascii(*++b) && isspace(*b))
263 continue;
264 if (isascii(*b) && isdigit(*b))
265 TrustedUid = atoi(b);
266 else
268 TrustedUid = 0;
269 pw = getpwnam(b);
270 if (pw == NULL)
271 (void) sm_io_fprintf(smioerr,
272 SM_TIME_DEFAULT,
273 "TrustedUser: unknown user %s\n", b);
274 else
275 TrustedUid = pw->pw_uid;
278 # ifdef UID_MAX
279 if (TrustedUid > UID_MAX)
281 (void) sm_io_fprintf(smioerr,
282 SM_TIME_DEFAULT,
283 "TrustedUser: uid value (%ld) > UID_MAX (%ld)",
284 (long) TrustedUid,
285 (long) UID_MAX);
286 TrustedUid = 0;
288 # endif /* UID_MAX */
289 break;
293 default:
294 continue;
297 (void) sm_io_close(cfp, SM_TIME_DEFAULT);
298 #endif /* HASFCHOWN */
300 if (!params.smdbp_allow_dup && !allowreplace)
301 putflags = SMDBF_NO_OVERWRITE;
303 if (unmake)
305 mode = O_RDONLY;
306 smode = S_IRUSR;
308 else
310 mode = O_RDWR;
311 if (!notrunc)
313 mode |= O_CREAT|O_TRUNC;
314 sff |= SFF_CREAT;
316 smode = S_IWUSR;
319 params.smdbp_num_elements = 4096;
321 errno = smdb_open_database(&database, mapname, mode, smode, sff,
322 typename, &user_info, &params);
323 if (errno != SMDBE_OK)
325 char *hint;
327 if (errno == SMDBE_UNSUPPORTED_DB_TYPE &&
328 (hint = smdb_db_definition(typename)) != NULL)
329 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
330 "%s: Need to recompile with -D%s for %s support\n",
331 progname, hint, typename);
332 else
333 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
334 "%s: error opening type %s map %s: %s\n",
335 progname, typename, mapname,
336 sm_errstring(errno));
337 exit(EX_CANTCREAT);
340 (void) database->smdb_sync(database, 0);
342 if (!unmake && geteuid() == 0 && TrustedUid != 0)
344 errno = database->smdb_set_owner(database, TrustedUid, -1);
345 if (errno != SMDBE_OK)
347 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
348 "WARNING: ownership change on %s failed %s",
349 mapname, sm_errstring(errno));
354 ** Copy the data
357 exitstat = EX_OK;
358 if (unmake)
360 errno = database->smdb_cursor(database, &cursor, 0);
361 if (errno != SMDBE_OK)
364 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
365 "%s: cannot make cursor for type %s map %s\n",
366 progname, typename, mapname);
367 exit(EX_SOFTWARE);
370 memset(&db_key, '\0', sizeof db_key);
371 memset(&db_val, '\0', sizeof db_val);
373 for (lineno = 0; ; lineno++)
375 errno = cursor->smdbc_get(cursor, &db_key, &db_val,
376 SMDB_CURSOR_GET_NEXT);
377 if (errno != SMDBE_OK)
378 break;
380 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
381 "%.*s\t%.*s\n",
382 (int) db_key.size,
383 (char *) db_key.data,
384 (int) db_val.size,
385 (char *)db_val.data);
388 (void) cursor->smdbc_close(cursor);
390 else
392 lineno = 0;
393 while (sm_io_fgets(smioin, SM_TIME_DEFAULT, ibuf, sizeof ibuf)
394 != NULL)
396 register char *p;
398 lineno++;
401 ** Parse the line.
404 p = strchr(ibuf, '\n');
405 if (p != NULL)
406 *p = '\0';
407 else if (!sm_io_eof(smioin))
409 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
410 "%s: %s: line %u: line too long (%ld bytes max)\n",
411 progname, mapname, lineno,
412 (long) sizeof ibuf);
413 exitstat = EX_DATAERR;
414 continue;
417 if (ibuf[0] == '\0' || ibuf[0] == comment)
418 continue;
419 if (sep == '\0' && isascii(ibuf[0]) && isspace(ibuf[0]))
421 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
422 "%s: %s: line %u: syntax error (leading space)\n",
423 progname, mapname, lineno);
424 exitstat = EX_DATAERR;
425 continue;
428 memset(&db_key, '\0', sizeof db_key);
429 memset(&db_val, '\0', sizeof db_val);
430 db_key.data = ibuf;
432 for (p = ibuf; *p != '\0' && !(ISSEP(*p)); p++)
434 if (foldcase && isascii(*p) && isupper(*p))
435 *p = tolower(*p);
437 db_key.size = p - ibuf;
438 if (inclnull)
439 db_key.size++;
441 if (*p != '\0')
442 *p++ = '\0';
443 while (*p != '\0' && ISSEP(*p))
444 p++;
445 if (!allowempty && *p == '\0')
447 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
448 "%s: %s: line %u: no RHS for LHS %s\n",
449 progname, mapname, lineno,
450 (char *) db_key.data);
451 exitstat = EX_DATAERR;
452 continue;
455 db_val.data = p;
456 db_val.size = strlen(p);
457 if (inclnull)
458 db_val.size++;
461 ** Do the database insert.
464 if (verbose)
466 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
467 "key=`%s', val=`%s'\n",
468 (char *) db_key.data,
469 (char *) db_val.data);
472 errno = database->smdb_put(database, &db_key, &db_val,
473 putflags);
474 switch (errno)
476 case SMDBE_KEY_EXIST:
477 st = 1;
478 break;
480 case 0:
481 st = 0;
482 break;
484 default:
485 st = -1;
486 break;
489 if (st < 0)
491 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
492 "%s: %s: line %u: key %s: put error: %s\n",
493 progname, mapname, lineno,
494 (char *) db_key.data,
495 sm_errstring(errno));
496 exitstat = EX_IOERR;
498 else if (st > 0)
500 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
501 "%s: %s: line %u: key %s: duplicate key\n",
502 progname, mapname,
503 lineno,
504 (char *) db_key.data);
505 exitstat = EX_DATAERR;
511 ** Now close the database.
514 errno = database->smdb_close(database);
515 if (errno != SMDBE_OK)
517 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
518 "%s: close(%s): %s\n",
519 progname, mapname, sm_errstring(errno));
520 exitstat = EX_IOERR;
522 smdb_free_database(database);
524 exit(exitstat);
526 /* NOTREACHED */
527 return exitstat;