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