xref: /onnv-gate/usr/src/cmd/sendmail/aux/editmap.c (revision 5402:a17d5e4e8666)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * Copyright (c) 1998-2002, 2004 Sendmail, Inc. and its suppliers.
30Sstevel@tonic-gate  *	All rights reserved.
40Sstevel@tonic-gate  * Copyright (c) 1992 Eric P. Allman.  All rights reserved.
50Sstevel@tonic-gate  * Copyright (c) 1992, 1993
60Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
90Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
100Sstevel@tonic-gate  * the sendmail distribution.
110Sstevel@tonic-gate  *
120Sstevel@tonic-gate  */
130Sstevel@tonic-gate 
140Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
150Sstevel@tonic-gate 
160Sstevel@tonic-gate #include <sm/gen.h>
170Sstevel@tonic-gate #ifndef lint
180Sstevel@tonic-gate SM_UNUSED(static char copyright[]) =
190Sstevel@tonic-gate "@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\
200Sstevel@tonic-gate 	All rights reserved.\n\
210Sstevel@tonic-gate      Copyright (c) 1992 Eric P. Allman.  All rights reserved.\n\
220Sstevel@tonic-gate      Copyright (c) 1992, 1993\n\
230Sstevel@tonic-gate 	The Regents of the University of California.  All rights reserved.\n";
240Sstevel@tonic-gate #endif /* ! lint */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #ifndef lint
27*5402Sjbeck SM_UNUSED(static char id[]) = "@(#)$Id: editmap.c,v 1.25 2007/05/11 18:50:35 ca Exp $";
280Sstevel@tonic-gate #endif /* ! lint */
290Sstevel@tonic-gate 
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #include <sys/types.h>
320Sstevel@tonic-gate #ifndef ISC_UNIX
330Sstevel@tonic-gate # include <sys/file.h>
340Sstevel@tonic-gate #endif /* ! ISC_UNIX */
350Sstevel@tonic-gate #include <ctype.h>
360Sstevel@tonic-gate #include <stdlib.h>
370Sstevel@tonic-gate #include <unistd.h>
380Sstevel@tonic-gate #ifdef EX_OK
390Sstevel@tonic-gate # undef EX_OK		/* unistd.h may have another use for this */
400Sstevel@tonic-gate #endif /* EX_OK */
410Sstevel@tonic-gate #include <sysexits.h>
420Sstevel@tonic-gate #include <assert.h>
430Sstevel@tonic-gate #include <sendmail/sendmail.h>
440Sstevel@tonic-gate #include <sendmail/pathnames.h>
450Sstevel@tonic-gate #include <libsmdb/smdb.h>
460Sstevel@tonic-gate 
470Sstevel@tonic-gate uid_t	RealUid;
480Sstevel@tonic-gate gid_t	RealGid;
490Sstevel@tonic-gate char	*RealUserName;
500Sstevel@tonic-gate uid_t	RunAsUid;
51*5402Sjbeck gid_t	RunAsGid;
520Sstevel@tonic-gate char	*RunAsUserName;
530Sstevel@tonic-gate int	Verbose = 2;
540Sstevel@tonic-gate bool	DontInitGroups = false;
550Sstevel@tonic-gate uid_t	TrustedUid = 0;
560Sstevel@tonic-gate BITMAP256 DontBlameSendmail;
570Sstevel@tonic-gate 
580Sstevel@tonic-gate #define BUFSIZE		1024
590Sstevel@tonic-gate #define ISSEP(c) (isascii(c) && isspace(c))
600Sstevel@tonic-gate 
610Sstevel@tonic-gate 
620Sstevel@tonic-gate static void usage __P((char *));
630Sstevel@tonic-gate 
640Sstevel@tonic-gate static void
usage(progname)650Sstevel@tonic-gate usage(progname)
660Sstevel@tonic-gate 	char *progname;
670Sstevel@tonic-gate {
680Sstevel@tonic-gate 	fprintf(stderr,
690Sstevel@tonic-gate 		"Usage: %s [-C cffile] [-N] [-f] [-q|-u|-x] maptype mapname key [ \"value ...\" ]\n",
700Sstevel@tonic-gate 		progname);
710Sstevel@tonic-gate 	exit(EX_USAGE);
720Sstevel@tonic-gate }
730Sstevel@tonic-gate 
740Sstevel@tonic-gate int
main(argc,argv)750Sstevel@tonic-gate main(argc, argv)
760Sstevel@tonic-gate 	int argc;
770Sstevel@tonic-gate 	char **argv;
780Sstevel@tonic-gate {
790Sstevel@tonic-gate 	char *progname;
800Sstevel@tonic-gate 	char *cfile;
810Sstevel@tonic-gate 	bool verbose = false;
820Sstevel@tonic-gate 	bool query = false;
830Sstevel@tonic-gate 	bool update = false;
840Sstevel@tonic-gate 	bool remove = false;
850Sstevel@tonic-gate 	bool inclnull = false;
860Sstevel@tonic-gate 	bool foldcase = true;
870Sstevel@tonic-gate 	unsigned int nops = 0;
880Sstevel@tonic-gate 	int exitstat;
890Sstevel@tonic-gate 	int opt;
900Sstevel@tonic-gate 	char *typename = NULL;
910Sstevel@tonic-gate 	char *mapname = NULL;
920Sstevel@tonic-gate 	char *keyname = NULL;
930Sstevel@tonic-gate 	char *value = NULL;
940Sstevel@tonic-gate 	int mode;
950Sstevel@tonic-gate 	int smode;
960Sstevel@tonic-gate 	int putflags = 0;
970Sstevel@tonic-gate 	long sff = SFF_ROOTOK|SFF_REGONLY;
980Sstevel@tonic-gate 	struct passwd *pw;
990Sstevel@tonic-gate 	SMDB_DATABASE *database;
1000Sstevel@tonic-gate 	SMDB_DBENT db_key, db_val;
1010Sstevel@tonic-gate 	SMDB_DBPARAMS params;
1020Sstevel@tonic-gate 	SMDB_USER_INFO user_info;
1030Sstevel@tonic-gate #if HASFCHOWN
1040Sstevel@tonic-gate 	FILE *cfp;
1050Sstevel@tonic-gate 	char buf[MAXLINE];
1060Sstevel@tonic-gate #endif /* HASFCHOWN */
1070Sstevel@tonic-gate 	static char rnamebuf[MAXNAME];	/* holds RealUserName */
1080Sstevel@tonic-gate 	extern char *optarg;
1090Sstevel@tonic-gate 	extern int optind;
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate 	memset(&params, '\0', sizeof params);
1120Sstevel@tonic-gate 	params.smdbp_cache_size = 1024 * 1024;
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 	progname = strrchr(argv[0], '/');
1150Sstevel@tonic-gate 	if (progname != NULL)
1160Sstevel@tonic-gate 		progname++;
1170Sstevel@tonic-gate 	else
1180Sstevel@tonic-gate 		progname = argv[0];
1190Sstevel@tonic-gate 	cfile = _PATH_SENDMAILCF;
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	clrbitmap(DontBlameSendmail);
1220Sstevel@tonic-gate 	RunAsUid = RealUid = getuid();
1230Sstevel@tonic-gate 	RunAsGid = RealGid = getgid();
1240Sstevel@tonic-gate 	pw = getpwuid(RealUid);
1250Sstevel@tonic-gate 	if (pw != NULL)
1260Sstevel@tonic-gate 		(void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf);
1270Sstevel@tonic-gate 	else
1280Sstevel@tonic-gate 		(void) sm_snprintf(rnamebuf, sizeof rnamebuf,
1290Sstevel@tonic-gate 				   "Unknown UID %d", (int) RealUid);
1300Sstevel@tonic-gate 	RunAsUserName = RealUserName = rnamebuf;
1310Sstevel@tonic-gate 	user_info.smdbu_id = RunAsUid;
1320Sstevel@tonic-gate 	user_info.smdbu_group_id = RunAsGid;
1330Sstevel@tonic-gate 	(void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
1340Sstevel@tonic-gate 			  SMDB_MAX_USER_NAME_LEN);
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate #define OPTIONS		"C:fquxvN"
1370Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, OPTIONS)) != -1)
1380Sstevel@tonic-gate 	{
1390Sstevel@tonic-gate 		switch (opt)
1400Sstevel@tonic-gate 		{
1410Sstevel@tonic-gate 		  case 'C':
1420Sstevel@tonic-gate 			cfile = optarg;
1430Sstevel@tonic-gate 			break;
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 		  case 'f':
1460Sstevel@tonic-gate 			foldcase = false;
1470Sstevel@tonic-gate 			break;
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 		  case 'q':
1500Sstevel@tonic-gate 			query = true;
1510Sstevel@tonic-gate 			nops++;
1520Sstevel@tonic-gate 			break;
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 		  case 'u':
1550Sstevel@tonic-gate 			update = true;
1560Sstevel@tonic-gate 			nops++;
1570Sstevel@tonic-gate 			break;
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate 		  case 'x':
1600Sstevel@tonic-gate 			remove = true;
1610Sstevel@tonic-gate 			nops++;
1620Sstevel@tonic-gate 			break;
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 		  case 'v':
1650Sstevel@tonic-gate 			verbose = true;
1660Sstevel@tonic-gate 			break;
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 		  case 'N':
1690Sstevel@tonic-gate 			inclnull = true;
1700Sstevel@tonic-gate 			break;
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 		  default:
1730Sstevel@tonic-gate 			usage(progname);
1740Sstevel@tonic-gate 			assert(0);  /* NOTREACHED */
1750Sstevel@tonic-gate 		}
1760Sstevel@tonic-gate 	}
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
1790Sstevel@tonic-gate 		sff |= SFF_NOSLINK;
1800Sstevel@tonic-gate 	if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
1810Sstevel@tonic-gate 		sff |= SFF_NOHLINK;
1820Sstevel@tonic-gate 	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
1830Sstevel@tonic-gate 		sff |= SFF_NOWLINK;
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 	argc -= optind;
1860Sstevel@tonic-gate 	argv += optind;
1870Sstevel@tonic-gate 	if ((nops != 1) ||
1880Sstevel@tonic-gate 	    (query && argc != 3) ||
1890Sstevel@tonic-gate 	    (remove && argc != 3) ||
1900Sstevel@tonic-gate 	    (update && argc <= 3))
1910Sstevel@tonic-gate 	{
1920Sstevel@tonic-gate 		usage(progname);
1930Sstevel@tonic-gate 		assert(0);  /* NOTREACHED */
1940Sstevel@tonic-gate 	}
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 	typename = argv[0];
1970Sstevel@tonic-gate 	mapname = argv[1];
1980Sstevel@tonic-gate 	keyname = argv[2];
1990Sstevel@tonic-gate 	if (update)
2000Sstevel@tonic-gate 		value = argv[3];
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 	if (foldcase)
2030Sstevel@tonic-gate 	{
2040Sstevel@tonic-gate 		char *p;
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 		for (p = keyname; *p != '\0'; p++)
2070Sstevel@tonic-gate 		{
2080Sstevel@tonic-gate 			if (isascii(*p) && isupper(*p))
2090Sstevel@tonic-gate 				*p = tolower(*p);
2100Sstevel@tonic-gate 		}
2110Sstevel@tonic-gate 	}
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate #if HASFCHOWN
2150Sstevel@tonic-gate 	/* Find TrustedUser value in sendmail.cf */
2160Sstevel@tonic-gate 	if ((cfp = fopen(cfile, "r")) == NULL)
2170Sstevel@tonic-gate 	{
2180Sstevel@tonic-gate 		fprintf(stderr, "%s: %s: %s\n", progname,
2190Sstevel@tonic-gate 			cfile, sm_errstring(errno));
2200Sstevel@tonic-gate 		exit(EX_NOINPUT);
2210Sstevel@tonic-gate 	}
2220Sstevel@tonic-gate 	while (fgets(buf, sizeof(buf), cfp) != NULL)
2230Sstevel@tonic-gate 	{
2240Sstevel@tonic-gate 		register char *b;
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 		if ((b = strchr(buf, '\n')) != NULL)
2270Sstevel@tonic-gate 			*b = '\0';
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 		b = buf;
2300Sstevel@tonic-gate 		switch (*b++)
2310Sstevel@tonic-gate 		{
2320Sstevel@tonic-gate 		  case 'O':		/* option */
2330Sstevel@tonic-gate 			if (strncasecmp(b, " TrustedUser", 12) == 0 &&
2340Sstevel@tonic-gate 			    !(isascii(b[12]) && isalnum(b[12])))
2350Sstevel@tonic-gate 			{
2360Sstevel@tonic-gate 				b = strchr(b, '=');
2370Sstevel@tonic-gate 				if (b == NULL)
2380Sstevel@tonic-gate 					continue;
2390Sstevel@tonic-gate 				while (isascii(*++b) && isspace(*b))
2400Sstevel@tonic-gate 					continue;
2410Sstevel@tonic-gate 				if (isascii(*b) && isdigit(*b))
2420Sstevel@tonic-gate 					TrustedUid = atoi(b);
2430Sstevel@tonic-gate 				else
2440Sstevel@tonic-gate 				{
2450Sstevel@tonic-gate 					TrustedUid = 0;
2460Sstevel@tonic-gate 					pw = getpwnam(b);
2470Sstevel@tonic-gate 					if (pw == NULL)
2480Sstevel@tonic-gate 						fprintf(stderr,
2490Sstevel@tonic-gate 							"TrustedUser: unknown user %s\n", b);
2500Sstevel@tonic-gate 					else
2510Sstevel@tonic-gate 						TrustedUid = pw->pw_uid;
2520Sstevel@tonic-gate 				}
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate # ifdef UID_MAX
2550Sstevel@tonic-gate 				if (TrustedUid > UID_MAX)
2560Sstevel@tonic-gate 				{
2570Sstevel@tonic-gate 					fprintf(stderr,
2580Sstevel@tonic-gate 						"TrustedUser: uid value (%ld) > UID_MAX (%ld)",
2590Sstevel@tonic-gate 						(long) TrustedUid,
2600Sstevel@tonic-gate 						(long) UID_MAX);
2610Sstevel@tonic-gate 					TrustedUid = 0;
2620Sstevel@tonic-gate 				}
2630Sstevel@tonic-gate # endif /* UID_MAX */
2640Sstevel@tonic-gate 				break;
2650Sstevel@tonic-gate 			}
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 		  default:
2690Sstevel@tonic-gate 			continue;
2700Sstevel@tonic-gate 		}
2710Sstevel@tonic-gate 	}
2720Sstevel@tonic-gate 	(void) fclose(cfp);
2730Sstevel@tonic-gate #endif /* HASFCHOWN */
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	if (query)
2760Sstevel@tonic-gate 	{
2770Sstevel@tonic-gate 		mode = O_RDONLY;
2780Sstevel@tonic-gate 		smode = S_IRUSR;
2790Sstevel@tonic-gate 	}
2800Sstevel@tonic-gate 	else
2810Sstevel@tonic-gate 	{
2820Sstevel@tonic-gate 		mode = O_RDWR | O_CREAT;
2830Sstevel@tonic-gate 		sff |= SFF_CREAT|SFF_NOTEXCL;
2840Sstevel@tonic-gate 		smode = S_IWUSR;
2850Sstevel@tonic-gate 	}
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	params.smdbp_num_elements = 4096;
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	errno = smdb_open_database(&database, mapname, mode, smode, sff,
2900Sstevel@tonic-gate 				   typename, &user_info, &params);
2910Sstevel@tonic-gate 	if (errno != SMDBE_OK)
2920Sstevel@tonic-gate 	{
2930Sstevel@tonic-gate 		char *hint;
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 		if (errno == SMDBE_UNSUPPORTED_DB_TYPE &&
2960Sstevel@tonic-gate 		    (hint = smdb_db_definition(typename)) != NULL)
2970Sstevel@tonic-gate 			fprintf(stderr,
2980Sstevel@tonic-gate 				"%s: Need to recompile with -D%s for %s support\n",
2990Sstevel@tonic-gate 				progname, hint, typename);
3000Sstevel@tonic-gate 		else
3010Sstevel@tonic-gate 			fprintf(stderr,
3020Sstevel@tonic-gate 				"%s: error opening type %s map %s: %s\n",
3030Sstevel@tonic-gate 				progname, typename, mapname,
3040Sstevel@tonic-gate 				sm_errstring(errno));
3050Sstevel@tonic-gate 		exit(EX_CANTCREAT);
3060Sstevel@tonic-gate 	}
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	(void) database->smdb_sync(database, 0);
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	if (geteuid() == 0 && TrustedUid != 0)
3110Sstevel@tonic-gate 	{
3120Sstevel@tonic-gate 		errno = database->smdb_set_owner(database, TrustedUid, -1);
3130Sstevel@tonic-gate 		if (errno != SMDBE_OK)
3140Sstevel@tonic-gate 		{
3150Sstevel@tonic-gate 			fprintf(stderr,
3160Sstevel@tonic-gate 				"WARNING: ownership change on %s failed %s",
3170Sstevel@tonic-gate 				mapname, sm_errstring(errno));
3180Sstevel@tonic-gate 		}
3190Sstevel@tonic-gate 	}
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	exitstat = EX_OK;
3220Sstevel@tonic-gate 	if (query)
3230Sstevel@tonic-gate 	{
3240Sstevel@tonic-gate 		memset(&db_key, '\0', sizeof db_key);
3250Sstevel@tonic-gate 		memset(&db_val, '\0', sizeof db_val);
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 		db_key.data = keyname;
3280Sstevel@tonic-gate 		db_key.size = strlen(keyname);
3290Sstevel@tonic-gate 		if (inclnull)
3300Sstevel@tonic-gate 			db_key.size++;
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 		errno = database->smdb_get(database, &db_key, &db_val, 0);
3330Sstevel@tonic-gate 		if (errno != SMDBE_OK)
3340Sstevel@tonic-gate 		{
3350Sstevel@tonic-gate 			/* XXX - Need to distinguish between not found */
3360Sstevel@tonic-gate 			fprintf(stderr,
3370Sstevel@tonic-gate 				"%s: couldn't find key %s in map %s\n",
3380Sstevel@tonic-gate 				progname, keyname, mapname);
3390Sstevel@tonic-gate 			exitstat = EX_UNAVAILABLE;
3400Sstevel@tonic-gate 		}
3410Sstevel@tonic-gate 		else
3420Sstevel@tonic-gate 		{
3430Sstevel@tonic-gate 			printf("%.*s\n", (int) db_val.size,
3440Sstevel@tonic-gate 			       (char *) db_val.data);
3450Sstevel@tonic-gate 		}
3460Sstevel@tonic-gate 	}
3470Sstevel@tonic-gate 	else if (update)
3480Sstevel@tonic-gate 	{
3490Sstevel@tonic-gate 		memset(&db_key, '\0', sizeof db_key);
3500Sstevel@tonic-gate 		memset(&db_val, '\0', sizeof db_val);
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 		db_key.data = keyname;
3530Sstevel@tonic-gate 		db_key.size = strlen(keyname);
3540Sstevel@tonic-gate 		if (inclnull)
3550Sstevel@tonic-gate 			db_key.size++;
3560Sstevel@tonic-gate 		db_val.data = value;
3570Sstevel@tonic-gate 		db_val.size = strlen(value);
3580Sstevel@tonic-gate 		if (inclnull)
3590Sstevel@tonic-gate 			db_val.size++;
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 		errno = database->smdb_put(database, &db_key, &db_val,
3620Sstevel@tonic-gate 					   putflags);
3630Sstevel@tonic-gate 		if (errno != SMDBE_OK)
3640Sstevel@tonic-gate 		{
3650Sstevel@tonic-gate 			fprintf(stderr,
3660Sstevel@tonic-gate 				"%s: error updating (%s, %s) in map %s: %s\n",
3670Sstevel@tonic-gate 				progname, keyname, value, mapname,
3680Sstevel@tonic-gate 				sm_errstring(errno));
3690Sstevel@tonic-gate 			exitstat = EX_IOERR;
3700Sstevel@tonic-gate 		}
3710Sstevel@tonic-gate 	}
3720Sstevel@tonic-gate 	else if (remove)
3730Sstevel@tonic-gate 	{
3740Sstevel@tonic-gate 		memset(&db_key, '\0', sizeof db_key);
3750Sstevel@tonic-gate 		memset(&db_val, '\0', sizeof db_val);
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 		db_key.data = keyname;
3780Sstevel@tonic-gate 		db_key.size = strlen(keyname);
3790Sstevel@tonic-gate 		if (inclnull)
3800Sstevel@tonic-gate 			db_key.size++;
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 		errno = database->smdb_del(database, &db_key, 0);
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 		switch (errno)
3850Sstevel@tonic-gate 		{
3860Sstevel@tonic-gate 		case SMDBE_NOT_FOUND:
3870Sstevel@tonic-gate 			fprintf(stderr,
3880Sstevel@tonic-gate 				"%s: key %s doesn't exist in map %s\n",
3890Sstevel@tonic-gate 				progname, keyname, mapname);
3900Sstevel@tonic-gate 			/* Don't set exitstat */
3910Sstevel@tonic-gate 			break;
3920Sstevel@tonic-gate 		case SMDBE_OK:
3930Sstevel@tonic-gate 			/* All's well */
3940Sstevel@tonic-gate 			break;
3950Sstevel@tonic-gate 		default:
3960Sstevel@tonic-gate 			fprintf(stderr,
3970Sstevel@tonic-gate 				"%s: couldn't remove key %s in map %s (error)\n",
3980Sstevel@tonic-gate 				progname, keyname, mapname);
3990Sstevel@tonic-gate 			exitstat = EX_IOERR;
4000Sstevel@tonic-gate 			break;
4010Sstevel@tonic-gate 		}
4020Sstevel@tonic-gate 	}
4030Sstevel@tonic-gate 	else
4040Sstevel@tonic-gate 	{
4050Sstevel@tonic-gate 		assert(0);  /* NOT REACHED */
4060Sstevel@tonic-gate 	}
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	/*
4090Sstevel@tonic-gate 	**  Now close the database.
4100Sstevel@tonic-gate 	*/
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	errno = database->smdb_close(database);
4130Sstevel@tonic-gate 	if (errno != SMDBE_OK)
4140Sstevel@tonic-gate 	{
4150Sstevel@tonic-gate 		fprintf(stderr, "%s: close(%s): %s\n",
4160Sstevel@tonic-gate 			progname, mapname, sm_errstring(errno));
4170Sstevel@tonic-gate 		exitstat = EX_IOERR;
4180Sstevel@tonic-gate 	}
4190Sstevel@tonic-gate 	smdb_free_database(database);
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	exit(exitstat);
4220Sstevel@tonic-gate 	/* NOTREACHED */
4230Sstevel@tonic-gate 	return exitstat;
4240Sstevel@tonic-gate }
425