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