xref: /freebsd/contrib/sendmail/praliases/praliases.c (revision 13058a916175518dfbac6ce66b9b8e22ecf43155)
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 #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 
44 static void praliases __P((char *, int, char **));
45 
46 uid_t	RealUid;
47 gid_t	RealGid;
48 char	*RealUserName;
49 uid_t	RunAsUid;
50 uid_t	RunAsGid;
51 char	*RunAsUserName;
52 int	Verbose = 2;
53 bool	DontInitGroups = FALSE;
54 uid_t	TrustedUid = 0;
55 BITMAP256 DontBlameSendmail;
56 
57 extern void	syserr __P((const char *, ...));
58 
59 # define DELIMITERS		" ,/"
60 # define PATH_SEPARATOR		':'
61 
62 int
63 main(argc, argv)
64 	int argc;
65 	char **argv;
66 {
67 	char *cfile;
68 	char *filename = NULL;
69 	FILE *cfp;
70 	int ch;
71 	char afilebuf[MAXLINE];
72 	char buf[MAXLINE];
73 	struct passwd *pw;
74 	static char rnamebuf[MAXNAME];
75 	extern char *optarg;
76 	extern int optind;
77 
78 
79 	clrbitmap(DontBlameSendmail);
80 	RunAsUid = RealUid = getuid();
81 	RunAsGid = RealGid = getgid();
82 	pw = getpwuid(RealUid);
83 	if (pw != NULL)
84 	{
85 		if (strlen(pw->pw_name) > MAXNAME - 1)
86 			pw->pw_name[MAXNAME] = 0;
87 		snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);
88 	}
89 	else
90 		(void) snprintf(rnamebuf, sizeof rnamebuf, "Unknown UID %d",
91 				(int) RealUid);
92 	RunAsUserName = RealUserName = rnamebuf;
93 
94 	cfile = _PATH_SENDMAILCF;
95 	while ((ch = getopt(argc, argv, "C:f:")) != -1)
96 	{
97 		switch ((char)ch) {
98 		case 'C':
99 			cfile = optarg;
100 			break;
101 		case 'f':
102 			filename = optarg;
103 			break;
104 		case '?':
105 		default:
106 			(void)fprintf(stderr,
107 				      "usage: praliases [-C cffile] [-f aliasfile]\n");
108 			exit(EX_USAGE);
109 		}
110 	}
111 	argc -= optind;
112 	argv += optind;
113 
114 	if (filename != NULL)
115 	{
116 		praliases(filename, argc, argv);
117 		exit(EX_OK);
118 	}
119 
120 	if ((cfp = fopen(cfile, "r")) == NULL)
121 	{
122 		fprintf(stderr, "praliases: %s: %s\n",
123 			cfile, errstring(errno));
124 		exit(EX_NOINPUT);
125 	}
126 
127 	while (fgets(buf, sizeof(buf), cfp) != NULL)
128 	{
129 		register char *b, *p;
130 
131 		b = strchr(buf, '\n');
132 		if (b != NULL)
133 			*b = '\0';
134 
135 		b = buf;
136 		switch (*b++)
137 		{
138 		  case 'O':		/* option -- see if alias file */
139 			if (strncasecmp(b, " AliasFile", 10) == 0 &&
140 			    !(isascii(b[10]) && isalnum(b[10])))
141 			{
142 				/* new form -- find value */
143 				b = strchr(b, '=');
144 				if (b == NULL)
145 					continue;
146 				while (isascii(*++b) && isspace(*b))
147 					continue;
148 			}
149 			else if (*b++ != 'A')
150 			{
151 				/* something else boring */
152 				continue;
153 			}
154 
155 			/* this is the A or AliasFile option -- save it */
156 			if (strlcpy(afilebuf, b, sizeof afilebuf) >=
157 			    sizeof afilebuf)
158 			{
159 				fprintf(stderr,
160 					"praliases: AliasFile filename too long: %.30s\n",
161 					b);
162 				(void) fclose(cfp);
163 				exit(EX_CONFIG);
164 			}
165 			b = afilebuf;
166 
167 			for (p = b; p != NULL; )
168 			{
169 				while (isascii(*p) && isspace(*p))
170 					p++;
171 				if (*p == '\0')
172 					break;
173 				b = p;
174 
175 				p = strpbrk(p, DELIMITERS);
176 
177 				/* find end of spec */
178 				if (p != NULL)
179 				{
180 					bool quoted = FALSE;
181 
182 					for (; *p != '\0'; p++)
183 					{
184 						/*
185 						**  Don't break into a quoted
186 						**  string.
187 						*/
188 
189 						if (*p == '"')
190 							quoted = !quoted;
191 						else if (*p == ',' && !quoted)
192 							break;
193 					}
194 
195 					/* No more alias specs follow */
196 					if (*p == '\0')
197 					{
198 						/* chop trailing whitespace */
199 						while (isascii(*p) &&
200 						       isspace(*p) &&
201 						       p > b)
202 							p--;
203 						*p = '\0';
204 						p = NULL;
205 					}
206 				}
207 
208 				if (p != NULL)
209 				{
210 					char *e = p - 1;
211 
212 					/* chop trailing whitespace */
213 					while (isascii(*e) &&
214 					       isspace(*e) &&
215 					       e > b)
216 						e--;
217 					*++e = '\0';
218 					*p++ = '\0';
219 				}
220 				praliases(b, argc, argv);
221 			}
222 
223 		  default:
224 			continue;
225 		}
226 	}
227 	(void) fclose(cfp);
228 	exit(EX_OK);
229 	/* NOTREACHED */
230 	return EX_OK;
231 }
232 
233 static void
234 praliases(filename, argc, argv)
235 	char *filename;
236 	int argc;
237 	char **argv;
238 {
239 	int result;
240 	char *colon;
241 	char *db_name;
242 	char *db_type;
243 	SMDB_DATABASE *database = NULL;
244 	SMDB_CURSOR *cursor = NULL;
245 	SMDB_DBENT db_key, db_value;
246 	SMDB_DBPARAMS params;
247 	SMDB_USER_INFO user_info;
248 
249 	colon = strchr(filename, PATH_SEPARATOR);
250 	if (colon == NULL)
251 	{
252 		db_name = filename;
253 		db_type = SMDB_TYPE_DEFAULT;
254 	}
255 	else
256 	{
257 		*colon = '\0';
258 		db_name = colon + 1;
259 		db_type = filename;
260 	}
261 
262 	/* clean off arguments */
263 	for (;;)
264 	{
265 		while (isascii(*db_name) && isspace(*db_name))
266 			db_name++;
267 
268 		if (*db_name != '-')
269 			break;
270 		while (*db_name != '\0' &&
271 		       !(isascii(*db_name) && isspace(*db_name)))
272 			db_name++;
273 	}
274 
275 	/* Skip non-file based DB types */
276 	if (db_type != NULL && *db_type != '\0')
277 	{
278 		if (db_type != SMDB_TYPE_DEFAULT &&
279 		    strcmp(db_type, "hash") != 0 &&
280 		    strcmp(db_type, "btree") != 0 &&
281 		    strcmp(db_type, "dbm") != 0)
282 		{
283 			fprintf(stderr,
284 				"praliases: Skipping non-file based alias type %s\n",
285 				db_type);
286 			return;
287 		}
288 	}
289 
290 	if (*db_name == '\0' || (db_type != NULL && *db_type == '\0'))
291 	{
292 		if (colon != NULL)
293 			*colon = ':';
294 		fprintf(stderr,	"praliases: illegal alias specification: %s\n",
295 			filename);
296 		goto fatal;
297 	}
298 
299 	memset(&params, '\0', sizeof params);
300 	params.smdbp_cache_size = 1024 * 1024;
301 
302 	user_info.smdbu_id = RunAsUid;
303 	user_info.smdbu_group_id = RunAsGid;
304 	strlcpy(user_info.smdbu_name, RunAsUserName, 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 		fprintf(stderr, "praliases: %s: open: %s\n",
311 			db_name, errstring(result));
312 		goto fatal;
313 	}
314 
315 	if (argc == 0)
316 	{
317 		memset(&db_key, '\0', sizeof db_key);
318 		memset(&db_value, '\0', sizeof db_value);
319 
320 		result = database->smdb_cursor(database, &cursor, 0);
321 		if (result != SMDBE_OK)
322 		{
323 			fprintf(stderr, "praliases: %s: set cursor: %s\n",
324 				db_name, 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 			printf("%.*s:%.*s\n",
344 			       (int) db_key.size,
345 			       (char *) db_key.data,
346 			       (int) db_value.size,
347 			       (char *) db_value.data);
348 		}
349 
350 		if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY)
351 		{
352 			fprintf(stderr,
353 				"praliases: %s: get value at cursor: %s\n",
354 				db_name, errstring(result));
355 			goto fatal;
356 		}
357 	}
358 	else for (; *argv != NULL; ++argv)
359 	{
360 		int get_res;
361 
362 		memset(&db_key, '\0', sizeof db_key);
363 		memset(&db_value, '\0', sizeof db_value);
364 		db_key.data = *argv;
365 		db_key.size = strlen(*argv);
366 		get_res = database->smdb_get(database, &db_key, &db_value, 0);
367 		if (get_res == SMDBE_NOT_FOUND)
368 		{
369 			db_key.size++;
370 			get_res = database->smdb_get(database, &db_key,
371 						     &db_value, 0);
372 		}
373 		if (get_res == SMDBE_OK)
374 		{
375 			printf("%.*s:%.*s\n",
376 			       (int) db_key.size,
377 			       (char *) db_key.data,
378 			       (int) db_value.size,
379 			       (char *) db_value.data);
380 		}
381 		else
382 			printf("%s: No such key\n", (char *) db_key.data);
383 	}
384 
385  fatal:
386 	if (cursor != NULL)
387 		(void) cursor->smdbc_close(cursor);
388 	if (database != NULL)
389 		(void) database->smdb_close(database);
390 	if (colon != NULL)
391 		*colon = ':';
392 	return;
393 }
394 
395 /*VARARGS1*/
396 void
397 #ifdef __STDC__
398 message(const char *msg, ...)
399 #else /* __STDC__ */
400 message(msg, va_alist)
401 	const char *msg;
402 	va_dcl
403 #endif /* __STDC__ */
404 {
405 	const char *m;
406 	VA_LOCAL_DECL
407 
408 	m = msg;
409 	if (isascii(m[0]) && isdigit(m[0]) &&
410 	    isascii(m[1]) && isdigit(m[1]) &&
411 	    isascii(m[2]) && isdigit(m[2]) && m[3] == ' ')
412 		m += 4;
413 	VA_START(msg);
414 	(void) vfprintf(stderr, m, ap);
415 	VA_END;
416 	(void) fprintf(stderr, "\n");
417 }
418 
419 /*VARARGS1*/
420 void
421 #ifdef __STDC__
422 syserr(const char *msg, ...)
423 #else /* __STDC__ */
424 syserr(msg, va_alist)
425 	const char *msg;
426 	va_dcl
427 #endif /* __STDC__ */
428 {
429 	const char *m;
430 	VA_LOCAL_DECL
431 
432 	m = msg;
433 	if (isascii(m[0]) && isdigit(m[0]) &&
434 	    isascii(m[1]) && isdigit(m[1]) &&
435 	    isascii(m[2]) && isdigit(m[2]) && m[3] == ' ')
436 		m += 4;
437 	VA_START(msg);
438 	(void) vfprintf(stderr, m, ap);
439 	VA_END;
440 	(void) fprintf(stderr, "\n");
441 }
442