]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - contrib/sendmail/makemap/makemap.c
MFC: Merge sendmail 8.14.8
[FreeBSD/stable/8.git] / contrib / sendmail / makemap / makemap.c
1 /*
2  * Copyright (c) 1998-2002, 2004, 2008 Proofpoint, 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 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")
22
23 SM_IDSTR(id, "@(#)$Id: makemap.c,v 8.183 2013/11/22 20:51:52 ca 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         if (!unmake && geteuid() == 0)
238         {
239                 /* Find TrustedUser value in sendmail.cf */
240                 if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile,
241                                       SM_IO_RDONLY, NULL)) == NULL)
242                 {
243                         sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
244                                       "makemap: %s: %s\n",
245                                       cfile, sm_errstring(errno));
246                         exit(EX_NOINPUT);
247                 }
248                 while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0)
249                 {
250                         register char *b;
251
252                         if ((b = strchr(buf, '\n')) != NULL)
253                                 *b = '\0';
254
255                         b = buf;
256                         switch (*b++)
257                         {
258                           case 'O':             /* option */
259                                 if (strncasecmp(b, " TrustedUser", 12) == 0 &&
260                                     !(isascii(b[12]) && isalnum(b[12])))
261                                 {
262                                         b = strchr(b, '=');
263                                         if (b == NULL)
264                                                 continue;
265                                         while (isascii(*++b) && isspace(*b))
266                                                 continue;
267                                         if (isascii(*b) && isdigit(*b))
268                                                 TrustedUid = atoi(b);
269                                         else
270                                         {
271                                                 TrustedUid = 0;
272                                                 pw = getpwnam(b);
273                                                 if (pw == NULL)
274                                                         (void) sm_io_fprintf(smioerr,
275                                                                              SM_TIME_DEFAULT,
276                                                                              "TrustedUser: unknown user %s\n", b);
277                                                 else
278                                                         TrustedUid = pw->pw_uid;
279                                         }
280
281 # ifdef UID_MAX
282                                         if (TrustedUid > UID_MAX)
283                                         {
284                                                 (void) sm_io_fprintf(smioerr,
285                                                                      SM_TIME_DEFAULT,
286                                                                      "TrustedUser: uid value (%ld) > UID_MAX (%ld)",
287                                                         (long) TrustedUid,
288                                                         (long) UID_MAX);
289                                                 TrustedUid = 0;
290                                         }
291 # endif /* UID_MAX */
292                                         break;
293                                 }
294
295
296                           default:
297                                 continue;
298                         }
299                 }
300                 (void) sm_io_close(cfp, SM_TIME_DEFAULT);
301         }
302 #endif /* HASFCHOWN */
303
304         if (!params.smdbp_allow_dup && !allowreplace)
305                 putflags = SMDBF_NO_OVERWRITE;
306
307         if (unmake)
308         {
309                 mode = O_RDONLY;
310                 smode = S_IRUSR;
311         }
312         else
313         {
314                 mode = O_RDWR;
315                 if (!notrunc)
316                 {
317                         mode |= O_CREAT|O_TRUNC;
318                         sff |= SFF_CREAT;
319                 }
320                 smode = S_IWUSR;
321         }
322
323         params.smdbp_num_elements = 4096;
324
325         errno = smdb_open_database(&database, mapname, mode, smode, sff,
326                                    typename, &user_info, &params);
327         if (errno != SMDBE_OK)
328         {
329                 char *hint;
330
331                 if (errno == SMDBE_UNSUPPORTED_DB_TYPE &&
332                     (hint = smdb_db_definition(typename)) != NULL)
333                         (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
334                                              "%s: Need to recompile with -D%s for %s support\n",
335                                              progname, hint, typename);
336                 else
337                         (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
338                                              "%s: error opening type %s map %s: %s\n",
339                                              progname, typename, mapname,
340                                              sm_errstring(errno));
341                 exit(EX_CANTCREAT);
342         }
343
344         (void) database->smdb_sync(database, 0);
345
346         if (!unmake && geteuid() == 0 && TrustedUid != 0)
347         {
348                 errno = database->smdb_set_owner(database, TrustedUid, -1);
349                 if (errno != SMDBE_OK)
350                 {
351                         (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
352                                              "WARNING: ownership change on %s failed %s",
353                                              mapname, sm_errstring(errno));
354                 }
355         }
356
357         /*
358         **  Copy the data
359         */
360
361         exitstat = EX_OK;
362         if (unmake)
363         {
364                 errno = database->smdb_cursor(database, &cursor, 0);
365                 if (errno != SMDBE_OK)
366                 {
367
368                         (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
369                                              "%s: cannot make cursor for type %s map %s\n",
370                                              progname, typename, mapname);
371                         exit(EX_SOFTWARE);
372                 }
373
374                 memset(&db_key, '\0', sizeof db_key);
375                 memset(&db_val, '\0', sizeof db_val);
376
377                 for (lineno = 0; ; lineno++)
378                 {
379                         errno = cursor->smdbc_get(cursor, &db_key, &db_val,
380                                                   SMDB_CURSOR_GET_NEXT);
381                         if (errno != SMDBE_OK)
382                                 break;
383
384                         (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
385                                              "%.*s%c%.*s\n",
386                                              (int) db_key.size,
387                                              (char *) db_key.data,
388                                              (sep != '\0') ? sep : '\t',
389                                              (int) db_val.size,
390                                              (char *)db_val.data);
391
392                 }
393                 (void) cursor->smdbc_close(cursor);
394         }
395         else
396         {
397                 lineno = 0;
398                 while (sm_io_fgets(smioin, SM_TIME_DEFAULT, ibuf, sizeof ibuf)
399                        >= 0)
400                 {
401                         register char *p;
402
403                         lineno++;
404
405                         /*
406                         **  Parse the line.
407                         */
408
409                         p = strchr(ibuf, '\n');
410                         if (p != NULL)
411                                 *p = '\0';
412                         else if (!sm_io_eof(smioin))
413                         {
414                                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
415                                                      "%s: %s: line %u: line too long (%ld bytes max)\n",
416                                                      progname, mapname, lineno,
417                                                      (long) sizeof ibuf);
418                                 exitstat = EX_DATAERR;
419                                 continue;
420                         }
421
422                         if (ibuf[0] == '\0' || ibuf[0] == comment)
423                                 continue;
424                         if (sep == '\0' && isascii(ibuf[0]) && isspace(ibuf[0]))
425                         {
426                                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
427                                                      "%s: %s: line %u: syntax error (leading space)\n",
428                                                      progname, mapname, lineno);
429                                 exitstat = EX_DATAERR;
430                                 continue;
431                         }
432
433                         memset(&db_key, '\0', sizeof db_key);
434                         memset(&db_val, '\0', sizeof db_val);
435                         db_key.data = ibuf;
436
437                         for (p = ibuf; *p != '\0' && !(ISSEP(*p)); p++)
438                         {
439                                 if (foldcase && isascii(*p) && isupper(*p))
440                                         *p = tolower(*p);
441                         }
442                         db_key.size = p - ibuf;
443                         if (inclnull)
444                                 db_key.size++;
445
446                         if (*p != '\0')
447                                 *p++ = '\0';
448                         while (*p != '\0' && ISSEP(*p))
449                                 p++;
450                         if (!allowempty && *p == '\0')
451                         {
452                                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
453                                                      "%s: %s: line %u: no RHS for LHS %s\n",
454                                                      progname, mapname, lineno,
455                                                      (char *) db_key.data);
456                                 exitstat = EX_DATAERR;
457                                 continue;
458                         }
459
460                         db_val.data = p;
461                         db_val.size = strlen(p);
462                         if (inclnull)
463                                 db_val.size++;
464
465                         /*
466                         **  Do the database insert.
467                         */
468
469                         if (verbose)
470                         {
471                                 (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
472                                                      "key=`%s', val=`%s'\n",
473                                                      (char *) db_key.data,
474                                                      (char *) db_val.data);
475                         }
476
477                         errno = database->smdb_put(database, &db_key, &db_val,
478                                                    putflags);
479                         switch (errno)
480                         {
481                           case SMDBE_KEY_EXIST:
482                                 st = 1;
483                                 break;
484
485                           case 0:
486                                 st = 0;
487                                 break;
488
489                           default:
490                                 st = -1;
491                                 break;
492                         }
493
494                         if (st < 0)
495                         {
496                                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
497                                                      "%s: %s: line %u: key %s: put error: %s\n",
498                                                      progname, mapname, lineno,
499                                                      (char *) db_key.data,
500                                                      sm_errstring(errno));
501                                 exitstat = EX_IOERR;
502                         }
503                         else if (st > 0)
504                         {
505                                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
506                                                      "%s: %s: line %u: key %s: duplicate key\n",
507                                                      progname, mapname,
508                                                      lineno,
509                                                      (char *) db_key.data);
510                                 exitstat = EX_DATAERR;
511                         }
512                 }
513         }
514
515         /*
516         **  Now close the database.
517         */
518
519         errno = database->smdb_close(database);
520         if (errno != SMDBE_OK)
521         {
522                 (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
523                                      "%s: close(%s): %s\n",
524                                      progname, mapname, sm_errstring(errno));
525                 exitstat = EX_IOERR;
526         }
527         smdb_free_database(database);
528
529         exit(exitstat);
530
531         /* NOTREACHED */
532         return exitstat;
533 }