praliases.c revision 261363
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 /* EX_OK */
32#include <sysexits.h>
33
34
35#ifndef NOT_SENDMAIL
36# define NOT_SENDMAIL
37#endif /* ! NOT_SENDMAIL */
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		    strcmp(db_type, "hash") != 0 &&
278		    strcmp(db_type, "btree") != 0 &&
279		    strcmp(db_type, "dbm") != 0)
280		{
281			sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
282				      "praliases: Skipping non-file based alias type %s\n",
283				db_type);
284			return;
285		}
286	}
287
288	if (*db_name == '\0' || (db_type != NULL && *db_type == '\0'))
289	{
290		if (colon != NULL)
291			*colon = ':';
292		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
293		    "praliases: illegal alias specification: %s\n", filename);
294		goto fatal;
295	}
296
297	memset(&params, '\0', sizeof params);
298	params.smdbp_cache_size = 1024 * 1024;
299
300	user_info.smdbu_id = RunAsUid;
301	user_info.smdbu_group_id = RunAsGid;
302	(void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
303			  SMDB_MAX_USER_NAME_LEN);
304
305	result = smdb_open_database(&database, db_name, O_RDONLY, 0,
306				    SFF_ROOTOK, db_type, &user_info, &params);
307	if (result != SMDBE_OK)
308	{
309		sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
310			      "praliases: %s: open: %s\n",
311			      db_name, sm_errstring(result));
312		goto fatal;
313	}
314
315	if (argc == 0)
316	{
317		memset(&db_key, '\0', sizeof db_key);
318		memset(&db_value, '\0', sizeof db_value);
319
320		result = database->smdb_cursor(database, &cursor, 0);
321		if (result != SMDBE_OK)
322		{
323			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
324			    "praliases: %s: set cursor: %s\n", db_name,
325			    sm_errstring(result));
326			goto fatal;
327		}
328
329		while ((result = cursor->smdbc_get(cursor, &db_key, &db_value,
330						   SMDB_CURSOR_GET_NEXT)) ==
331						   SMDBE_OK)
332		{
333#if 0
334			/* skip magic @:@ entry */
335			if (db_key.size == 2 &&
336			    db_key.data[0] == '@' &&
337			    db_key.data[1] == '\0' &&
338			    db_value.size == 2 &&
339			    db_value.data[0] == '@' &&
340			    db_value.data[1] == '\0')
341				continue;
342#endif /* 0 */
343
344			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
345					     "%.*s:%.*s\n",
346					     (int) db_key.size,
347					     (char *) db_key.data,
348					     (int) db_value.size,
349					     (char *) db_value.data);
350		}
351
352		if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY)
353		{
354			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
355				"praliases: %s: get value at cursor: %s\n",
356				db_name, sm_errstring(result));
357			goto fatal;
358		}
359	}
360	else for (; *argv != NULL; ++argv)
361	{
362		int get_res;
363
364		memset(&db_key, '\0', sizeof db_key);
365		memset(&db_value, '\0', sizeof db_value);
366		db_key.data = *argv;
367		db_key.size = strlen(*argv);
368		get_res = database->smdb_get(database, &db_key, &db_value, 0);
369		if (get_res == SMDBE_NOT_FOUND)
370		{
371			db_key.size++;
372			get_res = database->smdb_get(database, &db_key,
373						     &db_value, 0);
374		}
375		if (get_res == SMDBE_OK)
376		{
377			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
378					     "%.*s:%.*s\n",
379					     (int) db_key.size,
380					     (char *) db_key.data,
381					     (int) db_value.size,
382					     (char *) db_value.data);
383		}
384		else
385			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
386					     "%s: No such key\n",
387					     (char *)db_key.data);
388	}
389
390 fatal:
391	if (cursor != NULL)
392		(void) cursor->smdbc_close(cursor);
393	if (database != NULL)
394		(void) database->smdb_close(database);
395	if (colon != NULL)
396		*colon = ':';
397	return;
398}
399