138032Speter/*
2182352Sgshapiro * Copyright (c) 1998-2002, 2004, 2008 Sendmail, Inc. and its suppliers.
364565Sgshapiro *	All rights reserved.
438032Speter * Copyright (c) 1992 Eric P. Allman.  All rights reserved.
538032Speter * Copyright (c) 1992, 1993
638032Speter *	The Regents of the University of California.  All rights reserved.
738032Speter *
838032Speter * By using this file, you agree to the terms and conditions set
938032Speter * forth in the LICENSE file which can be found at the top level of
1038032Speter * the sendmail distribution.
1138032Speter *
1238032Speter */
1338032Speter
1490795Sgshapiro#include <sm/gen.h>
1590795Sgshapiro
1690795SgshapiroSM_IDSTR(copyright,
17141862Sgshapiro"@(#) Copyright (c) 1998-2002, 2004 Sendmail, Inc. and its suppliers.\n\
1864565Sgshapiro	All rights reserved.\n\
1964565Sgshapiro     Copyright (c) 1992 Eric P. Allman.  All rights reserved.\n\
2064565Sgshapiro     Copyright (c) 1992, 1993\n\
2190795Sgshapiro	The Regents of the University of California.  All rights reserved.\n")
2238032Speter
23249729SgshapiroSM_IDSTR(id, "@(#)$Id: makemap.c,v 8.181 2013/03/12 15:24:51 ca Exp $")
2464565Sgshapiro
25111367Sgshapiro
2638032Speter#include <sys/types.h>
2738032Speter#ifndef ISC_UNIX
2838032Speter# include <sys/file.h>
2964565Sgshapiro#endif /* ! ISC_UNIX */
3064565Sgshapiro#include <ctype.h>
3164565Sgshapiro#include <stdlib.h>
3264565Sgshapiro#include <unistd.h>
3364565Sgshapiro#ifdef EX_OK
3464565Sgshapiro# undef EX_OK		/* unistd.h may have another use for this */
3564565Sgshapiro#endif /* EX_OK */
3664565Sgshapiro#include <sysexits.h>
3764565Sgshapiro#include <sendmail/sendmail.h>
3864565Sgshapiro#include <sendmail/pathnames.h>
3964565Sgshapiro#include <libsmdb/smdb.h>
4038032Speter
4138032Speteruid_t	RealUid;
4238032Spetergid_t	RealGid;
4338032Speterchar	*RealUserName;
4438032Speteruid_t	RunAsUid;
45173343Sgshapirogid_t	RunAsGid;
4638032Speterchar	*RunAsUserName;
4738032Speterint	Verbose = 2;
4890795Sgshapirobool	DontInitGroups = false;
4942580Speteruid_t	TrustedUid = 0;
5064565SgshapiroBITMAP256 DontBlameSendmail;
5138032Speter
5238032Speter#define BUFSIZE		1024
5390795Sgshapiro#define ISSEP(c) (sep == '\0' ? isascii(c) && isspace(c) : (c) == sep)
5438032Speter
55141862Sgshapirostatic void usage __P((char *));
56141862Sgshapiro
5764565Sgshapirostatic void
5864565Sgshapirousage(progname)
5964565Sgshapiro	char *progname;
6064565Sgshapiro{
6190795Sgshapiro	sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
62132946Sgshapiro		      "Usage: %s [-C cffile] [-N] [-c cachesize] [-D commentchar]\n",
63132946Sgshapiro		      progname);
64132946Sgshapiro	sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
65132946Sgshapiro		      "       %*s [-d] [-e] [-f] [-l] [-o] [-r] [-s] [-t delimiter]\n",
66132946Sgshapiro		      (int) strlen(progname), "");
67132946Sgshapiro	sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
68132946Sgshapiro		      "       %*s [-u] [-v] type mapname\n",
69132946Sgshapiro		      (int) strlen(progname), "");
7064565Sgshapiro	exit(EX_USAGE);
7164565Sgshapiro}
7264565Sgshapiro
7338032Speterint
7438032Spetermain(argc, argv)
7538032Speter	int argc;
7638032Speter	char **argv;
7738032Speter{
7838032Speter	char *progname;
7938032Speter	char *cfile;
8090795Sgshapiro	bool inclnull = false;
8190795Sgshapiro	bool notrunc = false;
8290795Sgshapiro	bool allowreplace = false;
8390795Sgshapiro	bool allowempty = false;
8490795Sgshapiro	bool verbose = false;
8590795Sgshapiro	bool foldcase = true;
8690795Sgshapiro	bool unmake = false;
8764565Sgshapiro	char sep = '\0';
8890795Sgshapiro	char comment = '#';
8938032Speter	int exitstat;
9038032Speter	int opt;
9142580Speter	char *typename = NULL;
9242580Speter	char *mapname = NULL;
9390795Sgshapiro	unsigned int lineno;
9438032Speter	int st;
9538032Speter	int mode;
9664565Sgshapiro	int smode;
9742580Speter	int putflags = 0;
9864565Sgshapiro	long sff = SFF_ROOTOK|SFF_REGONLY;
9938032Speter	struct passwd *pw;
10064565Sgshapiro	SMDB_DATABASE *database;
10164565Sgshapiro	SMDB_CURSOR *cursor;
10264565Sgshapiro	SMDB_DBENT db_key, db_val;
10364565Sgshapiro	SMDB_DBPARAMS params;
10464565Sgshapiro	SMDB_USER_INFO user_info;
10538032Speter	char ibuf[BUFSIZE];
10664565Sgshapiro#if HASFCHOWN
10790795Sgshapiro	SM_FILE_T *cfp;
10838032Speter	char buf[MAXLINE];
10964565Sgshapiro#endif /* HASFCHOWN */
11038032Speter	static char rnamebuf[MAXNAME];	/* holds RealUserName */
11138032Speter	extern char *optarg;
11238032Speter	extern int optind;
11338032Speter
11464565Sgshapiro	memset(&params, '\0', sizeof params);
11564565Sgshapiro	params.smdbp_cache_size = 1024 * 1024;
11664565Sgshapiro
11764565Sgshapiro	progname = strrchr(argv[0], '/');
11864565Sgshapiro	if (progname != NULL)
11964565Sgshapiro		progname++;
12064565Sgshapiro	else
12164565Sgshapiro		progname = argv[0];
12290795Sgshapiro	cfile = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL);
12338032Speter
12464565Sgshapiro	clrbitmap(DontBlameSendmail);
12538032Speter	RunAsUid = RealUid = getuid();
12638032Speter	RunAsGid = RealGid = getgid();
12738032Speter	pw = getpwuid(RealUid);
12838032Speter	if (pw != NULL)
12990795Sgshapiro		(void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf);
13038032Speter	else
13190795Sgshapiro		(void) sm_snprintf(rnamebuf, sizeof rnamebuf,
13290795Sgshapiro		    "Unknown UID %d", (int) RealUid);
13338032Speter	RunAsUserName = RealUserName = rnamebuf;
13464565Sgshapiro	user_info.smdbu_id = RunAsUid;
13564565Sgshapiro	user_info.smdbu_group_id = RunAsGid;
13690795Sgshapiro	(void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
13764565Sgshapiro		       SMDB_MAX_USER_NAME_LEN);
13838032Speter
13990795Sgshapiro#define OPTIONS		"C:D:Nc:deflorst:uv"
14038076Speter	while ((opt = getopt(argc, argv, OPTIONS)) != -1)
14138032Speter	{
14238032Speter		switch (opt)
14338032Speter		{
14438032Speter		  case 'C':
14538032Speter			cfile = optarg;
14638032Speter			break;
14738032Speter
14838032Speter		  case 'N':
14990795Sgshapiro			inclnull = true;
15038032Speter			break;
15138032Speter
15238032Speter		  case 'c':
15364565Sgshapiro			params.smdbp_cache_size = atol(optarg);
15438032Speter			break;
15538032Speter
15638032Speter		  case 'd':
15790795Sgshapiro			params.smdbp_allow_dup = true;
15838032Speter			break;
15938032Speter
16064565Sgshapiro		  case 'e':
16190795Sgshapiro			allowempty = true;
16264565Sgshapiro			break;
16364565Sgshapiro
16438032Speter		  case 'f':
16590795Sgshapiro			foldcase = false;
16638032Speter			break;
16738032Speter
16890795Sgshapiro		  case 'D':
16990795Sgshapiro			comment = *optarg;
17090795Sgshapiro			break;
17190795Sgshapiro
17242580Speter		  case 'l':
17364565Sgshapiro			smdb_print_available_types();
17442580Speter			exit(EX_OK);
17542580Speter			break;
17642580Speter
17738032Speter		  case 'o':
17890795Sgshapiro			notrunc = true;
17938032Speter			break;
18038032Speter
18138032Speter		  case 'r':
18290795Sgshapiro			allowreplace = true;
18338032Speter			break;
18438032Speter
18538032Speter		  case 's':
18664565Sgshapiro			setbitn(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail);
18764565Sgshapiro			setbitn(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail);
18864565Sgshapiro			setbitn(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail);
18964565Sgshapiro			setbitn(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail);
19038032Speter			break;
19138032Speter
19264565Sgshapiro		  case 't':
19364565Sgshapiro			if (optarg == NULL || *optarg == '\0')
19464565Sgshapiro			{
19590795Sgshapiro				sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
19690795Sgshapiro					      "Invalid separator\n");
19764565Sgshapiro				break;
19864565Sgshapiro			}
19964565Sgshapiro			sep = *optarg;
20064565Sgshapiro			break;
20164565Sgshapiro
20264565Sgshapiro		  case 'u':
20390795Sgshapiro			unmake = true;
20464565Sgshapiro			break;
20564565Sgshapiro
20638032Speter		  case 'v':
20790795Sgshapiro			verbose = true;
20838032Speter			break;
20938032Speter
21038032Speter		  default:
21164565Sgshapiro			usage(progname);
21264565Sgshapiro			/* NOTREACHED */
21338032Speter		}
21438032Speter	}
21538032Speter
21664565Sgshapiro	if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
21738032Speter		sff |= SFF_NOSLINK;
21864565Sgshapiro	if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
21938032Speter		sff |= SFF_NOHLINK;
22064565Sgshapiro	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
22138032Speter		sff |= SFF_NOWLINK;
22238032Speter
22338032Speter	argc -= optind;
22438032Speter	argv += optind;
22538032Speter	if (argc != 2)
22664565Sgshapiro	{
22764565Sgshapiro		usage(progname);
22864565Sgshapiro		/* NOTREACHED */
22964565Sgshapiro	}
23038032Speter	else
23138032Speter	{
23238032Speter		typename = argv[0];
23338032Speter		mapname = argv[1];
23438032Speter	}
23538032Speter
23664565Sgshapiro#if HASFCHOWN
23764565Sgshapiro	/* Find TrustedUser value in sendmail.cf */
23890795Sgshapiro	if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY,
23990795Sgshapiro			      NULL)) == NULL)
24038032Speter	{
241223067Sgshapiro		sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "makemap: %s: %s\n",
24290795Sgshapiro			      cfile, sm_errstring(errno));
24338032Speter		exit(EX_NOINPUT);
24438032Speter	}
245249729Sgshapiro	while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0)
24638032Speter	{
24738032Speter		register char *b;
24838032Speter
24938032Speter		if ((b = strchr(buf, '\n')) != NULL)
25038032Speter			*b = '\0';
25138032Speter
25238032Speter		b = buf;
25338032Speter		switch (*b++)
25438032Speter		{
25538032Speter		  case 'O':		/* option */
25642580Speter			if (strncasecmp(b, " TrustedUser", 12) == 0 &&
25742580Speter			    !(isascii(b[12]) && isalnum(b[12])))
25838032Speter			{
25938032Speter				b = strchr(b, '=');
26038032Speter				if (b == NULL)
26138032Speter					continue;
26238032Speter				while (isascii(*++b) && isspace(*b))
26338032Speter					continue;
26438032Speter				if (isascii(*b) && isdigit(*b))
26542580Speter					TrustedUid = atoi(b);
26638032Speter				else
26738032Speter				{
26842580Speter					TrustedUid = 0;
26938032Speter					pw = getpwnam(b);
27038032Speter					if (pw == NULL)
27190795Sgshapiro						(void) sm_io_fprintf(smioerr,
27290795Sgshapiro								     SM_TIME_DEFAULT,
27390795Sgshapiro								     "TrustedUser: unknown user %s\n", b);
27438032Speter					else
27542580Speter						TrustedUid = pw->pw_uid;
27638032Speter				}
27764565Sgshapiro
27838032Speter# ifdef UID_MAX
27942580Speter				if (TrustedUid > UID_MAX)
28038032Speter				{
28190795Sgshapiro					(void) sm_io_fprintf(smioerr,
28290795Sgshapiro							     SM_TIME_DEFAULT,
28390795Sgshapiro							     "TrustedUser: uid value (%ld) > UID_MAX (%ld)",
28464565Sgshapiro						(long) TrustedUid,
28564565Sgshapiro						(long) UID_MAX);
28642580Speter					TrustedUid = 0;
28738032Speter				}
28864565Sgshapiro# endif /* UID_MAX */
28938032Speter				break;
29038032Speter			}
29138032Speter
29238032Speter
29338032Speter		  default:
29438032Speter			continue;
29538032Speter		}
29638032Speter	}
29790795Sgshapiro	(void) sm_io_close(cfp, SM_TIME_DEFAULT);
29864565Sgshapiro#endif /* HASFCHOWN */
29938032Speter
30064565Sgshapiro	if (!params.smdbp_allow_dup && !allowreplace)
30164565Sgshapiro		putflags = SMDBF_NO_OVERWRITE;
30238032Speter
30364565Sgshapiro	if (unmake)
30464565Sgshapiro	{
30564565Sgshapiro		mode = O_RDONLY;
30664565Sgshapiro		smode = S_IRUSR;
30764565Sgshapiro	}
30864565Sgshapiro	else
30964565Sgshapiro	{
31064565Sgshapiro		mode = O_RDWR;
31164565Sgshapiro		if (!notrunc)
31238032Speter		{
31364565Sgshapiro			mode |= O_CREAT|O_TRUNC;
31464565Sgshapiro			sff |= SFF_CREAT;
31538032Speter		}
31664565Sgshapiro		smode = S_IWUSR;
31738032Speter	}
31838032Speter
31964565Sgshapiro	params.smdbp_num_elements = 4096;
32038032Speter
32164565Sgshapiro	errno = smdb_open_database(&database, mapname, mode, smode, sff,
32264565Sgshapiro				   typename, &user_info, &params);
32364565Sgshapiro	if (errno != SMDBE_OK)
32438032Speter	{
32564565Sgshapiro		char *hint;
32638032Speter
32764565Sgshapiro		if (errno == SMDBE_UNSUPPORTED_DB_TYPE &&
32864565Sgshapiro		    (hint = smdb_db_definition(typename)) != NULL)
32990795Sgshapiro			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
33090795Sgshapiro					     "%s: Need to recompile with -D%s for %s support\n",
33190795Sgshapiro					     progname, hint, typename);
33264565Sgshapiro		else
33390795Sgshapiro			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
33490795Sgshapiro					     "%s: error opening type %s map %s: %s\n",
33590795Sgshapiro					     progname, typename, mapname,
33690795Sgshapiro					     sm_errstring(errno));
33764565Sgshapiro		exit(EX_CANTCREAT);
33838032Speter	}
33938032Speter
34064565Sgshapiro	(void) database->smdb_sync(database, 0);
34164565Sgshapiro
34266497Sgshapiro	if (!unmake && geteuid() == 0 && TrustedUid != 0)
34338032Speter	{
34464565Sgshapiro		errno = database->smdb_set_owner(database, TrustedUid, -1);
34564565Sgshapiro		if (errno != SMDBE_OK)
34638032Speter		{
34790795Sgshapiro			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
34890795Sgshapiro					     "WARNING: ownership change on %s failed %s",
34990795Sgshapiro					     mapname, sm_errstring(errno));
35038032Speter		}
35138032Speter	}
35238032Speter
35338032Speter	/*
35464565Sgshapiro	**  Copy the data
35538032Speter	*/
35638032Speter
35764565Sgshapiro	exitstat = EX_OK;
35864565Sgshapiro	if (unmake)
35938032Speter	{
36064565Sgshapiro		errno = database->smdb_cursor(database, &cursor, 0);
36164565Sgshapiro		if (errno != SMDBE_OK)
36238032Speter		{
36364565Sgshapiro
36490795Sgshapiro			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
36590795Sgshapiro					     "%s: cannot make cursor for type %s map %s\n",
36690795Sgshapiro					     progname, typename, mapname);
36764565Sgshapiro			exit(EX_SOFTWARE);
36838032Speter		}
36964565Sgshapiro
37064565Sgshapiro		memset(&db_key, '\0', sizeof db_key);
37164565Sgshapiro		memset(&db_val, '\0', sizeof db_val);
37264565Sgshapiro
37371348Sgshapiro		for (lineno = 0; ; lineno++)
37438032Speter		{
37564565Sgshapiro			errno = cursor->smdbc_get(cursor, &db_key, &db_val,
37664565Sgshapiro						  SMDB_CURSOR_GET_NEXT);
37764565Sgshapiro			if (errno != SMDBE_OK)
37871348Sgshapiro				break;
37964565Sgshapiro
38090795Sgshapiro			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
381182352Sgshapiro					     "%.*s%c%.*s\n",
38290795Sgshapiro					     (int) db_key.size,
38390795Sgshapiro					     (char *) db_key.data,
384182352Sgshapiro					     (sep != '\0') ? sep : '\t',
38590795Sgshapiro					     (int) db_val.size,
38690795Sgshapiro					     (char *)db_val.data);
38771348Sgshapiro
38838032Speter		}
38964565Sgshapiro		(void) cursor->smdbc_close(cursor);
39064565Sgshapiro	}
39164565Sgshapiro	else
39264565Sgshapiro	{
39364565Sgshapiro		lineno = 0;
39490795Sgshapiro		while (sm_io_fgets(smioin, SM_TIME_DEFAULT, ibuf, sizeof ibuf)
395249729Sgshapiro		       >= 0)
39664565Sgshapiro		{
39764565Sgshapiro			register char *p;
39838032Speter
39964565Sgshapiro			lineno++;
40038032Speter
40164565Sgshapiro			/*
40264565Sgshapiro			**  Parse the line.
40364565Sgshapiro			*/
40464565Sgshapiro
40564565Sgshapiro			p = strchr(ibuf, '\n');
40664565Sgshapiro			if (p != NULL)
40764565Sgshapiro				*p = '\0';
40890795Sgshapiro			else if (!sm_io_eof(smioin))
40938032Speter			{
41090795Sgshapiro				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
41190795Sgshapiro						     "%s: %s: line %u: line too long (%ld bytes max)\n",
41290795Sgshapiro						     progname, mapname, lineno,
41390795Sgshapiro						     (long) sizeof ibuf);
41464565Sgshapiro				exitstat = EX_DATAERR;
41564565Sgshapiro				continue;
41638032Speter			}
41764565Sgshapiro
41890795Sgshapiro			if (ibuf[0] == '\0' || ibuf[0] == comment)
41964565Sgshapiro				continue;
42090795Sgshapiro			if (sep == '\0' && isascii(ibuf[0]) && isspace(ibuf[0]))
42138032Speter			{
42290795Sgshapiro				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
42390795Sgshapiro						     "%s: %s: line %u: syntax error (leading space)\n",
42490795Sgshapiro						     progname, mapname, lineno);
42564565Sgshapiro				exitstat = EX_DATAERR;
42664565Sgshapiro				continue;
42738032Speter			}
42838032Speter
42964565Sgshapiro			memset(&db_key, '\0', sizeof db_key);
43064565Sgshapiro			memset(&db_val, '\0', sizeof db_val);
43171348Sgshapiro			db_key.data = ibuf;
43238032Speter
43364565Sgshapiro			for (p = ibuf; *p != '\0' && !(ISSEP(*p)); p++)
43438032Speter			{
43564565Sgshapiro				if (foldcase && isascii(*p) && isupper(*p))
43664565Sgshapiro					*p = tolower(*p);
43738032Speter			}
43871348Sgshapiro			db_key.size = p - ibuf;
43964565Sgshapiro			if (inclnull)
44071348Sgshapiro				db_key.size++;
44164565Sgshapiro
44264565Sgshapiro			if (*p != '\0')
44364565Sgshapiro				*p++ = '\0';
44490795Sgshapiro			while (*p != '\0' && ISSEP(*p))
44564565Sgshapiro				p++;
44664565Sgshapiro			if (!allowempty && *p == '\0')
44738032Speter			{
44890795Sgshapiro				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
44990795Sgshapiro						     "%s: %s: line %u: no RHS for LHS %s\n",
45090795Sgshapiro						     progname, mapname, lineno,
45190795Sgshapiro						     (char *) db_key.data);
45264565Sgshapiro				exitstat = EX_DATAERR;
45364565Sgshapiro				continue;
45438032Speter			}
45538032Speter
45671348Sgshapiro			db_val.data = p;
45771348Sgshapiro			db_val.size = strlen(p);
45864565Sgshapiro			if (inclnull)
45971348Sgshapiro				db_val.size++;
46038032Speter
46164565Sgshapiro			/*
46264565Sgshapiro			**  Do the database insert.
46364565Sgshapiro			*/
46438032Speter
46564565Sgshapiro			if (verbose)
46664565Sgshapiro			{
46790795Sgshapiro				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
46890795Sgshapiro						     "key=`%s', val=`%s'\n",
46990795Sgshapiro						     (char *) db_key.data,
47090795Sgshapiro						     (char *) db_val.data);
47164565Sgshapiro			}
47238032Speter
47364565Sgshapiro			errno = database->smdb_put(database, &db_key, &db_val,
47464565Sgshapiro						   putflags);
47538032Speter			switch (errno)
47638032Speter			{
47764565Sgshapiro			  case SMDBE_KEY_EXIST:
47838032Speter				st = 1;
47938032Speter				break;
48038032Speter
48138032Speter			  case 0:
48238032Speter				st = 0;
48338032Speter				break;
48438032Speter
48538032Speter			  default:
48638032Speter				st = -1;
48738032Speter				break;
48838032Speter			}
48938032Speter
49064565Sgshapiro			if (st < 0)
49164565Sgshapiro			{
49290795Sgshapiro				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
49390795Sgshapiro						     "%s: %s: line %u: key %s: put error: %s\n",
49490795Sgshapiro						     progname, mapname, lineno,
49590795Sgshapiro						     (char *) db_key.data,
49690795Sgshapiro						     sm_errstring(errno));
49764565Sgshapiro				exitstat = EX_IOERR;
49864565Sgshapiro			}
49964565Sgshapiro			else if (st > 0)
50064565Sgshapiro			{
50190795Sgshapiro				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
50290795Sgshapiro						     "%s: %s: line %u: key %s: duplicate key\n",
50390795Sgshapiro						     progname, mapname,
50490795Sgshapiro						     lineno,
50590795Sgshapiro						     (char *) db_key.data);
50664565Sgshapiro				exitstat = EX_DATAERR;
50764565Sgshapiro			}
50838032Speter		}
50938032Speter	}
51038032Speter
51138032Speter	/*
51238032Speter	**  Now close the database.
51338032Speter	*/
51438032Speter
51564565Sgshapiro	errno = database->smdb_close(database);
51664565Sgshapiro	if (errno != SMDBE_OK)
51738032Speter	{
51890795Sgshapiro		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
51990795Sgshapiro				     "%s: close(%s): %s\n",
52090795Sgshapiro				     progname, mapname, sm_errstring(errno));
52164565Sgshapiro		exitstat = EX_IOERR;
52238032Speter	}
52364565Sgshapiro	smdb_free_database(database);
52438032Speter
52564565Sgshapiro	exit(exitstat);
52690795Sgshapiro
52764565Sgshapiro	/* NOTREACHED */
52864565Sgshapiro	return exitstat;
52938032Speter}
530