xref: /onnv-gate/usr/src/cmd/sendmail/aux/praliases.c (revision 11440:802724e2906a)
10Sstevel@tonic-gate /*
2*11440SJohn.Beck@Sun.COM  * Copyright (c) 1998-2001, 2008 Sendmail, Inc. and its suppliers.
30Sstevel@tonic-gate  *	All rights reserved.
40Sstevel@tonic-gate  * Copyright (c) 1983 Eric P. Allman.  All rights reserved.
50Sstevel@tonic-gate  * Copyright (c) 1988, 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 #include <sm/gen.h>
150Sstevel@tonic-gate 
160Sstevel@tonic-gate SM_IDSTR(copyright,
170Sstevel@tonic-gate "@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\
180Sstevel@tonic-gate 	All rights reserved.\n\
190Sstevel@tonic-gate      Copyright (c) 1983 Eric P. Allman.  All rights reserved.\n\
200Sstevel@tonic-gate      Copyright (c) 1988, 1993\n\
210Sstevel@tonic-gate 	The Regents of the University of California.  All rights reserved.\n")
220Sstevel@tonic-gate 
23*11440SJohn.Beck@Sun.COM SM_IDSTR(id, "@(#)$Id: praliases.c,v 8.96 2008/07/10 20:13:10 ca Exp $")
240Sstevel@tonic-gate 
250Sstevel@tonic-gate #include <sys/types.h>
260Sstevel@tonic-gate #include <ctype.h>
270Sstevel@tonic-gate #include <stdlib.h>
280Sstevel@tonic-gate #include <unistd.h>
290Sstevel@tonic-gate #ifdef EX_OK
300Sstevel@tonic-gate # undef EX_OK		/* unistd.h may have another use for this */
310Sstevel@tonic-gate #endif /* EX_OK */
320Sstevel@tonic-gate #include <sysexits.h>
330Sstevel@tonic-gate 
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #ifndef NOT_SENDMAIL
360Sstevel@tonic-gate # define NOT_SENDMAIL
370Sstevel@tonic-gate #endif /* ! NOT_SENDMAIL */
380Sstevel@tonic-gate #include <sendmail/sendmail.h>
390Sstevel@tonic-gate #include <sendmail/pathnames.h>
400Sstevel@tonic-gate #include <libsmdb/smdb.h>
410Sstevel@tonic-gate 
420Sstevel@tonic-gate static void praliases __P((char *, int, char **));
430Sstevel@tonic-gate 
440Sstevel@tonic-gate uid_t	RealUid;
450Sstevel@tonic-gate gid_t	RealGid;
460Sstevel@tonic-gate char	*RealUserName;
470Sstevel@tonic-gate uid_t	RunAsUid;
485402Sjbeck gid_t	RunAsGid;
490Sstevel@tonic-gate char	*RunAsUserName;
500Sstevel@tonic-gate int	Verbose = 2;
510Sstevel@tonic-gate bool	DontInitGroups = false;
520Sstevel@tonic-gate uid_t	TrustedUid = 0;
530Sstevel@tonic-gate BITMAP256 DontBlameSendmail;
540Sstevel@tonic-gate 
550Sstevel@tonic-gate # define DELIMITERS		" ,/"
560Sstevel@tonic-gate # define PATH_SEPARATOR		':'
570Sstevel@tonic-gate 
580Sstevel@tonic-gate int
main(argc,argv)590Sstevel@tonic-gate main(argc, argv)
600Sstevel@tonic-gate 	int argc;
610Sstevel@tonic-gate 	char **argv;
620Sstevel@tonic-gate {
630Sstevel@tonic-gate 	char *cfile;
640Sstevel@tonic-gate 	char *filename = NULL;
650Sstevel@tonic-gate 	SM_FILE_T *cfp;
660Sstevel@tonic-gate 	int ch;
670Sstevel@tonic-gate 	char afilebuf[MAXLINE];
680Sstevel@tonic-gate 	char buf[MAXLINE];
690Sstevel@tonic-gate 	struct passwd *pw;
700Sstevel@tonic-gate 	static char rnamebuf[MAXNAME];
710Sstevel@tonic-gate 	extern char *optarg;
720Sstevel@tonic-gate 	extern int optind;
730Sstevel@tonic-gate 
740Sstevel@tonic-gate 	clrbitmap(DontBlameSendmail);
750Sstevel@tonic-gate 	RunAsUid = RealUid = getuid();
760Sstevel@tonic-gate 	RunAsGid = RealGid = getgid();
770Sstevel@tonic-gate 	pw = getpwuid(RealUid);
780Sstevel@tonic-gate 	if (pw != NULL)
790Sstevel@tonic-gate 	{
800Sstevel@tonic-gate 		if (strlen(pw->pw_name) > MAXNAME - 1)
810Sstevel@tonic-gate 			pw->pw_name[MAXNAME] = 0;
820Sstevel@tonic-gate 		sm_snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);
830Sstevel@tonic-gate 	}
840Sstevel@tonic-gate 	else
850Sstevel@tonic-gate 		(void) sm_snprintf(rnamebuf, sizeof rnamebuf,
860Sstevel@tonic-gate 		    "Unknown UID %d", (int) RealUid);
870Sstevel@tonic-gate 	RunAsUserName = RealUserName = rnamebuf;
880Sstevel@tonic-gate 
890Sstevel@tonic-gate 	cfile = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL);
900Sstevel@tonic-gate 	while ((ch = getopt(argc, argv, "C:f:")) != -1)
910Sstevel@tonic-gate 	{
920Sstevel@tonic-gate 		switch ((char)ch) {
930Sstevel@tonic-gate 		case 'C':
940Sstevel@tonic-gate 			cfile = optarg;
950Sstevel@tonic-gate 			break;
960Sstevel@tonic-gate 		case 'f':
970Sstevel@tonic-gate 			filename = optarg;
980Sstevel@tonic-gate 			break;
990Sstevel@tonic-gate 		case '?':
1000Sstevel@tonic-gate 		default:
1010Sstevel@tonic-gate 			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
102*11440SJohn.Beck@Sun.COM 			    "usage: praliases [-C cffile] [-f aliasfile]"
103*11440SJohn.Beck@Sun.COM 			    " [key ...]\n");
1040Sstevel@tonic-gate 			exit(EX_USAGE);
1050Sstevel@tonic-gate 		}
1060Sstevel@tonic-gate 	}
1070Sstevel@tonic-gate 	argc -= optind;
1080Sstevel@tonic-gate 	argv += optind;
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 	if (filename != NULL)
1110Sstevel@tonic-gate 	{
1120Sstevel@tonic-gate 		praliases(filename, argc, argv);
1130Sstevel@tonic-gate 		exit(EX_OK);
1140Sstevel@tonic-gate 	}
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 	if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY,
1170Sstevel@tonic-gate 			      NULL)) == NULL)
1180Sstevel@tonic-gate 	{
1190Sstevel@tonic-gate 		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
1200Sstevel@tonic-gate 				     "praliases: %s: %s\n", cfile,
1210Sstevel@tonic-gate 				     sm_errstring(errno));
1220Sstevel@tonic-gate 		exit(EX_NOINPUT);
1230Sstevel@tonic-gate 	}
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 	while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL)
1260Sstevel@tonic-gate 	{
1270Sstevel@tonic-gate 		register char *b, *p;
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 		b = strchr(buf, '\n');
1300Sstevel@tonic-gate 		if (b != NULL)
1310Sstevel@tonic-gate 			*b = '\0';
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 		b = buf;
1340Sstevel@tonic-gate 		switch (*b++)
1350Sstevel@tonic-gate 		{
1360Sstevel@tonic-gate 		  case 'O':		/* option -- see if alias file */
1370Sstevel@tonic-gate 			if (sm_strncasecmp(b, " AliasFile", 10) == 0 &&
1380Sstevel@tonic-gate 			    !(isascii(b[10]) && isalnum(b[10])))
1390Sstevel@tonic-gate 			{
1400Sstevel@tonic-gate 				/* new form -- find value */
1410Sstevel@tonic-gate 				b = strchr(b, '=');
1420Sstevel@tonic-gate 				if (b == NULL)
1430Sstevel@tonic-gate 					continue;
1440Sstevel@tonic-gate 				while (isascii(*++b) && isspace(*b))
1450Sstevel@tonic-gate 					continue;
1460Sstevel@tonic-gate 			}
1470Sstevel@tonic-gate 			else if (*b++ != 'A')
1480Sstevel@tonic-gate 			{
1490Sstevel@tonic-gate 				/* something else boring */
1500Sstevel@tonic-gate 				continue;
1510Sstevel@tonic-gate 			}
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 			/* this is the A or AliasFile option -- save it */
1540Sstevel@tonic-gate 			if (sm_strlcpy(afilebuf, b, sizeof afilebuf) >=
1550Sstevel@tonic-gate 			    sizeof afilebuf)
1560Sstevel@tonic-gate 			{
1570Sstevel@tonic-gate 				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
1580Sstevel@tonic-gate 				    "praliases: AliasFile filename too long: %.30s\n",
1590Sstevel@tonic-gate 					b);
1600Sstevel@tonic-gate 				(void) sm_io_close(cfp, SM_TIME_DEFAULT);
1610Sstevel@tonic-gate 				exit(EX_CONFIG);
1620Sstevel@tonic-gate 			}
1630Sstevel@tonic-gate 			b = afilebuf;
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 			for (p = b; p != NULL; )
1660Sstevel@tonic-gate 			{
1670Sstevel@tonic-gate 				while (isascii(*p) && isspace(*p))
1680Sstevel@tonic-gate 					p++;
1690Sstevel@tonic-gate 				if (*p == '\0')
1700Sstevel@tonic-gate 					break;
1710Sstevel@tonic-gate 				b = p;
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 				p = strpbrk(p, DELIMITERS);
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 				/* find end of spec */
1760Sstevel@tonic-gate 				if (p != NULL)
1770Sstevel@tonic-gate 				{
1780Sstevel@tonic-gate 					bool quoted = false;
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 					for (; *p != '\0'; p++)
1810Sstevel@tonic-gate 					{
1820Sstevel@tonic-gate 						/*
1830Sstevel@tonic-gate 						**  Don't break into a quoted
1840Sstevel@tonic-gate 						**  string.
1850Sstevel@tonic-gate 						*/
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate 						if (*p == '"')
1880Sstevel@tonic-gate 							quoted = !quoted;
1890Sstevel@tonic-gate 						else if (*p == ',' && !quoted)
1900Sstevel@tonic-gate 							break;
1910Sstevel@tonic-gate 					}
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 					/* No more alias specs follow */
1940Sstevel@tonic-gate 					if (*p == '\0')
1950Sstevel@tonic-gate 					{
1960Sstevel@tonic-gate 						/* chop trailing whitespace */
1970Sstevel@tonic-gate 						while (isascii(*p) &&
1980Sstevel@tonic-gate 						       isspace(*p) &&
1990Sstevel@tonic-gate 						       p > b)
2000Sstevel@tonic-gate 							p--;
2010Sstevel@tonic-gate 						*p = '\0';
2020Sstevel@tonic-gate 						p = NULL;
2030Sstevel@tonic-gate 					}
2040Sstevel@tonic-gate 				}
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 				if (p != NULL)
2070Sstevel@tonic-gate 				{
2080Sstevel@tonic-gate 					char *e = p - 1;
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 					/* chop trailing whitespace */
2110Sstevel@tonic-gate 					while (isascii(*e) &&
2120Sstevel@tonic-gate 					       isspace(*e) &&
2130Sstevel@tonic-gate 					       e > b)
2140Sstevel@tonic-gate 						e--;
2150Sstevel@tonic-gate 					*++e = '\0';
2160Sstevel@tonic-gate 					*p++ = '\0';
2170Sstevel@tonic-gate 				}
2180Sstevel@tonic-gate 				praliases(b, argc, argv);
2190Sstevel@tonic-gate 			}
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 		  default:
2220Sstevel@tonic-gate 			continue;
2230Sstevel@tonic-gate 		}
2240Sstevel@tonic-gate 	}
2250Sstevel@tonic-gate 	(void) sm_io_close(cfp, SM_TIME_DEFAULT);
2260Sstevel@tonic-gate 	exit(EX_OK);
2270Sstevel@tonic-gate 	/* NOTREACHED */
2280Sstevel@tonic-gate 	return EX_OK;
2290Sstevel@tonic-gate }
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate static void
praliases(filename,argc,argv)2320Sstevel@tonic-gate praliases(filename, argc, argv)
2330Sstevel@tonic-gate 	char *filename;
2340Sstevel@tonic-gate 	int argc;
2350Sstevel@tonic-gate 	char **argv;
2360Sstevel@tonic-gate {
2370Sstevel@tonic-gate 	int result;
2380Sstevel@tonic-gate 	char *colon;
2390Sstevel@tonic-gate 	char *db_name;
2400Sstevel@tonic-gate 	char *db_type;
2410Sstevel@tonic-gate 	SMDB_DATABASE *database = NULL;
2420Sstevel@tonic-gate 	SMDB_CURSOR *cursor = NULL;
2430Sstevel@tonic-gate 	SMDB_DBENT db_key, db_value;
2440Sstevel@tonic-gate 	SMDB_DBPARAMS params;
2450Sstevel@tonic-gate 	SMDB_USER_INFO user_info;
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 	colon = strchr(filename, PATH_SEPARATOR);
2480Sstevel@tonic-gate 	if (colon == NULL)
2490Sstevel@tonic-gate 	{
2500Sstevel@tonic-gate 		db_name = filename;
2510Sstevel@tonic-gate 		db_type = SMDB_TYPE_DEFAULT;
2520Sstevel@tonic-gate 	}
2530Sstevel@tonic-gate 	else
2540Sstevel@tonic-gate 	{
2550Sstevel@tonic-gate 		*colon = '\0';
2560Sstevel@tonic-gate 		db_name = colon + 1;
2570Sstevel@tonic-gate 		db_type = filename;
2580Sstevel@tonic-gate 	}
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 	/* clean off arguments */
2610Sstevel@tonic-gate 	for (;;)
2620Sstevel@tonic-gate 	{
2630Sstevel@tonic-gate 		while (isascii(*db_name) && isspace(*db_name))
2640Sstevel@tonic-gate 			db_name++;
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 		if (*db_name != '-')
2670Sstevel@tonic-gate 			break;
2680Sstevel@tonic-gate 		while (*db_name != '\0' &&
2690Sstevel@tonic-gate 		       !(isascii(*db_name) && isspace(*db_name)))
2700Sstevel@tonic-gate 			db_name++;
2710Sstevel@tonic-gate 	}
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	/* Skip non-file based DB types */
2740Sstevel@tonic-gate 	if (db_type != NULL && *db_type != '\0')
2750Sstevel@tonic-gate 	{
2760Sstevel@tonic-gate 		if (db_type != SMDB_TYPE_DEFAULT &&
2770Sstevel@tonic-gate 		    strcmp(db_type, "hash") != 0 &&
2780Sstevel@tonic-gate 		    strcmp(db_type, "btree") != 0 &&
2790Sstevel@tonic-gate 		    strcmp(db_type, "dbm") != 0)
2800Sstevel@tonic-gate 		{
2810Sstevel@tonic-gate 			sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
2820Sstevel@tonic-gate 				      "praliases: Skipping non-file based alias type %s\n",
2830Sstevel@tonic-gate 				db_type);
2840Sstevel@tonic-gate 			return;
2850Sstevel@tonic-gate 		}
2860Sstevel@tonic-gate 	}
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	if (*db_name == '\0' || (db_type != NULL && *db_type == '\0'))
2890Sstevel@tonic-gate 	{
2900Sstevel@tonic-gate 		if (colon != NULL)
2910Sstevel@tonic-gate 			*colon = ':';
2920Sstevel@tonic-gate 		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
2930Sstevel@tonic-gate 		    "praliases: illegal alias specification: %s\n", filename);
2940Sstevel@tonic-gate 		goto fatal;
2950Sstevel@tonic-gate 	}
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	memset(&params, '\0', sizeof params);
2980Sstevel@tonic-gate 	params.smdbp_cache_size = 1024 * 1024;
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	user_info.smdbu_id = RunAsUid;
3010Sstevel@tonic-gate 	user_info.smdbu_group_id = RunAsGid;
3020Sstevel@tonic-gate 	(void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
3030Sstevel@tonic-gate 			  SMDB_MAX_USER_NAME_LEN);
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	result = smdb_open_database(&database, db_name, O_RDONLY, 0,
3060Sstevel@tonic-gate 				    SFF_ROOTOK, db_type, &user_info, &params);
3070Sstevel@tonic-gate 	if (result != SMDBE_OK)
3080Sstevel@tonic-gate 	{
3090Sstevel@tonic-gate 		sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
3100Sstevel@tonic-gate 			      "praliases: %s: open: %s\n",
3110Sstevel@tonic-gate 			      db_name, sm_errstring(result));
3120Sstevel@tonic-gate 		goto fatal;
3130Sstevel@tonic-gate 	}
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	if (argc == 0)
3160Sstevel@tonic-gate 	{
3170Sstevel@tonic-gate 		memset(&db_key, '\0', sizeof db_key);
3180Sstevel@tonic-gate 		memset(&db_value, '\0', sizeof db_value);
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 		result = database->smdb_cursor(database, &cursor, 0);
3210Sstevel@tonic-gate 		if (result != SMDBE_OK)
3220Sstevel@tonic-gate 		{
3230Sstevel@tonic-gate 			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
3240Sstevel@tonic-gate 			    "praliases: %s: set cursor: %s\n", db_name,
3250Sstevel@tonic-gate 			    sm_errstring(result));
3260Sstevel@tonic-gate 			goto fatal;
3270Sstevel@tonic-gate 		}
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 		while ((result = cursor->smdbc_get(cursor, &db_key, &db_value,
3300Sstevel@tonic-gate 						   SMDB_CURSOR_GET_NEXT)) ==
3310Sstevel@tonic-gate 						   SMDBE_OK)
3320Sstevel@tonic-gate 		{
3330Sstevel@tonic-gate #if 0
3340Sstevel@tonic-gate 			/* skip magic @:@ entry */
3350Sstevel@tonic-gate 			if (db_key.size == 2 &&
3360Sstevel@tonic-gate 			    db_key.data[0] == '@' &&
3370Sstevel@tonic-gate 			    db_key.data[1] == '\0' &&
3380Sstevel@tonic-gate 			    db_value.size == 2 &&
3390Sstevel@tonic-gate 			    db_value.data[0] == '@' &&
3400Sstevel@tonic-gate 			    db_value.data[1] == '\0')
3410Sstevel@tonic-gate 				continue;
3420Sstevel@tonic-gate #endif /* 0 */
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3450Sstevel@tonic-gate 					     "%.*s:%.*s\n",
3460Sstevel@tonic-gate 					     (int) db_key.size,
3470Sstevel@tonic-gate 					     (char *) db_key.data,
3480Sstevel@tonic-gate 					     (int) db_value.size,
3490Sstevel@tonic-gate 					     (char *) db_value.data);
3500Sstevel@tonic-gate 		}
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 		if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY)
3530Sstevel@tonic-gate 		{
3540Sstevel@tonic-gate 			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
3550Sstevel@tonic-gate 				"praliases: %s: get value at cursor: %s\n",
3560Sstevel@tonic-gate 				db_name, sm_errstring(result));
3570Sstevel@tonic-gate 			goto fatal;
3580Sstevel@tonic-gate 		}
3590Sstevel@tonic-gate 	}
3600Sstevel@tonic-gate 	else for (; *argv != NULL; ++argv)
3610Sstevel@tonic-gate 	{
3620Sstevel@tonic-gate 		int get_res;
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 		memset(&db_key, '\0', sizeof db_key);
3650Sstevel@tonic-gate 		memset(&db_value, '\0', sizeof db_value);
3660Sstevel@tonic-gate 		db_key.data = *argv;
3670Sstevel@tonic-gate 		db_key.size = strlen(*argv);
3680Sstevel@tonic-gate 		get_res = database->smdb_get(database, &db_key, &db_value, 0);
3690Sstevel@tonic-gate 		if (get_res == SMDBE_NOT_FOUND)
3700Sstevel@tonic-gate 		{
3710Sstevel@tonic-gate 			db_key.size++;
3720Sstevel@tonic-gate 			get_res = database->smdb_get(database, &db_key,
3730Sstevel@tonic-gate 						     &db_value, 0);
3740Sstevel@tonic-gate 		}
3750Sstevel@tonic-gate 		if (get_res == SMDBE_OK)
3760Sstevel@tonic-gate 		{
3770Sstevel@tonic-gate 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3780Sstevel@tonic-gate 					     "%.*s:%.*s\n",
3790Sstevel@tonic-gate 					     (int) db_key.size,
3800Sstevel@tonic-gate 					     (char *) db_key.data,
3810Sstevel@tonic-gate 					     (int) db_value.size,
3820Sstevel@tonic-gate 					     (char *) db_value.data);
3830Sstevel@tonic-gate 		}
3840Sstevel@tonic-gate 		else
3850Sstevel@tonic-gate 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
3860Sstevel@tonic-gate 					     "%s: No such key\n",
3870Sstevel@tonic-gate 					     (char *)db_key.data);
3880Sstevel@tonic-gate 	}
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate  fatal:
3910Sstevel@tonic-gate 	if (cursor != NULL)
3920Sstevel@tonic-gate 		(void) cursor->smdbc_close(cursor);
3930Sstevel@tonic-gate 	if (database != NULL)
3940Sstevel@tonic-gate 		(void) database->smdb_close(database);
3950Sstevel@tonic-gate 	if (colon != NULL)
3960Sstevel@tonic-gate 		*colon = ':';
3970Sstevel@tonic-gate 	return;
3980Sstevel@tonic-gate }
399