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
27
28
29 #include <sys/types.h>
30 #ifndef ISC_UNIX
31 # include <sys/file.h>
32 #endif
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
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
usage(progname)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
main(argc,argv)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
104 static char rnamebuf[MAXNAME]; /* holds RealUserName */
105 extern char *optarg;
106 extern int optind;
107
108 memset(¶ms, '\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, ¶ms);
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 }
418