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(¶ms, '\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, ¶ms); 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