190792Sgshapiro/*
2261363Sgshapiro * Copyright (c) 1998-2002, 2004 Proofpoint, Inc. and its suppliers.
390792Sgshapiro *	All rights reserved.
490792Sgshapiro * Copyright (c) 1992 Eric P. Allman.  All rights reserved.
590792Sgshapiro * Copyright (c) 1992, 1993
690792Sgshapiro *	The Regents of the University of California.  All rights reserved.
790792Sgshapiro *
890792Sgshapiro * By using this file, you agree to the terms and conditions set
990792Sgshapiro * forth in the LICENSE file which can be found at the top level of
1090792Sgshapiro * the sendmail distribution.
1190792Sgshapiro *
1290792Sgshapiro */
1390792Sgshapiro
1490792Sgshapiro#include <sm/gen.h>
1590792Sgshapiro#ifndef lint
1690792SgshapiroSM_UNUSED(static char copyright[]) =
17261363Sgshapiro"@(#) Copyright (c) 1998-2001 Proofpoint, Inc. and its suppliers.\n\
1890792Sgshapiro	All rights reserved.\n\
1990792Sgshapiro     Copyright (c) 1992 Eric P. Allman.  All rights reserved.\n\
2090792Sgshapiro     Copyright (c) 1992, 1993\n\
2190792Sgshapiro	The Regents of the University of California.  All rights reserved.\n";
2290792Sgshapiro#endif /* ! lint */
2390792Sgshapiro
2490792Sgshapiro#ifndef lint
25266692SgshapiroSM_UNUSED(static char id[]) = "@(#)$Id: editmap.c,v 1.26 2013-11-22 20:51:26 ca Exp $";
2690792Sgshapiro#endif /* ! lint */
2790792Sgshapiro
2890792Sgshapiro
2990792Sgshapiro#include <sys/types.h>
3090792Sgshapiro#ifndef ISC_UNIX
3190792Sgshapiro# include <sys/file.h>
3290792Sgshapiro#endif /* ! ISC_UNIX */
3390792Sgshapiro#include <ctype.h>
3490792Sgshapiro#include <stdlib.h>
3590792Sgshapiro#include <unistd.h>
3690792Sgshapiro#ifdef EX_OK
3790792Sgshapiro# undef EX_OK		/* unistd.h may have another use for this */
3890792Sgshapiro#endif /* EX_OK */
3990792Sgshapiro#include <sysexits.h>
4090792Sgshapiro#include <assert.h>
4190792Sgshapiro#include <sendmail/sendmail.h>
4290792Sgshapiro#include <sendmail/pathnames.h>
4390792Sgshapiro#include <libsmdb/smdb.h>
4490792Sgshapiro
4590792Sgshapirouid_t	RealUid;
4690792Sgshapirogid_t	RealGid;
4790792Sgshapirochar	*RealUserName;
4890792Sgshapirouid_t	RunAsUid;
49173340Sgshapirogid_t	RunAsGid;
5090792Sgshapirochar	*RunAsUserName;
5190792Sgshapiroint	Verbose = 2;
5290792Sgshapirobool	DontInitGroups = false;
5390792Sgshapirouid_t	TrustedUid = 0;
5490792SgshapiroBITMAP256 DontBlameSendmail;
5590792Sgshapiro
5690792Sgshapiro#define BUFSIZE		1024
5790792Sgshapiro#define ISSEP(c) (isascii(c) && isspace(c))
5890792Sgshapiro
5990792Sgshapiro
60141858Sgshapirostatic void usage __P((char *));
61141858Sgshapiro
6290792Sgshapirostatic void
6390792Sgshapirousage(progname)
6490792Sgshapiro	char *progname;
6590792Sgshapiro{
6690792Sgshapiro	fprintf(stderr,
6790792Sgshapiro		"Usage: %s [-C cffile] [-N] [-f] [-q|-u|-x] maptype mapname key [ \"value ...\" ]\n",
6890792Sgshapiro		progname);
6990792Sgshapiro	exit(EX_USAGE);
7090792Sgshapiro}
7190792Sgshapiro
7290792Sgshapiroint
7390792Sgshapiromain(argc, argv)
7490792Sgshapiro	int argc;
7590792Sgshapiro	char **argv;
7690792Sgshapiro{
7790792Sgshapiro	char *progname;
7890792Sgshapiro	char *cfile;
7990792Sgshapiro	bool query = false;
8090792Sgshapiro	bool update = false;
8190792Sgshapiro	bool remove = false;
8290792Sgshapiro	bool inclnull = false;
8390792Sgshapiro	bool foldcase = true;
8490792Sgshapiro	unsigned int nops = 0;
8590792Sgshapiro	int exitstat;
8690792Sgshapiro	int opt;
8790792Sgshapiro	char *typename = NULL;
8890792Sgshapiro	char *mapname = NULL;
8990792Sgshapiro	char *keyname = NULL;
9090792Sgshapiro	char *value = NULL;
9190792Sgshapiro	int mode;
9290792Sgshapiro	int smode;
9390792Sgshapiro	int putflags = 0;
9490792Sgshapiro	long sff = SFF_ROOTOK|SFF_REGONLY;
9590792Sgshapiro	struct passwd *pw;
9690792Sgshapiro	SMDB_DATABASE *database;
9790792Sgshapiro	SMDB_DBENT db_key, db_val;
9890792Sgshapiro	SMDB_DBPARAMS params;
9990792Sgshapiro	SMDB_USER_INFO user_info;
10090792Sgshapiro#if HASFCHOWN
10190792Sgshapiro	FILE *cfp;
10290792Sgshapiro	char buf[MAXLINE];
10390792Sgshapiro#endif /* HASFCHOWN */
10490792Sgshapiro	static char rnamebuf[MAXNAME];	/* holds RealUserName */
10590792Sgshapiro	extern char *optarg;
10690792Sgshapiro	extern int optind;
10790792Sgshapiro
10890792Sgshapiro	memset(&params, '\0', sizeof params);
10990792Sgshapiro	params.smdbp_cache_size = 1024 * 1024;
11090792Sgshapiro
11190792Sgshapiro	progname = strrchr(argv[0], '/');
11290792Sgshapiro	if (progname != NULL)
11390792Sgshapiro		progname++;
11490792Sgshapiro	else
11590792Sgshapiro		progname = argv[0];
11690792Sgshapiro	cfile = _PATH_SENDMAILCF;
11790792Sgshapiro
11890792Sgshapiro	clrbitmap(DontBlameSendmail);
11990792Sgshapiro	RunAsUid = RealUid = getuid();
12090792Sgshapiro	RunAsGid = RealGid = getgid();
12190792Sgshapiro	pw = getpwuid(RealUid);
12290792Sgshapiro	if (pw != NULL)
12390792Sgshapiro		(void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf);
12490792Sgshapiro	else
12590792Sgshapiro		(void) sm_snprintf(rnamebuf, sizeof rnamebuf,
12690792Sgshapiro				   "Unknown UID %d", (int) RealUid);
12790792Sgshapiro	RunAsUserName = RealUserName = rnamebuf;
12890792Sgshapiro	user_info.smdbu_id = RunAsUid;
12990792Sgshapiro	user_info.smdbu_group_id = RunAsGid;
13090792Sgshapiro	(void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
13190792Sgshapiro			  SMDB_MAX_USER_NAME_LEN);
13290792Sgshapiro
133285303Sgshapiro#define OPTIONS		"C:fquxN"
13490792Sgshapiro	while ((opt = getopt(argc, argv, OPTIONS)) != -1)
13590792Sgshapiro	{
13690792Sgshapiro		switch (opt)
13790792Sgshapiro		{
13890792Sgshapiro		  case 'C':
13990792Sgshapiro			cfile = optarg;
14090792Sgshapiro			break;
14190792Sgshapiro
14290792Sgshapiro		  case 'f':
14390792Sgshapiro			foldcase = false;
14490792Sgshapiro			break;
14590792Sgshapiro
14690792Sgshapiro		  case 'q':
14790792Sgshapiro			query = true;
14890792Sgshapiro			nops++;
14990792Sgshapiro			break;
15090792Sgshapiro
15190792Sgshapiro		  case 'u':
15290792Sgshapiro			update = true;
15390792Sgshapiro			nops++;
15490792Sgshapiro			break;
15590792Sgshapiro
15690792Sgshapiro		  case 'x':
15790792Sgshapiro			remove = true;
15890792Sgshapiro			nops++;
15990792Sgshapiro			break;
16090792Sgshapiro
16190792Sgshapiro		  case 'N':
16290792Sgshapiro			inclnull = true;
16390792Sgshapiro			break;
16490792Sgshapiro
16590792Sgshapiro		  default:
16690792Sgshapiro			usage(progname);
16790792Sgshapiro			assert(0);  /* NOTREACHED */
16890792Sgshapiro		}
16990792Sgshapiro	}
17090792Sgshapiro
17190792Sgshapiro	if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
17290792Sgshapiro		sff |= SFF_NOSLINK;
17390792Sgshapiro	if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
17490792Sgshapiro		sff |= SFF_NOHLINK;
17590792Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
17690792Sgshapiro		sff |= SFF_NOWLINK;
17790792Sgshapiro
17890792Sgshapiro	argc -= optind;
17990792Sgshapiro	argv += optind;
18090792Sgshapiro	if ((nops != 1) ||
18190792Sgshapiro	    (query && argc != 3) ||
18290792Sgshapiro	    (remove && argc != 3) ||
18390792Sgshapiro	    (update && argc <= 3))
18490792Sgshapiro	{
18590792Sgshapiro		usage(progname);
18690792Sgshapiro		assert(0);  /* NOTREACHED */
18790792Sgshapiro	}
18890792Sgshapiro
18990792Sgshapiro	typename = argv[0];
19090792Sgshapiro	mapname = argv[1];
19190792Sgshapiro	keyname = argv[2];
19290792Sgshapiro	if (update)
19390792Sgshapiro		value = argv[3];
19490792Sgshapiro
19590792Sgshapiro	if (foldcase)
19690792Sgshapiro	{
19790792Sgshapiro		char *p;
19890792Sgshapiro
19990792Sgshapiro		for (p = keyname; *p != '\0'; p++)
20090792Sgshapiro		{
20190792Sgshapiro			if (isascii(*p) && isupper(*p))
20290792Sgshapiro				*p = tolower(*p);
20390792Sgshapiro		}
20490792Sgshapiro	}
20590792Sgshapiro
20690792Sgshapiro
20790792Sgshapiro#if HASFCHOWN
20890792Sgshapiro	/* Find TrustedUser value in sendmail.cf */
20990792Sgshapiro	if ((cfp = fopen(cfile, "r")) == NULL)
21090792Sgshapiro	{
21190792Sgshapiro		fprintf(stderr, "%s: %s: %s\n", progname,
21290792Sgshapiro			cfile, sm_errstring(errno));
21390792Sgshapiro		exit(EX_NOINPUT);
21490792Sgshapiro	}
21590792Sgshapiro	while (fgets(buf, sizeof(buf), cfp) != NULL)
21690792Sgshapiro	{
21790792Sgshapiro		register char *b;
21890792Sgshapiro
21990792Sgshapiro		if ((b = strchr(buf, '\n')) != NULL)
22090792Sgshapiro			*b = '\0';
22190792Sgshapiro
22290792Sgshapiro		b = buf;
22390792Sgshapiro		switch (*b++)
22490792Sgshapiro		{
22590792Sgshapiro		  case 'O':		/* option */
22690792Sgshapiro			if (strncasecmp(b, " TrustedUser", 12) == 0 &&
22790792Sgshapiro			    !(isascii(b[12]) && isalnum(b[12])))
22890792Sgshapiro			{
22990792Sgshapiro				b = strchr(b, '=');
23090792Sgshapiro				if (b == NULL)
23190792Sgshapiro					continue;
23290792Sgshapiro				while (isascii(*++b) && isspace(*b))
23390792Sgshapiro					continue;
23490792Sgshapiro				if (isascii(*b) && isdigit(*b))
23590792Sgshapiro					TrustedUid = atoi(b);
23690792Sgshapiro				else
23790792Sgshapiro				{
23890792Sgshapiro					TrustedUid = 0;
23990792Sgshapiro					pw = getpwnam(b);
24090792Sgshapiro					if (pw == NULL)
24190792Sgshapiro						fprintf(stderr,
24290792Sgshapiro							"TrustedUser: unknown user %s\n", b);
24390792Sgshapiro					else
24490792Sgshapiro						TrustedUid = pw->pw_uid;
24590792Sgshapiro				}
24690792Sgshapiro
24790792Sgshapiro# ifdef UID_MAX
24890792Sgshapiro				if (TrustedUid > UID_MAX)
24990792Sgshapiro				{
25090792Sgshapiro					fprintf(stderr,
25190792Sgshapiro						"TrustedUser: uid value (%ld) > UID_MAX (%ld)",
25290792Sgshapiro						(long) TrustedUid,
25390792Sgshapiro						(long) UID_MAX);
25490792Sgshapiro					TrustedUid = 0;
25590792Sgshapiro				}
25690792Sgshapiro# endif /* UID_MAX */
25790792Sgshapiro				break;
25890792Sgshapiro			}
25990792Sgshapiro
26090792Sgshapiro
26190792Sgshapiro		  default:
26290792Sgshapiro			continue;
26390792Sgshapiro		}
26490792Sgshapiro	}
26590792Sgshapiro	(void) fclose(cfp);
26690792Sgshapiro#endif /* HASFCHOWN */
26790792Sgshapiro
26890792Sgshapiro	if (query)
26990792Sgshapiro	{
27090792Sgshapiro		mode = O_RDONLY;
27190792Sgshapiro		smode = S_IRUSR;
27290792Sgshapiro	}
27390792Sgshapiro	else
27490792Sgshapiro	{
27590792Sgshapiro		mode = O_RDWR | O_CREAT;
27690792Sgshapiro		sff |= SFF_CREAT|SFF_NOTEXCL;
27790792Sgshapiro		smode = S_IWUSR;
27890792Sgshapiro	}
27990792Sgshapiro
28090792Sgshapiro	params.smdbp_num_elements = 4096;
28190792Sgshapiro
28290792Sgshapiro	errno = smdb_open_database(&database, mapname, mode, smode, sff,
28390792Sgshapiro				   typename, &user_info, &params);
28490792Sgshapiro	if (errno != SMDBE_OK)
28590792Sgshapiro	{
28690792Sgshapiro		char *hint;
28790792Sgshapiro
28890792Sgshapiro		if (errno == SMDBE_UNSUPPORTED_DB_TYPE &&
28990792Sgshapiro		    (hint = smdb_db_definition(typename)) != NULL)
29090792Sgshapiro			fprintf(stderr,
29190792Sgshapiro				"%s: Need to recompile with -D%s for %s support\n",
29290792Sgshapiro				progname, hint, typename);
29390792Sgshapiro		else
29490792Sgshapiro			fprintf(stderr,
29590792Sgshapiro				"%s: error opening type %s map %s: %s\n",
29690792Sgshapiro				progname, typename, mapname,
29790792Sgshapiro				sm_errstring(errno));
29890792Sgshapiro		exit(EX_CANTCREAT);
29990792Sgshapiro	}
30090792Sgshapiro
30190792Sgshapiro	(void) database->smdb_sync(database, 0);
30290792Sgshapiro
30390792Sgshapiro	if (geteuid() == 0 && TrustedUid != 0)
30490792Sgshapiro	{
30590792Sgshapiro		errno = database->smdb_set_owner(database, TrustedUid, -1);
30690792Sgshapiro		if (errno != SMDBE_OK)
30790792Sgshapiro		{
30890792Sgshapiro			fprintf(stderr,
30990792Sgshapiro				"WARNING: ownership change on %s failed %s",
31090792Sgshapiro				mapname, sm_errstring(errno));
31190792Sgshapiro		}
31290792Sgshapiro	}
31390792Sgshapiro
31490792Sgshapiro	exitstat = EX_OK;
31590792Sgshapiro	if (query)
31690792Sgshapiro	{
31790792Sgshapiro		memset(&db_key, '\0', sizeof db_key);
31890792Sgshapiro		memset(&db_val, '\0', sizeof db_val);
31990792Sgshapiro
32090792Sgshapiro		db_key.data = keyname;
32190792Sgshapiro		db_key.size = strlen(keyname);
32290792Sgshapiro		if (inclnull)
32390792Sgshapiro			db_key.size++;
32490792Sgshapiro
32590792Sgshapiro		errno = database->smdb_get(database, &db_key, &db_val, 0);
32690792Sgshapiro		if (errno != SMDBE_OK)
32790792Sgshapiro		{
32890792Sgshapiro			/* XXX - Need to distinguish between not found */
32990792Sgshapiro			fprintf(stderr,
33090792Sgshapiro				"%s: couldn't find key %s in map %s\n",
33190792Sgshapiro				progname, keyname, mapname);
33290792Sgshapiro			exitstat = EX_UNAVAILABLE;
33390792Sgshapiro		}
33490792Sgshapiro		else
33590792Sgshapiro		{
33690792Sgshapiro			printf("%.*s\n", (int) db_val.size,
33790792Sgshapiro			       (char *) db_val.data);
33890792Sgshapiro		}
33990792Sgshapiro	}
34090792Sgshapiro	else if (update)
34190792Sgshapiro	{
34290792Sgshapiro		memset(&db_key, '\0', sizeof db_key);
34390792Sgshapiro		memset(&db_val, '\0', sizeof db_val);
34490792Sgshapiro
34590792Sgshapiro		db_key.data = keyname;
34690792Sgshapiro		db_key.size = strlen(keyname);
34790792Sgshapiro		if (inclnull)
34890792Sgshapiro			db_key.size++;
34990792Sgshapiro		db_val.data = value;
35090792Sgshapiro		db_val.size = strlen(value);
35190792Sgshapiro		if (inclnull)
35290792Sgshapiro			db_val.size++;
35390792Sgshapiro
35490792Sgshapiro		errno = database->smdb_put(database, &db_key, &db_val,
35590792Sgshapiro					   putflags);
35690792Sgshapiro		if (errno != SMDBE_OK)
35790792Sgshapiro		{
35890792Sgshapiro			fprintf(stderr,
35990792Sgshapiro				"%s: error updating (%s, %s) in map %s: %s\n",
36090792Sgshapiro				progname, keyname, value, mapname,
36190792Sgshapiro				sm_errstring(errno));
36290792Sgshapiro			exitstat = EX_IOERR;
36390792Sgshapiro		}
36490792Sgshapiro	}
36590792Sgshapiro	else if (remove)
36690792Sgshapiro	{
36790792Sgshapiro		memset(&db_key, '\0', sizeof db_key);
36890792Sgshapiro		memset(&db_val, '\0', sizeof db_val);
36990792Sgshapiro
37090792Sgshapiro		db_key.data = keyname;
37190792Sgshapiro		db_key.size = strlen(keyname);
37290792Sgshapiro		if (inclnull)
37390792Sgshapiro			db_key.size++;
37490792Sgshapiro
37590792Sgshapiro		errno = database->smdb_del(database, &db_key, 0);
37690792Sgshapiro
37790792Sgshapiro		switch (errno)
37890792Sgshapiro		{
37990792Sgshapiro		case SMDBE_NOT_FOUND:
38090792Sgshapiro			fprintf(stderr,
38190792Sgshapiro				"%s: key %s doesn't exist in map %s\n",
38290792Sgshapiro				progname, keyname, mapname);
38390792Sgshapiro			/* Don't set exitstat */
38490792Sgshapiro			break;
38590792Sgshapiro		case SMDBE_OK:
38690792Sgshapiro			/* All's well */
38790792Sgshapiro			break;
38890792Sgshapiro		default:
38990792Sgshapiro			fprintf(stderr,
39090792Sgshapiro				"%s: couldn't remove key %s in map %s (error)\n",
39190792Sgshapiro				progname, keyname, mapname);
39290792Sgshapiro			exitstat = EX_IOERR;
39390792Sgshapiro			break;
39490792Sgshapiro		}
39590792Sgshapiro	}
39690792Sgshapiro	else
39790792Sgshapiro	{
39890792Sgshapiro		assert(0);  /* NOT REACHED */
39990792Sgshapiro	}
40090792Sgshapiro
40190792Sgshapiro	/*
40290792Sgshapiro	**  Now close the database.
40390792Sgshapiro	*/
40490792Sgshapiro
40590792Sgshapiro	errno = database->smdb_close(database);
40690792Sgshapiro	if (errno != SMDBE_OK)
40790792Sgshapiro	{
40890792Sgshapiro		fprintf(stderr, "%s: close(%s): %s\n",
40990792Sgshapiro			progname, mapname, sm_errstring(errno));
41090792Sgshapiro		exitstat = EX_IOERR;
41190792Sgshapiro	}
41290792Sgshapiro	smdb_free_database(database);
41390792Sgshapiro
41490792Sgshapiro	exit(exitstat);
41590792Sgshapiro	/* NOTREACHED */
41690792Sgshapiro	return exitstat;
41790792Sgshapiro}
418