praliases.c revision 77352
1/*
2 * Copyright (c) 1998-2001 Sendmail, 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#ifndef lint
15static char copyright[] =
16"@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\
17	All rights reserved.\n\
18     Copyright (c) 1983 Eric P. Allman.  All rights reserved.\n\
19     Copyright (c) 1988, 1993\n\
20	The Regents of the University of California.  All rights reserved.\n";
21#endif /* ! lint */
22
23#ifndef lint
24static char id[] = "@(#)$Id: praliases.c,v 8.59.4.19 2001/02/28 02:37:57 ca Exp $";
25#endif /* ! lint */
26
27/* $FreeBSD: head/contrib/sendmail/praliases/praliases.c 77352 2001-05-28 17:10:35Z gshapiro $ */
28
29#include <sys/types.h>
30#include <ctype.h>
31#include <stdlib.h>
32#include <unistd.h>
33#ifdef EX_OK
34# undef EX_OK		/* unistd.h may have another use for this */
35#endif /* EX_OK */
36#include <sysexits.h>
37
38
39#ifndef NOT_SENDMAIL
40# define NOT_SENDMAIL
41#endif /* ! NOT_SENDMAIL */
42#include <sendmail/sendmail.h>
43#include <sendmail/pathnames.h>
44#include <libsmdb/smdb.h>
45
46static void praliases __P((char *, int, char **));
47
48uid_t	RealUid;
49gid_t	RealGid;
50char	*RealUserName;
51uid_t	RunAsUid;
52uid_t	RunAsGid;
53char	*RunAsUserName;
54int	Verbose = 2;
55bool	DontInitGroups = FALSE;
56uid_t	TrustedUid = 0;
57BITMAP256 DontBlameSendmail;
58
59extern void	syserr __P((const char *, ...));
60
61# define DELIMITERS		" ,/"
62# define PATH_SEPARATOR		':'
63
64int
65main(argc, argv)
66	int argc;
67	char **argv;
68{
69	char *cfile;
70	char *filename = NULL;
71	FILE *cfp;
72	int ch;
73	char afilebuf[MAXLINE];
74	char buf[MAXLINE];
75	struct passwd *pw;
76	static char rnamebuf[MAXNAME];
77	extern char *optarg;
78	extern int optind;
79
80
81	clrbitmap(DontBlameSendmail);
82	RunAsUid = RealUid = getuid();
83	RunAsGid = RealGid = getgid();
84	pw = getpwuid(RealUid);
85	if (pw != NULL)
86	{
87		if (strlen(pw->pw_name) > MAXNAME - 1)
88			pw->pw_name[MAXNAME] = 0;
89		snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);
90	}
91	else
92		(void) snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d",
93				(int) RealUid);
94	RunAsUserName = RealUserName = rnamebuf;
95
96	cfile = _PATH_SENDMAILCF;
97	while ((ch = getopt(argc, argv, "C:f:")) != -1)
98	{
99		switch ((char)ch) {
100		case 'C':
101			cfile = optarg;
102			break;
103		case 'f':
104			filename = optarg;
105			break;
106		case '?':
107		default:
108			(void)fprintf(stderr,
109				      "usage: praliases [-C cffile] [-f aliasfile]\n");
110			exit(EX_USAGE);
111		}
112	}
113	argc -= optind;
114	argv += optind;
115
116	if (filename != NULL)
117	{
118		praliases(filename, argc, argv);
119		exit(EX_OK);
120	}
121
122	if ((cfp = fopen(cfile, "r")) == NULL)
123	{
124		fprintf(stderr, "praliases: %s: %s\n",
125			cfile, errstring(errno));
126		exit(EX_NOINPUT);
127	}
128
129	while (fgets(buf, sizeof(buf), cfp) != NULL)
130	{
131		register char *b, *p;
132
133		b = strchr(buf, '\n');
134		if (b != NULL)
135			*b = '\0';
136
137		b = buf;
138		switch (*b++)
139		{
140		  case 'O':		/* option -- see if alias file */
141			if (strncasecmp(b, " AliasFile", 10) == 0 &&
142			    !(isascii(b[10]) && isalnum(b[10])))
143			{
144				/* new form -- find value */
145				b = strchr(b, '=');
146				if (b == NULL)
147					continue;
148				while (isascii(*++b) && isspace(*b))
149					continue;
150			}
151			else if (*b++ != 'A')
152			{
153				/* something else boring */
154				continue;
155			}
156
157			/* this is the A or AliasFile option -- save it */
158			if (strlcpy(afilebuf, b, sizeof afilebuf) >=
159			    sizeof afilebuf)
160			{
161				fprintf(stderr,
162					"praliases: AliasFile filename too long: %.30s\n",
163					b);
164				(void) fclose(cfp);
165				exit(EX_CONFIG);
166			}
167			b = afilebuf;
168
169			for (p = b; p != NULL; )
170			{
171				while (isascii(*p) && isspace(*p))
172					p++;
173				if (*p == '\0')
174					break;
175				b = p;
176
177				p = strpbrk(p, DELIMITERS);
178
179				/* find end of spec */
180				if (p != NULL)
181				{
182					bool quoted = FALSE;
183
184					for (; *p != '\0'; p++)
185					{
186						/*
187						**  Don't break into a quoted
188						**  string.
189						*/
190
191						if (*p == '"')
192							quoted = !quoted;
193						else if (*p == ',' && !quoted)
194							break;
195					}
196
197					/* No more alias specs follow */
198					if (*p == '\0')
199					{
200						/* chop trailing whitespace */
201						while (isascii(*p) &&
202						       isspace(*p) &&
203						       p > b)
204							p--;
205						*p = '\0';
206						p = NULL;
207					}
208				}
209
210				if (p != NULL)
211				{
212					char *e = p - 1;
213
214					/* chop trailing whitespace */
215					while (isascii(*e) &&
216					       isspace(*e) &&
217					       e > b)
218						e--;
219					*++e = '\0';
220					*p++ = '\0';
221				}
222				praliases(b, argc, argv);
223			}
224
225		  default:
226			continue;
227		}
228	}
229	(void) fclose(cfp);
230	exit(EX_OK);
231	/* NOTREACHED */
232	return EX_OK;
233}
234
235static void
236praliases(filename, argc, argv)
237	char *filename;
238	int argc;
239	char **argv;
240{
241	int result;
242	char *colon;
243	char *db_name;
244	char *db_type;
245	SMDB_DATABASE *database = NULL;
246	SMDB_CURSOR *cursor = NULL;
247	SMDB_DBENT db_key, db_value;
248	SMDB_DBPARAMS params;
249	SMDB_USER_INFO user_info;
250
251	colon = strchr(filename, PATH_SEPARATOR);
252	if (colon == NULL)
253	{
254		db_name = filename;
255		db_type = SMDB_TYPE_DEFAULT;
256	}
257	else
258	{
259		*colon = '\0';
260		db_name = colon + 1;
261		db_type = filename;
262	}
263
264	/* clean off arguments */
265	for (;;)
266	{
267		while (isascii(*db_name) && isspace(*db_name))
268			db_name++;
269
270		if (*db_name != '-')
271			break;
272		while (*db_name != '\0' &&
273		       !(isascii(*db_name) && isspace(*db_name)))
274			db_name++;
275	}
276
277	/* Skip non-file based DB types */
278	if (db_type != NULL && *db_type != '\0')
279	{
280		if (db_type != SMDB_TYPE_DEFAULT &&
281		    strcmp(db_type, "hash") != 0 &&
282		    strcmp(db_type, "btree") != 0 &&
283		    strcmp(db_type, "dbm") != 0)
284		{
285			fprintf(stderr,
286				"praliases: Skipping non-file based alias type %s\n",
287				db_type);
288			return;
289		}
290	}
291
292	if (*db_name == '\0' || (db_type != NULL && *db_type == '\0'))
293	{
294		if (colon != NULL)
295			*colon = ':';
296		fprintf(stderr,	"praliases: illegal alias specification: %s\n",
297			filename);
298		goto fatal;
299	}
300
301	memset(&params, '\0', sizeof params);
302	params.smdbp_cache_size = 1024 * 1024;
303
304	user_info.smdbu_id = RunAsUid;
305	user_info.smdbu_group_id = RunAsGid;
306	strlcpy(user_info.smdbu_name, RunAsUserName, SMDB_MAX_USER_NAME_LEN);
307
308	result = smdb_open_database(&database, db_name, O_RDONLY, 0,
309				    SFF_ROOTOK, db_type, &user_info, &params);
310	if (result != SMDBE_OK)
311	{
312		fprintf(stderr, "praliases: %s: open: %s\n",
313			db_name, errstring(result));
314		goto fatal;
315	}
316
317	if (argc == 0)
318	{
319		memset(&db_key, '\0', sizeof db_key);
320		memset(&db_value, '\0', sizeof db_value);
321
322		result = database->smdb_cursor(database, &cursor, 0);
323		if (result != SMDBE_OK)
324		{
325			fprintf(stderr, "praliases: %s: set cursor: %s\n",
326				db_name, errstring(result));
327			goto fatal;
328		}
329
330		while ((result = cursor->smdbc_get(cursor, &db_key, &db_value,
331						   SMDB_CURSOR_GET_NEXT)) ==
332						   SMDBE_OK)
333		{
334#if 0
335			/* skip magic @:@ entry */
336			if (db_key.size == 2 &&
337			    db_key.data[0] == '@' &&
338			    db_key.data[1] == '\0' &&
339			    db_value.size == 2 &&
340			    db_value.data[0] == '@' &&
341			    db_value.data[1] == '\0')
342				continue;
343#endif /* 0 */
344
345			printf("%.*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			fprintf(stderr,
355				"praliases: %s: get value at cursor: %s\n",
356				db_name, 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			printf("%.*s:%.*s\n",
378			       (int) db_key.size,
379			       (char *) db_key.data,
380			       (int) db_value.size,
381			       (char *) db_value.data);
382		}
383		else
384			printf("%s: No such key\n", (char *) db_key.data);
385	}
386
387 fatal:
388	if (cursor != NULL)
389		(void) cursor->smdbc_close(cursor);
390	if (database != NULL)
391		(void) database->smdb_close(database);
392	if (colon != NULL)
393		*colon = ':';
394	return;
395}
396
397/*VARARGS1*/
398void
399#ifdef __STDC__
400message(const char *msg, ...)
401#else /* __STDC__ */
402message(msg, va_alist)
403	const char *msg;
404	va_dcl
405#endif /* __STDC__ */
406{
407	const char *m;
408	VA_LOCAL_DECL
409
410	m = msg;
411	if (isascii(m[0]) && isdigit(m[0]) &&
412	    isascii(m[1]) && isdigit(m[1]) &&
413	    isascii(m[2]) && isdigit(m[2]) && m[3] == ' ')
414		m += 4;
415	VA_START(msg);
416	(void) vfprintf(stderr, m, ap);
417	VA_END;
418	(void) fprintf(stderr, "\n");
419}
420
421/*VARARGS1*/
422void
423#ifdef __STDC__
424syserr(const char *msg, ...)
425#else /* __STDC__ */
426syserr(msg, va_alist)
427	const char *msg;
428	va_dcl
429#endif /* __STDC__ */
430{
431	const char *m;
432	VA_LOCAL_DECL
433
434	m = msg;
435	if (isascii(m[0]) && isdigit(m[0]) &&
436	    isascii(m[1]) && isdigit(m[1]) &&
437	    isascii(m[2]) && isdigit(m[2]) && m[3] == ' ')
438		m += 4;
439	VA_START(msg);
440	(void) vfprintf(stderr, m, ap);
441	VA_END;
442	(void) fprintf(stderr, "\n");
443}
444