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