praliases.c revision 266692
1193323Sed/*
2193323Sed * Copyright (c) 1998-2001, 2008 Proofpoint, Inc. and its suppliers.
3193323Sed *	All rights reserved.
4193323Sed * Copyright (c) 1983 Eric P. Allman.  All rights reserved.
5193323Sed * Copyright (c) 1988, 1993
6193323Sed *	The Regents of the University of California.  All rights reserved.
7193323Sed *
8193323Sed * By using this file, you agree to the terms and conditions set
9193323Sed * forth in the LICENSE file which can be found at the top level of
10193323Sed * the sendmail distribution.
11193323Sed *
12193323Sed */
13193323Sed
14193323Sed#include <sm/gen.h>
15193323Sed
16193323SedSM_IDSTR(copyright,
17193323Sed"@(#) Copyright (c) 1998-2001 Proofpoint, Inc. and its suppliers.\n\
18234353Sdim	All rights reserved.\n\
19198396Srdivacky     Copyright (c) 1983 Eric P. Allman.  All rights reserved.\n\
20193323Sed     Copyright (c) 1988, 1993\n\
21193323Sed	The Regents of the University of California.  All rights reserved.\n")
22193323Sed
23193323SedSM_IDSTR(id, "@(#)$Id: praliases.c,v 8.98 2013-11-22 20:51:53 ca Exp $")
24263508Sdim
25263508Sdim#include <sys/types.h>
26263508Sdim#include <ctype.h>
27263508Sdim#include <stdlib.h>
28263508Sdim#include <unistd.h>
29263508Sdim#ifdef EX_OK
30263508Sdim# undef EX_OK		/* unistd.h may have another use for this */
31263508Sdim#endif /* EX_OK */
32263508Sdim#include <sysexits.h>
33263508Sdim
34263508Sdim
35263508Sdim#ifndef NOT_SENDMAIL
36263508Sdim# define NOT_SENDMAIL
37263508Sdim#endif /* ! NOT_SENDMAIL */
38234353Sdim#include <sendmail/sendmail.h>
39263508Sdim#include <sendmail/pathnames.h>
40193323Sed#include <libsmdb/smdb.h>
41251662Sdim
42251662Sdimstatic void praliases __P((char *, int, char **));
43251662Sdim
44251662Sdimuid_t	RealUid;
45251662Sdimgid_t	RealGid;
46251662Sdimchar	*RealUserName;
47251662Sdimuid_t	RunAsUid;
48251662Sdimgid_t	RunAsGid;
49251662Sdimchar	*RunAsUserName;
50251662Sdimint	Verbose = 2;
51251662Sdimbool	DontInitGroups = false;
52251662Sdimuid_t	TrustedUid = 0;
53251662SdimBITMAP256 DontBlameSendmail;
54251662Sdim
55251662Sdim# define DELIMITERS		" ,/"
56251662Sdim# define PATH_SEPARATOR		':'
57251662Sdim
58251662Sdimint
59251662Sdimmain(argc, argv)
60251662Sdim	int argc;
61251662Sdim	char **argv;
62251662Sdim{
63251662Sdim	char *cfile;
64251662Sdim	char *filename = NULL;
65251662Sdim	SM_FILE_T *cfp;
66251662Sdim	int ch;
67251662Sdim	char afilebuf[MAXLINE];
68251662Sdim	char buf[MAXLINE];
69251662Sdim	struct passwd *pw;
70251662Sdim	static char rnamebuf[MAXNAME];
71251662Sdim	extern char *optarg;
72251662Sdim	extern int optind;
73251662Sdim
74251662Sdim	clrbitmap(DontBlameSendmail);
75251662Sdim	RunAsUid = RealUid = getuid();
76251662Sdim	RunAsGid = RealGid = getgid();
77251662Sdim	pw = getpwuid(RealUid);
78251662Sdim	if (pw != NULL)
79251662Sdim	{
80251662Sdim		if (strlen(pw->pw_name) > MAXNAME - 1)
81251662Sdim			pw->pw_name[MAXNAME] = 0;
82251662Sdim		sm_snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);
83234353Sdim	}
84234353Sdim	else
85234353Sdim		(void) sm_snprintf(rnamebuf, sizeof rnamebuf,
86234353Sdim		    "Unknown UID %d", (int) RealUid);
87234353Sdim	RunAsUserName = RealUserName = rnamebuf;
88234353Sdim
89234353Sdim	cfile = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL);
90234353Sdim	while ((ch = getopt(argc, argv, "C:f:")) != -1)
91234353Sdim	{
92234353Sdim		switch ((char)ch) {
93234353Sdim		case 'C':
94234353Sdim			cfile = optarg;
95234353Sdim			break;
96234353Sdim		case 'f':
97234353Sdim			filename = optarg;
98234353Sdim			break;
99234353Sdim		case '?':
100234353Sdim		default:
101234353Sdim			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
102239462Sdim			    "usage: praliases [-C cffile] [-f aliasfile]"
103239462Sdim			    " [key ...]\n");
104239462Sdim			exit(EX_USAGE);
105239462Sdim		}
106239462Sdim	}
107239462Sdim	argc -= optind;
108239462Sdim	argv += optind;
109234353Sdim
110234353Sdim	if (filename != NULL)
111234353Sdim	{
112234353Sdim		praliases(filename, argc, argv);
113234353Sdim		exit(EX_OK);
114234353Sdim	}
115234353Sdim
116234353Sdim	if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY,
117234353Sdim			      NULL)) == NULL)
118234353Sdim	{
119234353Sdim		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
120234353Sdim				     "praliases: %s: %s\n", cfile,
121234353Sdim				     sm_errstring(errno));
122234353Sdim		exit(EX_NOINPUT);
123234353Sdim	}
124234353Sdim
125234353Sdim	while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0)
126234353Sdim	{
127234353Sdim		register char *b, *p;
128234353Sdim
129234353Sdim		b = strchr(buf, '\n');
130234353Sdim		if (b != NULL)
131234353Sdim			*b = '\0';
132234353Sdim
133234353Sdim		b = buf;
134234353Sdim		switch (*b++)
135234353Sdim		{
136234353Sdim		  case 'O':		/* option -- see if alias file */
137234353Sdim			if (sm_strncasecmp(b, " AliasFile", 10) == 0 &&
138234353Sdim			    !(isascii(b[10]) && isalnum(b[10])))
139234353Sdim			{
140234353Sdim				/* new form -- find value */
141234353Sdim				b = strchr(b, '=');
142234353Sdim				if (b == NULL)
143234353Sdim					continue;
144234353Sdim				while (isascii(*++b) && isspace(*b))
145239462Sdim					continue;
146239462Sdim			}
147239462Sdim			else if (*b++ != 'A')
148239462Sdim			{
149239462Sdim				/* something else boring */
150239462Sdim				continue;
151239462Sdim			}
152239462Sdim
153239462Sdim			/* this is the A or AliasFile option -- save it */
154239462Sdim			if (sm_strlcpy(afilebuf, b, sizeof afilebuf) >=
155239462Sdim			    sizeof afilebuf)
156239462Sdim			{
157234353Sdim				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
158234353Sdim				    "praliases: AliasFile filename too long: %.30s\n",
159234353Sdim					b);
160234353Sdim				(void) sm_io_close(cfp, SM_TIME_DEFAULT);
161234353Sdim				exit(EX_CONFIG);
162234353Sdim			}
163234353Sdim			b = afilebuf;
164239462Sdim
165251662Sdim			for (p = b; p != NULL; )
166234353Sdim			{
167239462Sdim				while (isascii(*p) && isspace(*p))
168251662Sdim					p++;
169239462Sdim				if (*p == '\0')
170234353Sdim					break;
171239462Sdim				b = p;
172234353Sdim
173234353Sdim				p = strpbrk(p, DELIMITERS);
174251662Sdim
175251662Sdim				/* find end of spec */
176251662Sdim				if (p != NULL)
177234353Sdim				{
178239462Sdim					bool quoted = false;
179234353Sdim
180251662Sdim					for (; *p != '\0'; p++)
181234353Sdim					{
182234353Sdim						/*
183234353Sdim						**  Don't break into a quoted
184234353Sdim						**  string.
185234353Sdim						*/
186234353Sdim
187234353Sdim						if (*p == '"')
188234353Sdim							quoted = !quoted;
189239462Sdim						else if (*p == ',' && !quoted)
190239462Sdim							break;
191239462Sdim					}
192249423Sdim
193249423Sdim					/* No more alias specs follow */
194249423Sdim					if (*p == '\0')
195249423Sdim					{
196234353Sdim						/* chop trailing whitespace */
197234353Sdim						while (isascii(*p) &&
198234353Sdim						       isspace(*p) &&
199234353Sdim						       p > b)
200234353Sdim							p--;
201234353Sdim						*p = '\0';
202234353Sdim						p = NULL;
203234353Sdim					}
204234353Sdim				}
205234353Sdim
206234353Sdim				if (p != NULL)
207234353Sdim				{
208234353Sdim					char *e = p - 1;
209234353Sdim
210263508Sdim					/* chop trailing whitespace */
211263508Sdim					while (isascii(*e) &&
212263508Sdim					       isspace(*e) &&
213263508Sdim					       e > b)
214263508Sdim						e--;
215263508Sdim					*++e = '\0';
216263508Sdim					*p++ = '\0';
217263508Sdim				}
218263508Sdim				praliases(b, argc, argv);
219263508Sdim			}
220263508Sdim
221263508Sdim		  default:
222263508Sdim			continue;
223263508Sdim		}
224234353Sdim	}
225234353Sdim	(void) sm_io_close(cfp, SM_TIME_DEFAULT);
226234353Sdim	exit(EX_OK);
227234353Sdim	/* NOTREACHED */
228234353Sdim	return EX_OK;
229234353Sdim}
230234353Sdim
231234353Sdimstatic void
232234353Sdimpraliases(filename, argc, argv)
233234353Sdim	char *filename;
234234353Sdim	int argc;
235234353Sdim	char **argv;
236234353Sdim{
237234353Sdim	int result;
238234353Sdim	char *colon;
239234353Sdim	char *db_name;
240234353Sdim	char *db_type;
241234353Sdim	SMDB_DATABASE *database = NULL;
242234353Sdim	SMDB_CURSOR *cursor = NULL;
243234353Sdim	SMDB_DBENT db_key, db_value;
244234353Sdim	SMDB_DBPARAMS params;
245249423Sdim	SMDB_USER_INFO user_info;
246249423Sdim
247249423Sdim	colon = strchr(filename, PATH_SEPARATOR);
248249423Sdim	if (colon == NULL)
249249423Sdim	{
250249423Sdim		db_name = filename;
251249423Sdim		db_type = SMDB_TYPE_DEFAULT;
252249423Sdim	}
253249423Sdim	else
254249423Sdim	{
255234353Sdim		*colon = '\0';
256234353Sdim		db_name = colon + 1;
257234353Sdim		db_type = filename;
258234353Sdim	}
259234353Sdim
260234353Sdim	/* clean off arguments */
261234353Sdim	for (;;)
262234353Sdim	{
263234353Sdim		while (isascii(*db_name) && isspace(*db_name))
264234353Sdim			db_name++;
265234353Sdim
266234353Sdim		if (*db_name != '-')
267234353Sdim			break;
268234353Sdim		while (*db_name != '\0' &&
269234353Sdim		       !(isascii(*db_name) && isspace(*db_name)))
270234353Sdim			db_name++;
271234353Sdim	}
272234353Sdim
273234353Sdim	/* Skip non-file based DB types */
274239462Sdim	if (db_type != NULL && *db_type != '\0')
275239462Sdim	{
276239462Sdim		if (db_type != SMDB_TYPE_DEFAULT &&
277239462Sdim		    strcmp(db_type, "hash") != 0 &&
278239462Sdim		    strcmp(db_type, "btree") != 0 &&
279239462Sdim		    strcmp(db_type, "dbm") != 0)
280239462Sdim		{
281239462Sdim			sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
282239462Sdim				      "praliases: Skipping non-file based alias type %s\n",
283239462Sdim				db_type);
284239462Sdim			return;
285239462Sdim		}
286234353Sdim	}
287234353Sdim
288234353Sdim	if (*db_name == '\0' || (db_type != NULL && *db_type == '\0'))
289234353Sdim	{
290234353Sdim		if (colon != NULL)
291234353Sdim			*colon = ':';
292234353Sdim		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
293234353Sdim		    "praliases: illegal alias specification: %s\n", filename);
294234353Sdim		goto fatal;
295234353Sdim	}
296234353Sdim
297234353Sdim	memset(&params, '\0', sizeof params);
298234353Sdim	params.smdbp_cache_size = 1024 * 1024;
299234353Sdim
300234353Sdim	user_info.smdbu_id = RunAsUid;
301234353Sdim	user_info.smdbu_group_id = RunAsGid;
302234353Sdim	(void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
303234353Sdim			  SMDB_MAX_USER_NAME_LEN);
304234353Sdim
305249423Sdim	result = smdb_open_database(&database, db_name, O_RDONLY, 0,
306249423Sdim				    SFF_ROOTOK, db_type, &user_info, &params);
307249423Sdim	if (result != SMDBE_OK)
308249423Sdim	{
309249423Sdim		sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
310234353Sdim			      "praliases: %s: open: %s\n",
311234353Sdim			      db_name, sm_errstring(result));
312234353Sdim		goto fatal;
313234353Sdim	}
314234353Sdim
315234353Sdim	if (argc == 0)
316234353Sdim	{
317234353Sdim		memset(&db_key, '\0', sizeof db_key);
318234353Sdim		memset(&db_value, '\0', sizeof db_value);
319234353Sdim
320234353Sdim		result = database->smdb_cursor(database, &cursor, 0);
321234353Sdim		if (result != SMDBE_OK)
322234353Sdim		{
323234353Sdim			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
324239462Sdim			    "praliases: %s: set cursor: %s\n", db_name,
325239462Sdim			    sm_errstring(result));
326234353Sdim			goto fatal;
327239462Sdim		}
328263508Sdim
329263508Sdim		while ((result = cursor->smdbc_get(cursor, &db_key, &db_value,
330239462Sdim						   SMDB_CURSOR_GET_NEXT)) ==
331239462Sdim						   SMDBE_OK)
332234353Sdim		{
333234353Sdim#if 0
334234353Sdim			/* skip magic @:@ entry */
335234353Sdim			if (db_key.size == 2 &&
336234353Sdim			    db_key.data[0] == '@' &&
337234353Sdim			    db_key.data[1] == '\0' &&
338234353Sdim			    db_value.size == 2 &&
339239462Sdim			    db_value.data[0] == '@' &&
340234353Sdim			    db_value.data[1] == '\0')
341234353Sdim				continue;
342234353Sdim#endif /* 0 */
343234353Sdim
344234353Sdim			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
345249423Sdim					     "%.*s:%.*s\n",
346249423Sdim					     (int) db_key.size,
347249423Sdim					     (char *) db_key.data,
348249423Sdim					     (int) db_value.size,
349249423Sdim					     (char *) db_value.data);
350263508Sdim		}
351249423Sdim
352193323Sed		if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY)
353193323Sed		{
354193323Sed			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
355212904Sdim				"praliases: %s: get value at cursor: %s\n",
356193323Sed				db_name, sm_errstring(result));
357193323Sed			goto fatal;
358193323Sed		}
359193323Sed	}
360193323Sed	else for (; *argv != NULL; ++argv)
361212904Sdim	{
362206124Srdivacky		int get_res;
363206124Srdivacky
364206124Srdivacky		memset(&db_key, '\0', sizeof db_key);
365193323Sed		memset(&db_value, '\0', sizeof db_value);
366234353Sdim		db_key.data = *argv;
367212904Sdim		db_key.size = strlen(*argv);
368193323Sed		get_res = database->smdb_get(database, &db_key, &db_value, 0);
369234353Sdim		if (get_res == SMDBE_NOT_FOUND)
370212904Sdim		{
371193323Sed			db_key.size++;
372218893Sdim			get_res = database->smdb_get(database, &db_key,
373218893Sdim						     &db_value, 0);
374218893Sdim		}
375234353Sdim		if (get_res == SMDBE_OK)
376234353Sdim		{
377234353Sdim			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
378234353Sdim					     "%.*s:%.*s\n",
379234353Sdim					     (int) db_key.size,
380193323Sed					     (char *) db_key.data,
381193323Sed					     (int) db_value.size,
382193323Sed					     (char *) db_value.data);
383212904Sdim		}
384212904Sdim		else
385239462Sdim			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
386239462Sdim					     "%s: No such key\n",
387239462Sdim					     (char *)db_key.data);
388239462Sdim	}
389218893Sdim
390218893Sdim fatal:
391218893Sdim	if (cursor != NULL)
392234353Sdim		(void) cursor->smdbc_close(cursor);
393193323Sed	if (database != NULL)
394193323Sed		(void) database->smdb_close(database);
395212904Sdim	if (colon != NULL)
396193323Sed		*colon = ':';
397234353Sdim	return;
398234353Sdim}
399226633Sdim