sendmail transition: Do not pre-generate sendmail.cf
[dragonfly.git] / contrib / sendmail-8.14 / makemap / makemap.c
1 /*
2  * Copyright (c) 1998-2002, 2004, 2008 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.
7  *
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.
11  *
12  */
13
14 #include <sm/gen.h>
15
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")
22
23 SM_IDSTR(id, "@(#)$Id: makemap.c,v 8.180 2010/11/23 02:35:08 gshapiro Exp $")
24
25
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>
40
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;
51
52 #define BUFSIZE         1024
53 #define ISSEP(c) (sep == '\0' ? isascii(c) && isspace(c) : (c) == sep)
54
55 static void usage __P((char *));
56
57 static void
58 usage(progname)
59         char *progname;
60 {
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);
71 }
72
73 int
74 main(argc, argv)
75         int argc;
76         char **argv;
77 {
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;
113
114         memset(&params, '\0', sizeof params);
115         params.smdbp_cache_size = 1024 * 1024;
116
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);
123
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);
138
139 #define OPTIONS         "C:D:Nc:deflorst:uv"
140         while ((opt = getopt(argc, argv, OPTIONS)) != -1)
141         {
142                 switch (opt)
143                 {
144                   case 'C':
145                         cfile = optarg;
146                         break;
147
148                   case 'N':
149                         inclnull = true;
150                         break;
151
152                   case 'c':
153                         params.smdbp_cache_size = atol(optarg);
154                         break;
155
156                   case 'd':
157                         params.smdbp_allow_dup = true;
158                         break;
159
160                   case 'e':
161                         allowempty = true;
162                         break;
163
164                   case 'f':
165                         foldcase = false;
166                         break;
167
168                   case 'D':
169                         comment = *optarg;
170                         break;
171
172                   case 'l':
173                         smdb_print_available_types();
174                         exit(EX_OK);
175                         break;
176
177                   case 'o':
178                         notrunc = true;
179                         break;
180
181                   case 'r':
182                         allowreplace = true;
183                         break;
184
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;
191
192                   case 't':
193                         if (optarg == NULL || *optarg == '\0')
194                         {
195                                 sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
196                                               "Invalid separator\n");
197                                 break;
198                         }
199                         sep = *optarg;
200                         break;
201
202                   case 'u':
203                         unmake = true;
204                         break;
205
206                   case 'v':
207                         verbose = true;
208                         break;
209
210                   default:
211                         usage(progname);
212                         /* NOTREACHED */
213                 }
214         }
215
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;
222
223         argc -= optind;
224         argv += optind;
225         if (argc != 2)
226         {
227                 usage(progname);
228                 /* NOTREACHED */
229         }
230         else
231         {
232                 typename = argv[0];
233                 mapname = argv[1];
234         }
235
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)
240         {
241                 sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "makemap: %s: %s\n",
242                               cfile, sm_errstring(errno));
243                 exit(EX_NOINPUT);
244         }
245         while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL)
246         {
247                 register char *b;
248
249                 if ((b = strchr(buf, '\n')) != NULL)
250                         *b = '\0';
251
252                 b = buf;
253                 switch (*b++)
254                 {
255                   case 'O':             /* option */
256                         if (strncasecmp(b, " TrustedUser", 12) == 0 &&
257                             !(isascii(b[12]) && isalnum(b[12])))
258                         {
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
267                                 {
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;
276                                 }
277
278 # ifdef UID_MAX
279                                 if (TrustedUid > UID_MAX)
280                                 {
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;
287                                 }
288 # endif /* UID_MAX */
289                                 break;
290                         }
291
292
293                   default:
294                         continue;
295                 }
296         }
297         (void) sm_io_close(cfp, SM_TIME_DEFAULT);
298 #endif /* HASFCHOWN */
299
300         if (!params.smdbp_allow_dup && !allowreplace)
301                 putflags = SMDBF_NO_OVERWRITE;
302
303         if (unmake)
304         {
305                 mode = O_RDONLY;
306                 smode = S_IRUSR;
307         }
308         else
309         {
310                 mode = O_RDWR;
311                 if (!notrunc)
312                 {
313                         mode |= O_CREAT|O_TRUNC;
314                         sff |= SFF_CREAT;
315                 }
316                 smode = S_IWUSR;
317         }
318
319         params.smdbp_num_elements = 4096;
320
321         errno = smdb_open_database(&database, mapname, mode, smode, sff,
322                                    typename, &user_info, &params);
323         if (errno != SMDBE_OK)
324         {
325                 char *hint;
326
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);
338         }
339
340         (void) database->smdb_sync(database, 0);
341
342         if (!unmake && geteuid() == 0 && TrustedUid != 0)
343         {
344                 errno = database->smdb_set_owner(database, TrustedUid, -1);
345                 if (errno != SMDBE_OK)
346                 {
347                         (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
348                                              "WARNING: ownership change on %s failed %s",
349                                              mapname, sm_errstring(errno));
350                 }
351         }
352
353         /*
354         **  Copy the data
355         */
356
357         exitstat = EX_OK;
358         if (unmake)
359         {
360                 errno = database->smdb_cursor(database, &cursor, 0);
361                 if (errno != SMDBE_OK)
362                 {
363
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);
368                 }
369
370                 memset(&db_key, '\0', sizeof db_key);
371                 memset(&db_val, '\0', sizeof db_val);
372
373                 for (lineno = 0; ; lineno++)
374                 {
375                         errno = cursor->smdbc_get(cursor, &db_key, &db_val,
376                                                   SMDB_CURSOR_GET_NEXT);
377                         if (errno != SMDBE_OK)
378                                 break;
379
380                         (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
381                                              "%.*s%c%.*s\n",
382                                              (int) db_key.size,
383                                              (char *) db_key.data,
384                                              (sep != '\0') ? sep : '\t',
385                                              (int) db_val.size,
386                                              (char *)db_val.data);
387
388                 }
389                 (void) cursor->smdbc_close(cursor);
390         }
391         else
392         {
393                 lineno = 0;
394                 while (sm_io_fgets(smioin, SM_TIME_DEFAULT, ibuf, sizeof ibuf)
395                        != NULL)
396                 {
397                         register char *p;
398
399                         lineno++;
400
401                         /*
402                         **  Parse the line.
403                         */
404
405                         p = strchr(ibuf, '\n');
406                         if (p != NULL)
407                                 *p = '\0';
408                         else if (!sm_io_eof(smioin))
409                         {
410                                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
411                                                      "%s: %s: line %u: line too long (%ld bytes max)\n",
412                                                      progname, mapname, lineno,
413                                                      (long) sizeof ibuf);
414                                 exitstat = EX_DATAERR;
415                                 continue;
416                         }
417
418                         if (ibuf[0] == '\0' || ibuf[0] == comment)
419                                 continue;
420                         if (sep == '\0' && isascii(ibuf[0]) && isspace(ibuf[0]))
421                         {
422                                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
423                                                      "%s: %s: line %u: syntax error (leading space)\n",
424                                                      progname, mapname, lineno);
425                                 exitstat = EX_DATAERR;
426                                 continue;
427                         }
428
429                         memset(&db_key, '\0', sizeof db_key);
430                         memset(&db_val, '\0', sizeof db_val);
431                         db_key.data = ibuf;
432
433                         for (p = ibuf; *p != '\0' && !(ISSEP(*p)); p++)
434                         {
435                                 if (foldcase && isascii(*p) && isupper(*p))
436                                         *p = tolower(*p);
437                         }
438                         db_key.size = p - ibuf;
439                         if (inclnull)
440                                 db_key.size++;
441
442                         if (*p != '\0')
443                                 *p++ = '\0';
444                         while (*p != '\0' && ISSEP(*p))
445                                 p++;
446                         if (!allowempty && *p == '\0')
447                         {
448                                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
449                                                      "%s: %s: line %u: no RHS for LHS %s\n",
450                                                      progname, mapname, lineno,
451                                                      (char *) db_key.data);
452                                 exitstat = EX_DATAERR;
453                                 continue;
454                         }
455
456                         db_val.data = p;
457                         db_val.size = strlen(p);
458                         if (inclnull)
459                                 db_val.size++;
460
461                         /*
462                         **  Do the database insert.
463                         */
464
465                         if (verbose)
466                         {
467                                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
468                                                      "key=`%s', val=`%s'\n",
469                                                      (char *) db_key.data,
470                                                      (char *) db_val.data);
471                         }
472
473                         errno = database->smdb_put(database, &db_key, &db_val,
474                                                    putflags);
475                         switch (errno)
476                         {
477                           case SMDBE_KEY_EXIST:
478                                 st = 1;
479                                 break;
480
481                           case 0:
482                                 st = 0;
483                                 break;
484
485                           default:
486                                 st = -1;
487                                 break;
488                         }
489
490                         if (st < 0)
491                         {
492                                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
493                                                      "%s: %s: line %u: key %s: put error: %s\n",
494                                                      progname, mapname, lineno,
495                                                      (char *) db_key.data,
496                                                      sm_errstring(errno));
497                                 exitstat = EX_IOERR;
498                         }
499                         else if (st > 0)
500                         {
501                                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
502                                                      "%s: %s: line %u: key %s: duplicate key\n",
503                                                      progname, mapname,
504                                                      lineno,
505                                                      (char *) db_key.data);
506                                 exitstat = EX_DATAERR;
507                         }
508                 }
509         }
510
511         /*
512         **  Now close the database.
513         */
514
515         errno = database->smdb_close(database);
516         if (errno != SMDBE_OK)
517         {
518                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
519                                      "%s: close(%s): %s\n",
520                                      progname, mapname, sm_errstring(errno));
521                 exitstat = EX_IOERR;
522         }
523         smdb_free_database(database);
524
525         exit(exitstat);
526
527         /* NOTREACHED */
528         return exitstat;
529 }