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