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