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