138032Speter/*
2261363Sgshapiro * Copyright (c) 1998-2001, 2008 Proofpoint, Inc. and its suppliers.
364565Sgshapiro *	All rights reserved.
438032Speter * Copyright (c) 1983 Eric P. Allman.  All rights reserved.
538032Speter * Copyright (c) 1988, 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,
17261363Sgshapiro"@(#) Copyright (c) 1998-2001 Proofpoint, Inc. and its suppliers.\n\
1864565Sgshapiro	All rights reserved.\n\
1964565Sgshapiro     Copyright (c) 1983 Eric P. Allman.  All rights reserved.\n\
2064565Sgshapiro     Copyright (c) 1988, 1993\n\
2190795Sgshapiro	The Regents of the University of California.  All rights reserved.\n")
2238032Speter
23266692SgshapiroSM_IDSTR(id, "@(#)$Id: praliases.c,v 8.98 2013-11-22 20:51:53 ca Exp $")
2438032Speter
2564565Sgshapiro#include <sys/types.h>
2664565Sgshapiro#include <ctype.h>
2764565Sgshapiro#include <stdlib.h>
2864565Sgshapiro#include <unistd.h>
2964565Sgshapiro#ifdef EX_OK
3064565Sgshapiro# undef EX_OK		/* unistd.h may have another use for this */
3164565Sgshapiro#endif /* EX_OK */
3264565Sgshapiro#include <sysexits.h>
3364565Sgshapiro
3464565Sgshapiro
3538032Speter#ifndef NOT_SENDMAIL
3638032Speter# define NOT_SENDMAIL
3764565Sgshapiro#endif /* ! NOT_SENDMAIL */
3864565Sgshapiro#include <sendmail/sendmail.h>
3964565Sgshapiro#include <sendmail/pathnames.h>
4064565Sgshapiro#include <libsmdb/smdb.h>
4138032Speter
4264565Sgshapirostatic void praliases __P((char *, int, char **));
4338032Speter
4464565Sgshapirouid_t	RealUid;
4564565Sgshapirogid_t	RealGid;
4664565Sgshapirochar	*RealUserName;
4764565Sgshapirouid_t	RunAsUid;
48173343Sgshapirogid_t	RunAsGid;
4964565Sgshapirochar	*RunAsUserName;
5064565Sgshapiroint	Verbose = 2;
5190795Sgshapirobool	DontInitGroups = false;
5264565Sgshapirouid_t	TrustedUid = 0;
5364565SgshapiroBITMAP256 DontBlameSendmail;
5438032Speter
5571348Sgshapiro# define DELIMITERS		" ,/"
5671348Sgshapiro# define PATH_SEPARATOR		':'
5764565Sgshapiro
5838032Speterint
5938032Spetermain(argc, argv)
6038032Speter	int argc;
6138032Speter	char **argv;
6238032Speter{
6342580Speter	char *cfile;
6442580Speter	char *filename = NULL;
6590795Sgshapiro	SM_FILE_T *cfp;
6638032Speter	int ch;
6742580Speter	char afilebuf[MAXLINE];
6842580Speter	char buf[MAXLINE];
6964565Sgshapiro	struct passwd *pw;
7064565Sgshapiro	static char rnamebuf[MAXNAME];
7164565Sgshapiro	extern char *optarg;
7264565Sgshapiro	extern int optind;
7338032Speter
7464565Sgshapiro	clrbitmap(DontBlameSendmail);
7564565Sgshapiro	RunAsUid = RealUid = getuid();
7664565Sgshapiro	RunAsGid = RealGid = getgid();
7764565Sgshapiro	pw = getpwuid(RealUid);
7864565Sgshapiro	if (pw != NULL)
7964565Sgshapiro	{
8064565Sgshapiro		if (strlen(pw->pw_name) > MAXNAME - 1)
8164565Sgshapiro			pw->pw_name[MAXNAME] = 0;
8290795Sgshapiro		sm_snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);
8364565Sgshapiro	}
8464565Sgshapiro	else
8590795Sgshapiro		(void) sm_snprintf(rnamebuf, sizeof rnamebuf,
8690795Sgshapiro		    "Unknown UID %d", (int) RealUid);
8764565Sgshapiro	RunAsUserName = RealUserName = rnamebuf;
8864565Sgshapiro
8990795Sgshapiro	cfile = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL);
9042580Speter	while ((ch = getopt(argc, argv, "C:f:")) != -1)
9142580Speter	{
9242580Speter		switch ((char)ch) {
9342580Speter		case 'C':
9442580Speter			cfile = optarg;
9542580Speter			break;
9638032Speter		case 'f':
9738032Speter			filename = optarg;
9838032Speter			break;
9938032Speter		case '?':
10038032Speter		default:
10190795Sgshapiro			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
102203004Sgshapiro			    "usage: praliases [-C cffile] [-f aliasfile]"
103203004Sgshapiro			    " [key ...]\n");
10438032Speter			exit(EX_USAGE);
10538032Speter		}
10642580Speter	}
10738032Speter	argc -= optind;
10838032Speter	argv += optind;
10938032Speter
11042580Speter	if (filename != NULL)
11142580Speter	{
11242580Speter		praliases(filename, argc, argv);
11342580Speter		exit(EX_OK);
11442580Speter	}
11542580Speter
11690795Sgshapiro	if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY,
11790795Sgshapiro			      NULL)) == NULL)
11842580Speter	{
11990795Sgshapiro		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
12090795Sgshapiro				     "praliases: %s: %s\n", cfile,
12190795Sgshapiro				     sm_errstring(errno));
12242580Speter		exit(EX_NOINPUT);
12342580Speter	}
12442580Speter
125249729Sgshapiro	while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0)
12642580Speter	{
12742580Speter		register char *b, *p;
12842580Speter
12964565Sgshapiro		b = strchr(buf, '\n');
13064565Sgshapiro		if (b != NULL)
13164565Sgshapiro			*b = '\0';
13264565Sgshapiro
13342580Speter		b = buf;
13442580Speter		switch (*b++)
13542580Speter		{
13642580Speter		  case 'O':		/* option -- see if alias file */
13790795Sgshapiro			if (sm_strncasecmp(b, " AliasFile", 10) == 0 &&
13842580Speter			    !(isascii(b[10]) && isalnum(b[10])))
13942580Speter			{
14042580Speter				/* new form -- find value */
14142580Speter				b = strchr(b, '=');
14242580Speter				if (b == NULL)
14342580Speter					continue;
14442580Speter				while (isascii(*++b) && isspace(*b))
14542580Speter					continue;
14642580Speter			}
14742580Speter			else if (*b++ != 'A')
14842580Speter			{
14942580Speter				/* something else boring */
15042580Speter				continue;
15142580Speter			}
15242580Speter
15342580Speter			/* this is the A or AliasFile option -- save it */
15490795Sgshapiro			if (sm_strlcpy(afilebuf, b, sizeof afilebuf) >=
15564565Sgshapiro			    sizeof afilebuf)
15642580Speter			{
15790795Sgshapiro				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
15890795Sgshapiro				    "praliases: AliasFile filename too long: %.30s\n",
15942580Speter					b);
16090795Sgshapiro				(void) sm_io_close(cfp, SM_TIME_DEFAULT);
16142580Speter				exit(EX_CONFIG);
16242580Speter			}
16342580Speter			b = afilebuf;
16442580Speter
16542580Speter			for (p = b; p != NULL; )
16642580Speter			{
16742580Speter				while (isascii(*p) && isspace(*p))
16842580Speter					p++;
16942580Speter				if (*p == '\0')
17042580Speter					break;
17142580Speter				b = p;
17242580Speter
17371348Sgshapiro				p = strpbrk(p, DELIMITERS);
17464565Sgshapiro
17542580Speter				/* find end of spec */
17642580Speter				if (p != NULL)
17764565Sgshapiro				{
17890795Sgshapiro					bool quoted = false;
17964565Sgshapiro
18064565Sgshapiro					for (; *p != '\0'; p++)
18164565Sgshapiro					{
18264565Sgshapiro						/*
18364565Sgshapiro						**  Don't break into a quoted
18464565Sgshapiro						**  string.
18564565Sgshapiro						*/
18664565Sgshapiro
18764565Sgshapiro						if (*p == '"')
18864565Sgshapiro							quoted = !quoted;
18964565Sgshapiro						else if (*p == ',' && !quoted)
19064565Sgshapiro							break;
19164565Sgshapiro					}
19264565Sgshapiro
19364565Sgshapiro					/* No more alias specs follow */
19464565Sgshapiro					if (*p == '\0')
19564565Sgshapiro					{
19664565Sgshapiro						/* chop trailing whitespace */
19764565Sgshapiro						while (isascii(*p) &&
19864565Sgshapiro						       isspace(*p) &&
19964565Sgshapiro						       p > b)
20064565Sgshapiro							p--;
20164565Sgshapiro						*p = '\0';
20264565Sgshapiro						p = NULL;
20364565Sgshapiro					}
20464565Sgshapiro				}
20564565Sgshapiro
20642580Speter				if (p != NULL)
20764565Sgshapiro				{
20864565Sgshapiro					char *e = p - 1;
20964565Sgshapiro
21064565Sgshapiro					/* chop trailing whitespace */
21164565Sgshapiro					while (isascii(*e) &&
21264565Sgshapiro					       isspace(*e) &&
21364565Sgshapiro					       e > b)
21464565Sgshapiro						e--;
21564565Sgshapiro					*++e = '\0';
21642580Speter					*p++ = '\0';
21764565Sgshapiro				}
21842580Speter				praliases(b, argc, argv);
21942580Speter			}
22042580Speter
22142580Speter		  default:
22242580Speter			continue;
22342580Speter		}
22442580Speter	}
22590795Sgshapiro	(void) sm_io_close(cfp, SM_TIME_DEFAULT);
22642580Speter	exit(EX_OK);
22764565Sgshapiro	/* NOTREACHED */
22864565Sgshapiro	return EX_OK;
22942580Speter}
23042580Speter
23142580Speterstatic void
23242580Speterpraliases(filename, argc, argv)
23342580Speter	char *filename;
23464565Sgshapiro	int argc;
23542580Speter	char **argv;
23642580Speter{
23764565Sgshapiro	int result;
23864565Sgshapiro	char *colon;
23964565Sgshapiro	char *db_name;
24064565Sgshapiro	char *db_type;
24164565Sgshapiro	SMDB_DATABASE *database = NULL;
24264565Sgshapiro	SMDB_CURSOR *cursor = NULL;
24364565Sgshapiro	SMDB_DBENT db_key, db_value;
24464565Sgshapiro	SMDB_DBPARAMS params;
24564565Sgshapiro	SMDB_USER_INFO user_info;
24642580Speter
24771348Sgshapiro	colon = strchr(filename, PATH_SEPARATOR);
24864565Sgshapiro	if (colon == NULL)
24942580Speter	{
25064565Sgshapiro		db_name = filename;
25164565Sgshapiro		db_type = SMDB_TYPE_DEFAULT;
25242580Speter	}
25364565Sgshapiro	else
25438032Speter	{
25564565Sgshapiro		*colon = '\0';
25664565Sgshapiro		db_name = colon + 1;
25764565Sgshapiro		db_type = filename;
25838032Speter	}
25964565Sgshapiro
26064565Sgshapiro	/* clean off arguments */
26164565Sgshapiro	for (;;)
26238032Speter	{
26364565Sgshapiro		while (isascii(*db_name) && isspace(*db_name))
26464565Sgshapiro			db_name++;
26571348Sgshapiro
26664565Sgshapiro		if (*db_name != '-')
26764565Sgshapiro			break;
26864565Sgshapiro		while (*db_name != '\0' &&
26964565Sgshapiro		       !(isascii(*db_name) && isspace(*db_name)))
27064565Sgshapiro			db_name++;
27164565Sgshapiro	}
27238032Speter
27373191Sgshapiro	/* Skip non-file based DB types */
27473191Sgshapiro	if (db_type != NULL && *db_type != '\0')
27573191Sgshapiro	{
27673191Sgshapiro		if (db_type != SMDB_TYPE_DEFAULT &&
27773191Sgshapiro		    strcmp(db_type, "hash") != 0 &&
27873191Sgshapiro		    strcmp(db_type, "btree") != 0 &&
27973191Sgshapiro		    strcmp(db_type, "dbm") != 0)
28073191Sgshapiro		{
28190795Sgshapiro			sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
28290795Sgshapiro				      "praliases: Skipping non-file based alias type %s\n",
28373191Sgshapiro				db_type);
28473191Sgshapiro			return;
28573191Sgshapiro		}
28673191Sgshapiro	}
28773191Sgshapiro
28864565Sgshapiro	if (*db_name == '\0' || (db_type != NULL && *db_type == '\0'))
28942580Speter	{
29064565Sgshapiro		if (colon != NULL)
29164565Sgshapiro			*colon = ':';
29290795Sgshapiro		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
29390795Sgshapiro		    "praliases: illegal alias specification: %s\n", filename);
29464565Sgshapiro		goto fatal;
29542580Speter	}
29642580Speter
29764565Sgshapiro	memset(&params, '\0', sizeof params);
29864565Sgshapiro	params.smdbp_cache_size = 1024 * 1024;
29942580Speter
30064565Sgshapiro	user_info.smdbu_id = RunAsUid;
30164565Sgshapiro	user_info.smdbu_group_id = RunAsGid;
30290795Sgshapiro	(void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
30390795Sgshapiro			  SMDB_MAX_USER_NAME_LEN);
30464565Sgshapiro
30564565Sgshapiro	result = smdb_open_database(&database, db_name, O_RDONLY, 0,
30664565Sgshapiro				    SFF_ROOTOK, db_type, &user_info, &params);
30764565Sgshapiro	if (result != SMDBE_OK)
30842580Speter	{
30990795Sgshapiro		sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
31090795Sgshapiro			      "praliases: %s: open: %s\n",
31190795Sgshapiro			      db_name, sm_errstring(result));
31264565Sgshapiro		goto fatal;
31342580Speter	}
31464565Sgshapiro
31564565Sgshapiro	if (argc == 0)
31642580Speter	{
31764565Sgshapiro		memset(&db_key, '\0', sizeof db_key);
31864565Sgshapiro		memset(&db_value, '\0', sizeof db_value);
31964565Sgshapiro
32064565Sgshapiro		result = database->smdb_cursor(database, &cursor, 0);
32164565Sgshapiro		if (result != SMDBE_OK)
32242580Speter		{
32390795Sgshapiro			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
32490795Sgshapiro			    "praliases: %s: set cursor: %s\n", db_name,
32590795Sgshapiro			    sm_errstring(result));
32664565Sgshapiro			goto fatal;
32738032Speter		}
32864565Sgshapiro
32964565Sgshapiro		while ((result = cursor->smdbc_get(cursor, &db_key, &db_value,
33064565Sgshapiro						   SMDB_CURSOR_GET_NEXT)) ==
33164565Sgshapiro						   SMDBE_OK)
33264565Sgshapiro		{
33364565Sgshapiro#if 0
33464565Sgshapiro			/* skip magic @:@ entry */
33571348Sgshapiro			if (db_key.size == 2 &&
33671348Sgshapiro			    db_key.data[0] == '@' &&
33771348Sgshapiro			    db_key.data[1] == '\0' &&
33871348Sgshapiro			    db_value.size == 2 &&
33971348Sgshapiro			    db_value.data[0] == '@' &&
34071348Sgshapiro			    db_value.data[1] == '\0')
34164565Sgshapiro				continue;
34264565Sgshapiro#endif /* 0 */
34364565Sgshapiro
34490795Sgshapiro			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
34590795Sgshapiro					     "%.*s:%.*s\n",
34690795Sgshapiro					     (int) db_key.size,
34790795Sgshapiro					     (char *) db_key.data,
34890795Sgshapiro					     (int) db_value.size,
34990795Sgshapiro					     (char *) db_value.data);
35064565Sgshapiro		}
35164565Sgshapiro
35264565Sgshapiro		if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY)
35364565Sgshapiro		{
35490795Sgshapiro			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
35564565Sgshapiro				"praliases: %s: get value at cursor: %s\n",
35690795Sgshapiro				db_name, sm_errstring(result));
35764565Sgshapiro			goto fatal;
35864565Sgshapiro		}
35942580Speter	}
36064565Sgshapiro	else for (; *argv != NULL; ++argv)
36142580Speter	{
36277352Sgshapiro		int get_res;
36377352Sgshapiro
36464565Sgshapiro		memset(&db_key, '\0', sizeof db_key);
36564565Sgshapiro		memset(&db_value, '\0', sizeof db_value);
36671348Sgshapiro		db_key.data = *argv;
36777352Sgshapiro		db_key.size = strlen(*argv);
36877352Sgshapiro		get_res = database->smdb_get(database, &db_key, &db_value, 0);
36977352Sgshapiro		if (get_res == SMDBE_NOT_FOUND)
37042580Speter		{
37177352Sgshapiro			db_key.size++;
37277352Sgshapiro			get_res = database->smdb_get(database, &db_key,
37377352Sgshapiro						     &db_value, 0);
37477352Sgshapiro		}
37577352Sgshapiro		if (get_res == SMDBE_OK)
37677352Sgshapiro		{
37790795Sgshapiro			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
37890795Sgshapiro					     "%.*s:%.*s\n",
37990795Sgshapiro					     (int) db_key.size,
38090795Sgshapiro					     (char *) db_key.data,
38190795Sgshapiro					     (int) db_value.size,
38290795Sgshapiro					     (char *) db_value.data);
38338032Speter		}
38464565Sgshapiro		else
38590795Sgshapiro			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
38690795Sgshapiro					     "%s: No such key\n",
38790795Sgshapiro					     (char *)db_key.data);
38838032Speter	}
38964565Sgshapiro
39064565Sgshapiro fatal:
39164565Sgshapiro	if (cursor != NULL)
39264565Sgshapiro		(void) cursor->smdbc_close(cursor);
39364565Sgshapiro	if (database != NULL)
39464565Sgshapiro		(void) database->smdb_close(database);
39564565Sgshapiro	if (colon != NULL)
39664565Sgshapiro		*colon = ':';
39764565Sgshapiro	return;
39842580Speter}
399