Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / sendmail / editmap / editmap.c
1 /*
2  * Copyright (c) 1998-2002 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 #ifndef lint
16 SM_UNUSED(static char copyright[]) =
17 "@(#) Copyright (c) 1998-2001 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 #endif /* ! lint */
23
24 #ifndef lint
25 SM_UNUSED(static char id[]) = "@(#)$Id: editmap.c,v 1.23 2002/03/28 17:49:33 gshapiro Exp $";
26 #endif /* ! lint */
27
28
29 #include <sys/types.h>
30 #ifndef ISC_UNIX
31 # include <sys/file.h>
32 #endif /* ! ISC_UNIX */
33 #include <ctype.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #ifdef EX_OK
37 # undef EX_OK           /* unistd.h may have another use for this */
38 #endif /* EX_OK */
39 #include <sysexits.h>
40 #include <assert.h>
41 #include <sendmail/sendmail.h>
42 #include <sendmail/pathnames.h>
43 #include <libsmdb/smdb.h>
44
45 uid_t   RealUid;
46 gid_t   RealGid;
47 char    *RealUserName;
48 uid_t   RunAsUid;
49 uid_t   RunAsGid;
50 char    *RunAsUserName;
51 int     Verbose = 2;
52 bool    DontInitGroups = false;
53 uid_t   TrustedUid = 0;
54 BITMAP256 DontBlameSendmail;
55
56 #define BUFSIZE         1024
57 #define ISSEP(c) (isascii(c) && isspace(c))
58
59
60 static void
61 usage(progname)
62         char *progname;
63 {
64         fprintf(stderr,
65                 "Usage: %s [-C cffile] [-N] [-f] [-q|-u|-x] maptype mapname key [ \"value ...\" ]\n",
66                 progname);
67         exit(EX_USAGE);
68 }
69
70 int
71 main(argc, argv)
72         int argc;
73         char **argv;
74 {
75         char *progname;
76         char *cfile;
77         bool verbose = false;
78         bool query = false;
79         bool update = false;
80         bool remove = false;
81         bool inclnull = false;
82         bool foldcase = true;
83         unsigned int nops = 0;
84         int exitstat;
85         int opt;
86         char *typename = NULL;
87         char *mapname = NULL;
88         char *keyname = NULL;
89         char *value = NULL;
90         int mode;
91         int smode;
92         int putflags = 0;
93         long sff = SFF_ROOTOK|SFF_REGONLY;
94         struct passwd *pw;
95         SMDB_DATABASE *database;
96         SMDB_DBENT db_key, db_val;
97         SMDB_DBPARAMS params;
98         SMDB_USER_INFO user_info;
99 #if HASFCHOWN
100         FILE *cfp;
101         char buf[MAXLINE];
102 #endif /* HASFCHOWN */
103         static char rnamebuf[MAXNAME];  /* holds RealUserName */
104         extern char *optarg;
105         extern int optind;
106
107         memset(&params, '\0', sizeof params);
108         params.smdbp_cache_size = 1024 * 1024;
109
110         progname = strrchr(argv[0], '/');
111         if (progname != NULL)
112                 progname++;
113         else
114                 progname = argv[0];
115         cfile = _PATH_SENDMAILCF;
116
117         clrbitmap(DontBlameSendmail);
118         RunAsUid = RealUid = getuid();
119         RunAsGid = RealGid = getgid();
120         pw = getpwuid(RealUid);
121         if (pw != NULL)
122                 (void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf);
123         else
124                 (void) sm_snprintf(rnamebuf, sizeof rnamebuf,
125                                    "Unknown UID %d", (int) RealUid);
126         RunAsUserName = RealUserName = rnamebuf;
127         user_info.smdbu_id = RunAsUid;
128         user_info.smdbu_group_id = RunAsGid;
129         (void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
130                           SMDB_MAX_USER_NAME_LEN);
131
132 #define OPTIONS         "C:fquxvN"
133         while ((opt = getopt(argc, argv, OPTIONS)) != -1)
134         {
135                 switch (opt)
136                 {
137                   case 'C':
138                         cfile = optarg;
139                         break;
140
141                   case 'f':
142                         foldcase = false;
143                         break;
144
145                   case 'q':
146                         query = true;
147                         nops++;
148                         break;
149
150                   case 'u':
151                         update = true;
152                         nops++;
153                         break;
154
155                   case 'x':
156                         remove = true;
157                         nops++;
158                         break;
159
160                   case 'v':
161                         verbose = true;
162                         break;
163
164                   case 'N':
165                         inclnull = true;
166                         break;
167
168                   default:
169                         usage(progname);
170                         assert(0);  /* NOTREACHED */
171                 }
172         }
173
174         if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
175                 sff |= SFF_NOSLINK;
176         if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
177                 sff |= SFF_NOHLINK;
178         if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
179                 sff |= SFF_NOWLINK;
180
181         argc -= optind;
182         argv += optind;
183         if ((nops != 1) ||
184             (query && argc != 3) ||
185             (remove && argc != 3) ||
186             (update && argc <= 3))
187         {
188                 usage(progname);
189                 assert(0);  /* NOTREACHED */
190         }
191
192         typename = argv[0];
193         mapname = argv[1];
194         keyname = argv[2];
195         if (update)
196                 value = argv[3];
197
198         if (foldcase)
199         {
200                 char *p;
201
202                 for (p = keyname; *p != '\0'; p++)
203                 {
204                         if (isascii(*p) && isupper(*p))
205                                 *p = tolower(*p);
206                 }
207         }
208
209
210 #if HASFCHOWN
211         /* Find TrustedUser value in sendmail.cf */
212         if ((cfp = fopen(cfile, "r")) == NULL)
213         {
214                 fprintf(stderr, "%s: %s: %s\n", progname,
215                         cfile, sm_errstring(errno));
216                 exit(EX_NOINPUT);
217         }
218         while (fgets(buf, sizeof(buf), cfp) != NULL)
219         {
220                 register char *b;
221
222                 if ((b = strchr(buf, '\n')) != NULL)
223                         *b = '\0';
224
225                 b = buf;
226                 switch (*b++)
227                 {
228                   case 'O':             /* option */
229                         if (strncasecmp(b, " TrustedUser", 12) == 0 &&
230                             !(isascii(b[12]) && isalnum(b[12])))
231                         {
232                                 b = strchr(b, '=');
233                                 if (b == NULL)
234                                         continue;
235                                 while (isascii(*++b) && isspace(*b))
236                                         continue;
237                                 if (isascii(*b) && isdigit(*b))
238                                         TrustedUid = atoi(b);
239                                 else
240                                 {
241                                         TrustedUid = 0;
242                                         pw = getpwnam(b);
243                                         if (pw == NULL)
244                                                 fprintf(stderr,
245                                                         "TrustedUser: unknown user %s\n", b);
246                                         else
247                                                 TrustedUid = pw->pw_uid;
248                                 }
249
250 # ifdef UID_MAX
251                                 if (TrustedUid > UID_MAX)
252                                 {
253                                         fprintf(stderr,
254                                                 "TrustedUser: uid value (%ld) > UID_MAX (%ld)",
255                                                 (long) TrustedUid,
256                                                 (long) UID_MAX);
257                                         TrustedUid = 0;
258                                 }
259 # endif /* UID_MAX */
260                                 break;
261                         }
262
263
264                   default:
265                         continue;
266                 }
267         }
268         (void) fclose(cfp);
269 #endif /* HASFCHOWN */
270
271         if (query)
272         {
273                 mode = O_RDONLY;
274                 smode = S_IRUSR;
275         }
276         else
277         {
278                 mode = O_RDWR | O_CREAT;
279                 sff |= SFF_CREAT|SFF_NOTEXCL;
280                 smode = S_IWUSR;
281         }
282
283         params.smdbp_num_elements = 4096;
284
285         errno = smdb_open_database(&database, mapname, mode, smode, sff,
286                                    typename, &user_info, &params);
287         if (errno != SMDBE_OK)
288         {
289                 char *hint;
290
291                 if (errno == SMDBE_UNSUPPORTED_DB_TYPE &&
292                     (hint = smdb_db_definition(typename)) != NULL)
293                         fprintf(stderr,
294                                 "%s: Need to recompile with -D%s for %s support\n",
295                                 progname, hint, typename);
296                 else
297                         fprintf(stderr,
298                                 "%s: error opening type %s map %s: %s\n",
299                                 progname, typename, mapname,
300                                 sm_errstring(errno));
301                 exit(EX_CANTCREAT);
302         }
303
304         (void) database->smdb_sync(database, 0);
305
306         if (geteuid() == 0 && TrustedUid != 0)
307         {
308                 errno = database->smdb_set_owner(database, TrustedUid, -1);
309                 if (errno != SMDBE_OK)
310                 {
311                         fprintf(stderr,
312                                 "WARNING: ownership change on %s failed %s",
313                                 mapname, sm_errstring(errno));
314                 }
315         }
316
317         exitstat = EX_OK;
318         if (query)
319         {
320                 memset(&db_key, '\0', sizeof db_key);
321                 memset(&db_val, '\0', sizeof db_val);
322
323                 db_key.data = keyname;
324                 db_key.size = strlen(keyname);
325                 if (inclnull)
326                         db_key.size++;
327
328                 errno = database->smdb_get(database, &db_key, &db_val, 0);
329                 if (errno != SMDBE_OK)
330                 {
331                         /* XXX - Need to distinguish between not found */
332                         fprintf(stderr,
333                                 "%s: couldn't find key %s in map %s\n",
334                                 progname, keyname, mapname);
335                         exitstat = EX_UNAVAILABLE;
336                 }
337                 else
338                 {
339                         printf("%.*s\n", (int) db_val.size,
340                                (char *) db_val.data);
341                 }
342         }
343         else if (update)
344         {
345                 memset(&db_key, '\0', sizeof db_key);
346                 memset(&db_val, '\0', sizeof db_val);
347
348                 db_key.data = keyname;
349                 db_key.size = strlen(keyname);
350                 if (inclnull)
351                         db_key.size++;
352                 db_val.data = value;
353                 db_val.size = strlen(value);
354                 if (inclnull)
355                         db_val.size++;
356
357                 errno = database->smdb_put(database, &db_key, &db_val,
358                                            putflags);
359                 if (errno != SMDBE_OK)
360                 {
361                         fprintf(stderr,
362                                 "%s: error updating (%s, %s) in map %s: %s\n",
363                                 progname, keyname, value, mapname,
364                                 sm_errstring(errno));
365                         exitstat = EX_IOERR;
366                 }
367         }
368         else if (remove)
369         {
370                 memset(&db_key, '\0', sizeof db_key);
371                 memset(&db_val, '\0', sizeof db_val);
372
373                 db_key.data = keyname;
374                 db_key.size = strlen(keyname);
375                 if (inclnull)
376                         db_key.size++;
377
378                 errno = database->smdb_del(database, &db_key, 0);
379
380                 switch (errno)
381                 {
382                 case SMDBE_NOT_FOUND:
383                         fprintf(stderr,
384                                 "%s: key %s doesn't exist in map %s\n",
385                                 progname, keyname, mapname);
386                         /* Don't set exitstat */
387                         break;
388                 case SMDBE_OK:
389                         /* All's well */
390                         break;
391                 default:
392                         fprintf(stderr,
393                                 "%s: couldn't remove key %s in map %s (error)\n",
394                                 progname, keyname, mapname);
395                         exitstat = EX_IOERR;
396                         break;
397                 }
398         }
399         else
400         {
401                 assert(0);  /* NOT REACHED */
402         }
403
404         /*
405         **  Now close the database.
406         */
407
408         errno = database->smdb_close(database);
409         if (errno != SMDBE_OK)
410         {
411                 fprintf(stderr, "%s: close(%s): %s\n",
412                         progname, mapname, sm_errstring(errno));
413                 exitstat = EX_IOERR;
414         }
415         smdb_free_database(database);
416
417         exit(exitstat);
418         /* NOTREACHED */
419         return exitstat;
420 }