praliases.c revision 182352
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.94 2007/05/11 18:50:36 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]\n");
103			exit(EX_USAGE);
104		}
105	}
106	argc -= optind;
107	argv += optind;
108
109	if (filename != NULL)
110	{
111		praliases(filename, argc, argv);
112		exit(EX_OK);
113	}
114
115	if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY,
116			      NULL)) == NULL)
117	{
118		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
119				     "praliases: %s: %s\n", cfile,
120				     sm_errstring(errno));
121		exit(EX_NOINPUT);
122	}
123
124	while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL)
125	{
126		register char *b, *p;
127
128		b = strchr(buf, '\n');
129		if (b != NULL)
130			*b = '\0';
131
132		b = buf;
133		switch (*b++)
134		{
135		  case 'O':		/* option -- see if alias file */
136			if (sm_strncasecmp(b, " AliasFile", 10) == 0 &&
137			    !(isascii(b[10]) && isalnum(b[10])))
138			{
139				/* new form -- find value */
140				b = strchr(b, '=');
141				if (b == NULL)
142					continue;
143				while (isascii(*++b) && isspace(*b))
144					continue;
145			}
146			else if (*b++ != 'A')
147			{
148				/* something else boring */
149				continue;
150			}
151
152			/* this is the A or AliasFile option -- save it */
153			if (sm_strlcpy(afilebuf, b, sizeof afilebuf) >=
154			    sizeof afilebuf)
155			{
156				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
157				    "praliases: AliasFile filename too long: %.30s\n",
158					b);
159				(void) sm_io_close(cfp, SM_TIME_DEFAULT);
160				exit(EX_CONFIG);
161			}
162			b = afilebuf;
163
164			for (p = b; p != NULL; )
165			{
166				while (isascii(*p) && isspace(*p))
167					p++;
168				if (*p == '\0')
169					break;
170				b = p;
171
172				p = strpbrk(p, DELIMITERS);
173
174				/* find end of spec */
175				if (p != NULL)
176				{
177					bool quoted = false;
178
179					for (; *p != '\0'; p++)
180					{
181						/*
182						**  Don't break into a quoted
183						**  string.
184						*/
185
186						if (*p == '"')
187							quoted = !quoted;
188						else if (*p == ',' && !quoted)
189							break;
190					}
191
192					/* No more alias specs follow */
193					if (*p == '\0')
194					{
195						/* chop trailing whitespace */
196						while (isascii(*p) &&
197						       isspace(*p) &&
198						       p > b)
199							p--;
200						*p = '\0';
201						p = NULL;
202					}
203				}
204
205				if (p != NULL)
206				{
207					char *e = p - 1;
208
209					/* chop trailing whitespace */
210					while (isascii(*e) &&
211					       isspace(*e) &&
212					       e > b)
213						e--;
214					*++e = '\0';
215					*p++ = '\0';
216				}
217				praliases(b, argc, argv);
218			}
219
220		  default:
221			continue;
222		}
223	}
224	(void) sm_io_close(cfp, SM_TIME_DEFAULT);
225	exit(EX_OK);
226	/* NOTREACHED */
227	return EX_OK;
228}
229
230static void
231praliases(filename, argc, argv)
232	char *filename;
233	int argc;
234	char **argv;
235{
236	int result;
237	char *colon;
238	char *db_name;
239	char *db_type;
240	SMDB_DATABASE *database = NULL;
241	SMDB_CURSOR *cursor = NULL;
242	SMDB_DBENT db_key, db_value;
243	SMDB_DBPARAMS params;
244	SMDB_USER_INFO user_info;
245
246	colon = strchr(filename, PATH_SEPARATOR);
247	if (colon == NULL)
248	{
249		db_name = filename;
250		db_type = SMDB_TYPE_DEFAULT;
251	}
252	else
253	{
254		*colon = '\0';
255		db_name = colon + 1;
256		db_type = filename;
257	}
258
259	/* clean off arguments */
260	for (;;)
261	{
262		while (isascii(*db_name) && isspace(*db_name))
263			db_name++;
264
265		if (*db_name != '-')
266			break;
267		while (*db_name != '\0' &&
268		       !(isascii(*db_name) && isspace(*db_name)))
269			db_name++;
270	}
271
272	/* Skip non-file based DB types */
273	if (db_type != NULL && *db_type != '\0')
274	{
275		if (db_type != SMDB_TYPE_DEFAULT &&
276		    strcmp(db_type, "hash") != 0 &&
277		    strcmp(db_type, "btree") != 0 &&
278		    strcmp(db_type, "dbm") != 0)
279		{
280			sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
281				      "praliases: Skipping non-file based alias type %s\n",
282				db_type);
283			return;
284		}
285	}
286
287	if (*db_name == '\0' || (db_type != NULL && *db_type == '\0'))
288	{
289		if (colon != NULL)
290			*colon = ':';
291		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
292		    "praliases: illegal alias specification: %s\n", filename);
293		goto fatal;
294	}
295
296	memset(&params, '\0', sizeof params);
297	params.smdbp_cache_size = 1024 * 1024;
298
299	user_info.smdbu_id = RunAsUid;
300	user_info.smdbu_group_id = RunAsGid;
301	(void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
302			  SMDB_MAX_USER_NAME_LEN);
303
304	result = smdb_open_database(&database, db_name, O_RDONLY, 0,
305				    SFF_ROOTOK, db_type, &user_info, &params);
306	if (result != SMDBE_OK)
307	{
308		sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
309			      "praliases: %s: open: %s\n",
310			      db_name, sm_errstring(result));
311		goto fatal;
312	}
313
314	if (argc == 0)
315	{
316		memset(&db_key, '\0', sizeof db_key);
317		memset(&db_value, '\0', sizeof db_value);
318
319		result = database->smdb_cursor(database, &cursor, 0);
320		if (result != SMDBE_OK)
321		{
322			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
323			    "praliases: %s: set cursor: %s\n", db_name,
324			    sm_errstring(result));
325			goto fatal;
326		}
327
328		while ((result = cursor->smdbc_get(cursor, &db_key, &db_value,
329						   SMDB_CURSOR_GET_NEXT)) ==
330						   SMDBE_OK)
331		{
332#if 0
333			/* skip magic @:@ entry */
334			if (db_key.size == 2 &&
335			    db_key.data[0] == '@' &&
336			    db_key.data[1] == '\0' &&
337			    db_value.size == 2 &&
338			    db_value.data[0] == '@' &&
339			    db_value.data[1] == '\0')
340				continue;
341#endif /* 0 */
342
343			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
344					     "%.*s:%.*s\n",
345					     (int) db_key.size,
346					     (char *) db_key.data,
347					     (int) db_value.size,
348					     (char *) db_value.data);
349		}
350
351		if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY)
352		{
353			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
354				"praliases: %s: get value at cursor: %s\n",
355				db_name, sm_errstring(result));
356			goto fatal;
357		}
358	}
359	else for (; *argv != NULL; ++argv)
360	{
361		int get_res;
362
363		memset(&db_key, '\0', sizeof db_key);
364		memset(&db_value, '\0', sizeof db_value);
365		db_key.data = *argv;
366		db_key.size = strlen(*argv);
367		get_res = database->smdb_get(database, &db_key, &db_value, 0);
368		if (get_res == SMDBE_NOT_FOUND)
369		{
370			db_key.size++;
371			get_res = database->smdb_get(database, &db_key,
372						     &db_value, 0);
373		}
374		if (get_res == SMDBE_OK)
375		{
376			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
377					     "%.*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			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
385					     "%s: No such key\n",
386					     (char *)db_key.data);
387	}
388
389 fatal:
390	if (cursor != NULL)
391		(void) cursor->smdbc_close(cursor);
392	if (database != NULL)
393		(void) database->smdb_close(database);
394	if (colon != NULL)
395		*colon = ':';
396	return;
397}
398