xref: /freebsd/contrib/sendmail/praliases/praliases.c (revision 5521ff5a4d1929056e7ffc982fac3341ca54df7c)
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
15 static 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
24 static char id[] = "@(#)$Id: praliases.c,v 8.59.4.19 2001/02/28 02:37:57 ca Exp $";
25 #endif /* ! lint */
26 
27 /* $FreeBSD$ */
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 
46 static void praliases __P((char *, int, char **));
47 
48 uid_t	RealUid;
49 gid_t	RealGid;
50 char	*RealUserName;
51 uid_t	RunAsUid;
52 uid_t	RunAsGid;
53 char	*RunAsUserName;
54 int	Verbose = 2;
55 bool	DontInitGroups = FALSE;
56 uid_t	TrustedUid = 0;
57 BITMAP256 DontBlameSendmail;
58 
59 extern void	syserr __P((const char *, ...));
60 
61 # define DELIMITERS		" ,/"
62 # define PATH_SEPARATOR		':'
63 
64 int
65 main(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 
235 static void
236 praliases(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*/
398 void
399 #ifdef __STDC__
400 message(const char *msg, ...)
401 #else /* __STDC__ */
402 message(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*/
422 void
423 #ifdef __STDC__
424 syserr(const char *msg, ...)
425 #else /* __STDC__ */
426 syserr(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