xref: /onnv-gate/usr/src/cmd/sendmail/aux/praliases.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
3*0Sstevel@tonic-gate  *	All rights reserved.
4*0Sstevel@tonic-gate  * Copyright (c) 1983 Eric P. Allman.  All rights reserved.
5*0Sstevel@tonic-gate  * Copyright (c) 1988, 1993
6*0Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
7*0Sstevel@tonic-gate  *
8*0Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
9*0Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
10*0Sstevel@tonic-gate  * the sendmail distribution.
11*0Sstevel@tonic-gate  *
12*0Sstevel@tonic-gate  */
13*0Sstevel@tonic-gate 
14*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
15*0Sstevel@tonic-gate 
16*0Sstevel@tonic-gate #include <sm/gen.h>
17*0Sstevel@tonic-gate 
18*0Sstevel@tonic-gate SM_IDSTR(copyright,
19*0Sstevel@tonic-gate "@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\
20*0Sstevel@tonic-gate 	All rights reserved.\n\
21*0Sstevel@tonic-gate      Copyright (c) 1983 Eric P. Allman.  All rights reserved.\n\
22*0Sstevel@tonic-gate      Copyright (c) 1988, 1993\n\
23*0Sstevel@tonic-gate 	The Regents of the University of California.  All rights reserved.\n")
24*0Sstevel@tonic-gate 
25*0Sstevel@tonic-gate SM_IDSTR(id, "@(#)$Id: praliases.c,v 8.91 2001/03/29 21:15:53 rodney Exp $")
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #include <sys/types.h>
28*0Sstevel@tonic-gate #include <ctype.h>
29*0Sstevel@tonic-gate #include <stdlib.h>
30*0Sstevel@tonic-gate #include <unistd.h>
31*0Sstevel@tonic-gate #ifdef EX_OK
32*0Sstevel@tonic-gate # undef EX_OK		/* unistd.h may have another use for this */
33*0Sstevel@tonic-gate #endif /* EX_OK */
34*0Sstevel@tonic-gate #include <sysexits.h>
35*0Sstevel@tonic-gate 
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate #ifndef NOT_SENDMAIL
38*0Sstevel@tonic-gate # define NOT_SENDMAIL
39*0Sstevel@tonic-gate #endif /* ! NOT_SENDMAIL */
40*0Sstevel@tonic-gate #include <sendmail/sendmail.h>
41*0Sstevel@tonic-gate #include <sendmail/pathnames.h>
42*0Sstevel@tonic-gate #include <libsmdb/smdb.h>
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate static void praliases __P((char *, int, char **));
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate uid_t	RealUid;
47*0Sstevel@tonic-gate gid_t	RealGid;
48*0Sstevel@tonic-gate char	*RealUserName;
49*0Sstevel@tonic-gate uid_t	RunAsUid;
50*0Sstevel@tonic-gate uid_t	RunAsGid;
51*0Sstevel@tonic-gate char	*RunAsUserName;
52*0Sstevel@tonic-gate int	Verbose = 2;
53*0Sstevel@tonic-gate bool	DontInitGroups = false;
54*0Sstevel@tonic-gate uid_t	TrustedUid = 0;
55*0Sstevel@tonic-gate BITMAP256 DontBlameSendmail;
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate # define DELIMITERS		" ,/"
58*0Sstevel@tonic-gate # define PATH_SEPARATOR		':'
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate int
61*0Sstevel@tonic-gate main(argc, argv)
62*0Sstevel@tonic-gate 	int argc;
63*0Sstevel@tonic-gate 	char **argv;
64*0Sstevel@tonic-gate {
65*0Sstevel@tonic-gate 	char *cfile;
66*0Sstevel@tonic-gate 	char *filename = NULL;
67*0Sstevel@tonic-gate 	SM_FILE_T *cfp;
68*0Sstevel@tonic-gate 	int ch;
69*0Sstevel@tonic-gate 	char afilebuf[MAXLINE];
70*0Sstevel@tonic-gate 	char buf[MAXLINE];
71*0Sstevel@tonic-gate 	struct passwd *pw;
72*0Sstevel@tonic-gate 	static char rnamebuf[MAXNAME];
73*0Sstevel@tonic-gate 	extern char *optarg;
74*0Sstevel@tonic-gate 	extern int optind;
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate 	clrbitmap(DontBlameSendmail);
77*0Sstevel@tonic-gate 	RunAsUid = RealUid = getuid();
78*0Sstevel@tonic-gate 	RunAsGid = RealGid = getgid();
79*0Sstevel@tonic-gate 	pw = getpwuid(RealUid);
80*0Sstevel@tonic-gate 	if (pw != NULL)
81*0Sstevel@tonic-gate 	{
82*0Sstevel@tonic-gate 		if (strlen(pw->pw_name) > MAXNAME - 1)
83*0Sstevel@tonic-gate 			pw->pw_name[MAXNAME] = 0;
84*0Sstevel@tonic-gate 		sm_snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);
85*0Sstevel@tonic-gate 	}
86*0Sstevel@tonic-gate 	else
87*0Sstevel@tonic-gate 		(void) sm_snprintf(rnamebuf, sizeof rnamebuf,
88*0Sstevel@tonic-gate 		    "Unknown UID %d", (int) RealUid);
89*0Sstevel@tonic-gate 	RunAsUserName = RealUserName = rnamebuf;
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate 	cfile = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL);
92*0Sstevel@tonic-gate 	while ((ch = getopt(argc, argv, "C:f:")) != -1)
93*0Sstevel@tonic-gate 	{
94*0Sstevel@tonic-gate 		switch ((char)ch) {
95*0Sstevel@tonic-gate 		case 'C':
96*0Sstevel@tonic-gate 			cfile = optarg;
97*0Sstevel@tonic-gate 			break;
98*0Sstevel@tonic-gate 		case 'f':
99*0Sstevel@tonic-gate 			filename = optarg;
100*0Sstevel@tonic-gate 			break;
101*0Sstevel@tonic-gate 		case '?':
102*0Sstevel@tonic-gate 		default:
103*0Sstevel@tonic-gate 			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
104*0Sstevel@tonic-gate 			    "usage: praliases [-C cffile] [-f aliasfile]\n");
105*0Sstevel@tonic-gate 			exit(EX_USAGE);
106*0Sstevel@tonic-gate 		}
107*0Sstevel@tonic-gate 	}
108*0Sstevel@tonic-gate 	argc -= optind;
109*0Sstevel@tonic-gate 	argv += optind;
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 	if (filename != NULL)
112*0Sstevel@tonic-gate 	{
113*0Sstevel@tonic-gate 		praliases(filename, argc, argv);
114*0Sstevel@tonic-gate 		exit(EX_OK);
115*0Sstevel@tonic-gate 	}
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate 	if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY,
118*0Sstevel@tonic-gate 			      NULL)) == NULL)
119*0Sstevel@tonic-gate 	{
120*0Sstevel@tonic-gate 		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
121*0Sstevel@tonic-gate 				     "praliases: %s: %s\n", cfile,
122*0Sstevel@tonic-gate 				     sm_errstring(errno));
123*0Sstevel@tonic-gate 		exit(EX_NOINPUT);
124*0Sstevel@tonic-gate 	}
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate 	while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL)
127*0Sstevel@tonic-gate 	{
128*0Sstevel@tonic-gate 		register char *b, *p;
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate 		b = strchr(buf, '\n');
131*0Sstevel@tonic-gate 		if (b != NULL)
132*0Sstevel@tonic-gate 			*b = '\0';
133*0Sstevel@tonic-gate 
134*0Sstevel@tonic-gate 		b = buf;
135*0Sstevel@tonic-gate 		switch (*b++)
136*0Sstevel@tonic-gate 		{
137*0Sstevel@tonic-gate 		  case 'O':		/* option -- see if alias file */
138*0Sstevel@tonic-gate 			if (sm_strncasecmp(b, " AliasFile", 10) == 0 &&
139*0Sstevel@tonic-gate 			    !(isascii(b[10]) && isalnum(b[10])))
140*0Sstevel@tonic-gate 			{
141*0Sstevel@tonic-gate 				/* new form -- find value */
142*0Sstevel@tonic-gate 				b = strchr(b, '=');
143*0Sstevel@tonic-gate 				if (b == NULL)
144*0Sstevel@tonic-gate 					continue;
145*0Sstevel@tonic-gate 				while (isascii(*++b) && isspace(*b))
146*0Sstevel@tonic-gate 					continue;
147*0Sstevel@tonic-gate 			}
148*0Sstevel@tonic-gate 			else if (*b++ != 'A')
149*0Sstevel@tonic-gate 			{
150*0Sstevel@tonic-gate 				/* something else boring */
151*0Sstevel@tonic-gate 				continue;
152*0Sstevel@tonic-gate 			}
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate 			/* this is the A or AliasFile option -- save it */
155*0Sstevel@tonic-gate 			if (sm_strlcpy(afilebuf, b, sizeof afilebuf) >=
156*0Sstevel@tonic-gate 			    sizeof afilebuf)
157*0Sstevel@tonic-gate 			{
158*0Sstevel@tonic-gate 				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
159*0Sstevel@tonic-gate 				    "praliases: AliasFile filename too long: %.30s\n",
160*0Sstevel@tonic-gate 					b);
161*0Sstevel@tonic-gate 				(void) sm_io_close(cfp, SM_TIME_DEFAULT);
162*0Sstevel@tonic-gate 				exit(EX_CONFIG);
163*0Sstevel@tonic-gate 			}
164*0Sstevel@tonic-gate 			b = afilebuf;
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate 			for (p = b; p != NULL; )
167*0Sstevel@tonic-gate 			{
168*0Sstevel@tonic-gate 				while (isascii(*p) && isspace(*p))
169*0Sstevel@tonic-gate 					p++;
170*0Sstevel@tonic-gate 				if (*p == '\0')
171*0Sstevel@tonic-gate 					break;
172*0Sstevel@tonic-gate 				b = p;
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate 				p = strpbrk(p, DELIMITERS);
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate 				/* find end of spec */
177*0Sstevel@tonic-gate 				if (p != NULL)
178*0Sstevel@tonic-gate 				{
179*0Sstevel@tonic-gate 					bool quoted = false;
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 					for (; *p != '\0'; p++)
182*0Sstevel@tonic-gate 					{
183*0Sstevel@tonic-gate 						/*
184*0Sstevel@tonic-gate 						**  Don't break into a quoted
185*0Sstevel@tonic-gate 						**  string.
186*0Sstevel@tonic-gate 						*/
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate 						if (*p == '"')
189*0Sstevel@tonic-gate 							quoted = !quoted;
190*0Sstevel@tonic-gate 						else if (*p == ',' && !quoted)
191*0Sstevel@tonic-gate 							break;
192*0Sstevel@tonic-gate 					}
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate 					/* No more alias specs follow */
195*0Sstevel@tonic-gate 					if (*p == '\0')
196*0Sstevel@tonic-gate 					{
197*0Sstevel@tonic-gate 						/* chop trailing whitespace */
198*0Sstevel@tonic-gate 						while (isascii(*p) &&
199*0Sstevel@tonic-gate 						       isspace(*p) &&
200*0Sstevel@tonic-gate 						       p > b)
201*0Sstevel@tonic-gate 							p--;
202*0Sstevel@tonic-gate 						*p = '\0';
203*0Sstevel@tonic-gate 						p = NULL;
204*0Sstevel@tonic-gate 					}
205*0Sstevel@tonic-gate 				}
206*0Sstevel@tonic-gate 
207*0Sstevel@tonic-gate 				if (p != NULL)
208*0Sstevel@tonic-gate 				{
209*0Sstevel@tonic-gate 					char *e = p - 1;
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 					/* chop trailing whitespace */
212*0Sstevel@tonic-gate 					while (isascii(*e) &&
213*0Sstevel@tonic-gate 					       isspace(*e) &&
214*0Sstevel@tonic-gate 					       e > b)
215*0Sstevel@tonic-gate 						e--;
216*0Sstevel@tonic-gate 					*++e = '\0';
217*0Sstevel@tonic-gate 					*p++ = '\0';
218*0Sstevel@tonic-gate 				}
219*0Sstevel@tonic-gate 				praliases(b, argc, argv);
220*0Sstevel@tonic-gate 			}
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate 		  default:
223*0Sstevel@tonic-gate 			continue;
224*0Sstevel@tonic-gate 		}
225*0Sstevel@tonic-gate 	}
226*0Sstevel@tonic-gate 	(void) sm_io_close(cfp, SM_TIME_DEFAULT);
227*0Sstevel@tonic-gate 	exit(EX_OK);
228*0Sstevel@tonic-gate 	/* NOTREACHED */
229*0Sstevel@tonic-gate 	return EX_OK;
230*0Sstevel@tonic-gate }
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate static void
233*0Sstevel@tonic-gate praliases(filename, argc, argv)
234*0Sstevel@tonic-gate 	char *filename;
235*0Sstevel@tonic-gate 	int argc;
236*0Sstevel@tonic-gate 	char **argv;
237*0Sstevel@tonic-gate {
238*0Sstevel@tonic-gate 	int result;
239*0Sstevel@tonic-gate 	char *colon;
240*0Sstevel@tonic-gate 	char *db_name;
241*0Sstevel@tonic-gate 	char *db_type;
242*0Sstevel@tonic-gate 	SMDB_DATABASE *database = NULL;
243*0Sstevel@tonic-gate 	SMDB_CURSOR *cursor = NULL;
244*0Sstevel@tonic-gate 	SMDB_DBENT db_key, db_value;
245*0Sstevel@tonic-gate 	SMDB_DBPARAMS params;
246*0Sstevel@tonic-gate 	SMDB_USER_INFO user_info;
247*0Sstevel@tonic-gate 
248*0Sstevel@tonic-gate 	colon = strchr(filename, PATH_SEPARATOR);
249*0Sstevel@tonic-gate 	if (colon == NULL)
250*0Sstevel@tonic-gate 	{
251*0Sstevel@tonic-gate 		db_name = filename;
252*0Sstevel@tonic-gate 		db_type = SMDB_TYPE_DEFAULT;
253*0Sstevel@tonic-gate 	}
254*0Sstevel@tonic-gate 	else
255*0Sstevel@tonic-gate 	{
256*0Sstevel@tonic-gate 		*colon = '\0';
257*0Sstevel@tonic-gate 		db_name = colon + 1;
258*0Sstevel@tonic-gate 		db_type = filename;
259*0Sstevel@tonic-gate 	}
260*0Sstevel@tonic-gate 
261*0Sstevel@tonic-gate 	/* clean off arguments */
262*0Sstevel@tonic-gate 	for (;;)
263*0Sstevel@tonic-gate 	{
264*0Sstevel@tonic-gate 		while (isascii(*db_name) && isspace(*db_name))
265*0Sstevel@tonic-gate 			db_name++;
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate 		if (*db_name != '-')
268*0Sstevel@tonic-gate 			break;
269*0Sstevel@tonic-gate 		while (*db_name != '\0' &&
270*0Sstevel@tonic-gate 		       !(isascii(*db_name) && isspace(*db_name)))
271*0Sstevel@tonic-gate 			db_name++;
272*0Sstevel@tonic-gate 	}
273*0Sstevel@tonic-gate 
274*0Sstevel@tonic-gate 	/* Skip non-file based DB types */
275*0Sstevel@tonic-gate 	if (db_type != NULL && *db_type != '\0')
276*0Sstevel@tonic-gate 	{
277*0Sstevel@tonic-gate 		if (db_type != SMDB_TYPE_DEFAULT &&
278*0Sstevel@tonic-gate 		    strcmp(db_type, "hash") != 0 &&
279*0Sstevel@tonic-gate 		    strcmp(db_type, "btree") != 0 &&
280*0Sstevel@tonic-gate 		    strcmp(db_type, "dbm") != 0)
281*0Sstevel@tonic-gate 		{
282*0Sstevel@tonic-gate 			sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
283*0Sstevel@tonic-gate 				      "praliases: Skipping non-file based alias type %s\n",
284*0Sstevel@tonic-gate 				db_type);
285*0Sstevel@tonic-gate 			return;
286*0Sstevel@tonic-gate 		}
287*0Sstevel@tonic-gate 	}
288*0Sstevel@tonic-gate 
289*0Sstevel@tonic-gate 	if (*db_name == '\0' || (db_type != NULL && *db_type == '\0'))
290*0Sstevel@tonic-gate 	{
291*0Sstevel@tonic-gate 		if (colon != NULL)
292*0Sstevel@tonic-gate 			*colon = ':';
293*0Sstevel@tonic-gate 		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
294*0Sstevel@tonic-gate 		    "praliases: illegal alias specification: %s\n", filename);
295*0Sstevel@tonic-gate 		goto fatal;
296*0Sstevel@tonic-gate 	}
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 	memset(&params, '\0', sizeof params);
299*0Sstevel@tonic-gate 	params.smdbp_cache_size = 1024 * 1024;
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate 	user_info.smdbu_id = RunAsUid;
302*0Sstevel@tonic-gate 	user_info.smdbu_group_id = RunAsGid;
303*0Sstevel@tonic-gate 	(void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
304*0Sstevel@tonic-gate 			  SMDB_MAX_USER_NAME_LEN);
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate 	result = smdb_open_database(&database, db_name, O_RDONLY, 0,
307*0Sstevel@tonic-gate 				    SFF_ROOTOK, db_type, &user_info, &params);
308*0Sstevel@tonic-gate 	if (result != SMDBE_OK)
309*0Sstevel@tonic-gate 	{
310*0Sstevel@tonic-gate 		sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
311*0Sstevel@tonic-gate 			      "praliases: %s: open: %s\n",
312*0Sstevel@tonic-gate 			      db_name, sm_errstring(result));
313*0Sstevel@tonic-gate 		goto fatal;
314*0Sstevel@tonic-gate 	}
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 	if (argc == 0)
317*0Sstevel@tonic-gate 	{
318*0Sstevel@tonic-gate 		memset(&db_key, '\0', sizeof db_key);
319*0Sstevel@tonic-gate 		memset(&db_value, '\0', sizeof db_value);
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate 		result = database->smdb_cursor(database, &cursor, 0);
322*0Sstevel@tonic-gate 		if (result != SMDBE_OK)
323*0Sstevel@tonic-gate 		{
324*0Sstevel@tonic-gate 			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
325*0Sstevel@tonic-gate 			    "praliases: %s: set cursor: %s\n", db_name,
326*0Sstevel@tonic-gate 			    sm_errstring(result));
327*0Sstevel@tonic-gate 			goto fatal;
328*0Sstevel@tonic-gate 		}
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate 		while ((result = cursor->smdbc_get(cursor, &db_key, &db_value,
331*0Sstevel@tonic-gate 						   SMDB_CURSOR_GET_NEXT)) ==
332*0Sstevel@tonic-gate 						   SMDBE_OK)
333*0Sstevel@tonic-gate 		{
334*0Sstevel@tonic-gate #if 0
335*0Sstevel@tonic-gate 			/* skip magic @:@ entry */
336*0Sstevel@tonic-gate 			if (db_key.size == 2 &&
337*0Sstevel@tonic-gate 			    db_key.data[0] == '@' &&
338*0Sstevel@tonic-gate 			    db_key.data[1] == '\0' &&
339*0Sstevel@tonic-gate 			    db_value.size == 2 &&
340*0Sstevel@tonic-gate 			    db_value.data[0] == '@' &&
341*0Sstevel@tonic-gate 			    db_value.data[1] == '\0')
342*0Sstevel@tonic-gate 				continue;
343*0Sstevel@tonic-gate #endif /* 0 */
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
346*0Sstevel@tonic-gate 					     "%.*s:%.*s\n",
347*0Sstevel@tonic-gate 					     (int) db_key.size,
348*0Sstevel@tonic-gate 					     (char *) db_key.data,
349*0Sstevel@tonic-gate 					     (int) db_value.size,
350*0Sstevel@tonic-gate 					     (char *) db_value.data);
351*0Sstevel@tonic-gate 		}
352*0Sstevel@tonic-gate 
353*0Sstevel@tonic-gate 		if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY)
354*0Sstevel@tonic-gate 		{
355*0Sstevel@tonic-gate 			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
356*0Sstevel@tonic-gate 				"praliases: %s: get value at cursor: %s\n",
357*0Sstevel@tonic-gate 				db_name, sm_errstring(result));
358*0Sstevel@tonic-gate 			goto fatal;
359*0Sstevel@tonic-gate 		}
360*0Sstevel@tonic-gate 	}
361*0Sstevel@tonic-gate 	else for (; *argv != NULL; ++argv)
362*0Sstevel@tonic-gate 	{
363*0Sstevel@tonic-gate 		int get_res;
364*0Sstevel@tonic-gate 
365*0Sstevel@tonic-gate 		memset(&db_key, '\0', sizeof db_key);
366*0Sstevel@tonic-gate 		memset(&db_value, '\0', sizeof db_value);
367*0Sstevel@tonic-gate 		db_key.data = *argv;
368*0Sstevel@tonic-gate 		db_key.size = strlen(*argv);
369*0Sstevel@tonic-gate 		get_res = database->smdb_get(database, &db_key, &db_value, 0);
370*0Sstevel@tonic-gate 		if (get_res == SMDBE_NOT_FOUND)
371*0Sstevel@tonic-gate 		{
372*0Sstevel@tonic-gate 			db_key.size++;
373*0Sstevel@tonic-gate 			get_res = database->smdb_get(database, &db_key,
374*0Sstevel@tonic-gate 						     &db_value, 0);
375*0Sstevel@tonic-gate 		}
376*0Sstevel@tonic-gate 		if (get_res == SMDBE_OK)
377*0Sstevel@tonic-gate 		{
378*0Sstevel@tonic-gate 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
379*0Sstevel@tonic-gate 					     "%.*s:%.*s\n",
380*0Sstevel@tonic-gate 					     (int) db_key.size,
381*0Sstevel@tonic-gate 					     (char *) db_key.data,
382*0Sstevel@tonic-gate 					     (int) db_value.size,
383*0Sstevel@tonic-gate 					     (char *) db_value.data);
384*0Sstevel@tonic-gate 		}
385*0Sstevel@tonic-gate 		else
386*0Sstevel@tonic-gate 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
387*0Sstevel@tonic-gate 					     "%s: No such key\n",
388*0Sstevel@tonic-gate 					     (char *)db_key.data);
389*0Sstevel@tonic-gate 	}
390*0Sstevel@tonic-gate 
391*0Sstevel@tonic-gate  fatal:
392*0Sstevel@tonic-gate 	if (cursor != NULL)
393*0Sstevel@tonic-gate 		(void) cursor->smdbc_close(cursor);
394*0Sstevel@tonic-gate 	if (database != NULL)
395*0Sstevel@tonic-gate 		(void) database->smdb_close(database);
396*0Sstevel@tonic-gate 	if (colon != NULL)
397*0Sstevel@tonic-gate 		*colon = ':';
398*0Sstevel@tonic-gate 	return;
399*0Sstevel@tonic-gate }
400