xref: /freebsd/contrib/sendmail/praliases/praliases.c (revision 2e3f49888ec8851bafb22011533217487764fdb0)
1 /*
2  * Copyright (c) 1998-2001, 2008 Proofpoint, 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 
16 SM_IDSTR(copyright,
17 "@(#) Copyright (c) 1998-2001 Proofpoint, 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 
23 SM_IDSTR(id, "@(#)$Id: praliases.c,v 8.98 2013-11-22 20:51:53 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
32 #include <sysexits.h>
33 
34 
35 #ifndef NOT_SENDMAIL
36 # define NOT_SENDMAIL
37 #endif
38 #include <sendmail/sendmail.h>
39 #include <sendmail/pathnames.h>
40 #include <libsmdb/smdb.h>
41 
42 static void praliases __P((char *, int, char **));
43 
44 uid_t	RealUid;
45 gid_t	RealGid;
46 char	*RealUserName;
47 uid_t	RunAsUid;
48 gid_t	RunAsGid;
49 char	*RunAsUserName;
50 int	Verbose = 2;
51 bool	DontInitGroups = false;
52 uid_t	TrustedUid = 0;
53 BITMAP256 DontBlameSendmail;
54 
55 # define DELIMITERS		" ,/"
56 # define PATH_SEPARATOR		':'
57 
58 int
59 main(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:l")) != -1)
91 	{
92 		switch ((char)ch) {
93 		case 'C':
94 			cfile = optarg;
95 			break;
96 		case 'f':
97 			filename = optarg;
98 			break;
99 
100 		case 'l':
101 			smdb_print_available_types(false);
102 			exit(EX_OK);
103 			break;
104 		case '?':
105 		default:
106 			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
107 			    "usage: praliases [-C cffile] [-f aliasfile]"
108 			    " [key ...]\n");
109 			exit(EX_USAGE);
110 		}
111 	}
112 	argc -= optind;
113 	argv += optind;
114 
115 	if (filename != NULL)
116 	{
117 		praliases(filename, argc, argv);
118 		exit(EX_OK);
119 	}
120 
121 	if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY,
122 			      NULL)) == NULL)
123 	{
124 		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
125 				     "praliases: %s: %s\n", cfile,
126 				     sm_errstring(errno));
127 		exit(EX_NOINPUT);
128 	}
129 
130 	while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0)
131 	{
132 		register char *b, *p;
133 
134 		b = strchr(buf, '\n');
135 		if (b != NULL)
136 			*b = '\0';
137 
138 		b = buf;
139 		switch (*b++)
140 		{
141 		  case 'O':		/* option -- see if alias file */
142 			if (sm_strncasecmp(b, " AliasFile", 10) == 0 &&
143 			    !(isascii(b[10]) && isalnum(b[10])))
144 			{
145 				/* new form -- find value */
146 				b = strchr(b, '=');
147 				if (b == NULL)
148 					continue;
149 				while (isascii(*++b) && isspace(*b))
150 					continue;
151 			}
152 			else if (*b++ != 'A')
153 			{
154 				/* something else boring */
155 				continue;
156 			}
157 
158 			/* this is the A or AliasFile option -- save it */
159 			if (sm_strlcpy(afilebuf, b, sizeof afilebuf) >=
160 			    sizeof afilebuf)
161 			{
162 				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
163 				    "praliases: AliasFile filename too long: %.30s\n",
164 					b);
165 				(void) sm_io_close(cfp, SM_TIME_DEFAULT);
166 				exit(EX_CONFIG);
167 			}
168 			b = afilebuf;
169 
170 			for (p = b; p != NULL; )
171 			{
172 				while (isascii(*p) && isspace(*p))
173 					p++;
174 				if (*p == '\0')
175 					break;
176 				b = p;
177 
178 				p = strpbrk(p, DELIMITERS);
179 
180 				/* find end of spec */
181 				if (p != NULL)
182 				{
183 					bool quoted = false;
184 
185 					for (; *p != '\0'; p++)
186 					{
187 						/*
188 						**  Don't break into a quoted
189 						**  string.
190 						*/
191 
192 						if (*p == '"')
193 							quoted = !quoted;
194 						else if (*p == ',' && !quoted)
195 							break;
196 					}
197 
198 					/* No more alias specs follow */
199 					if (*p == '\0')
200 					{
201 						/* chop trailing whitespace */
202 						while (isascii(*p) &&
203 						       isspace(*p) &&
204 						       p > b)
205 							p--;
206 						*p = '\0';
207 						p = NULL;
208 					}
209 				}
210 
211 				if (p != NULL)
212 				{
213 					char *e = p - 1;
214 
215 					/* chop trailing whitespace */
216 					while (isascii(*e) &&
217 					       isspace(*e) &&
218 					       e > b)
219 						e--;
220 					*++e = '\0';
221 					*p++ = '\0';
222 				}
223 				praliases(b, argc, argv);
224 			}
225 
226 		  default:
227 			continue;
228 		}
229 	}
230 	(void) sm_io_close(cfp, SM_TIME_DEFAULT);
231 	exit(EX_OK);
232 	/* NOTREACHED */
233 	return EX_OK;
234 }
235 
236 static void
237 praliases(filename, argc, argv)
238 	char *filename;
239 	int argc;
240 	char **argv;
241 {
242 	int result;
243 	char *colon;
244 	char *db_name;
245 	char *db_type;
246 	SMDB_DATABASE *database = NULL;
247 	SMDB_CURSOR *cursor = NULL;
248 	SMDB_DBENT db_key, db_value;
249 	SMDB_DBPARAMS params;
250 	SMDB_USER_INFO user_info;
251 
252 	colon = strchr(filename, PATH_SEPARATOR);
253 	if (colon == NULL)
254 	{
255 		db_name = filename;
256 		db_type = SMDB_TYPE_DEFAULT;
257 	}
258 	else
259 	{
260 		*colon = '\0';
261 		db_name = colon + 1;
262 		db_type = filename;
263 	}
264 
265 	/* clean off arguments */
266 	for (;;)
267 	{
268 		while (isascii(*db_name) && isspace(*db_name))
269 			db_name++;
270 
271 		if (*db_name != '-')
272 			break;
273 		while (*db_name != '\0' &&
274 		       !(isascii(*db_name) && isspace(*db_name)))
275 			db_name++;
276 	}
277 
278 	/* Skip non-file based DB types */
279 	if (db_type != NULL && *db_type != '\0')
280 	{
281 		if (db_type != SMDB_TYPE_DEFAULT &&
282 		    !smdb_is_db_type(db_type))
283 		{
284 			sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
285 				      "praliases: Skipping non-file based alias type %s\n",
286 				db_type);
287 			return;
288 		}
289 	}
290 
291 	if (*db_name == '\0' || (db_type != NULL && *db_type == '\0'))
292 	{
293 		if (colon != NULL)
294 			*colon = ':';
295 		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
296 		    "praliases: illegal alias specification: %s\n", filename);
297 		goto fatal;
298 	}
299 
300 	memset(&params, '\0', sizeof params);
301 	params.smdbp_cache_size = 1024 * 1024;
302 
303 	user_info.smdbu_id = RunAsUid;
304 	user_info.smdbu_group_id = RunAsGid;
305 	(void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
306 			  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 		sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
313 			      "praliases: %s: open: %s\n",
314 			      db_name, sm_errstring(result));
315 		goto fatal;
316 	}
317 
318 	if (argc == 0)
319 	{
320 		memset(&db_key, '\0', sizeof db_key);
321 		memset(&db_value, '\0', sizeof db_value);
322 
323 		result = database->smdb_cursor(database, &cursor, 0);
324 		if (result != SMDBE_OK)
325 		{
326 			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
327 			    "praliases: %s: set cursor: %s\n", db_name,
328 			    sm_errstring(result));
329 			goto fatal;
330 		}
331 
332 		while ((result = cursor->smdbc_get(cursor, &db_key, &db_value,
333 						   SMDB_CURSOR_GET_NEXT)) ==
334 						   SMDBE_OK)
335 		{
336 #if 0
337 			/* skip magic @:@ entry */
338 			if (db_key.size == 2 &&
339 			    db_key.data[0] == '@' &&
340 			    db_key.data[1] == '\0' &&
341 			    db_value.size == 2 &&
342 			    db_value.data[0] == '@' &&
343 			    db_value.data[1] == '\0')
344 				continue;
345 #endif /* 0 */
346 
347 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
348 					     "%.*s:%.*s\n",
349 					     (int) db_key.size,
350 					     (char *) db_key.data,
351 					     (int) db_value.size,
352 					     (char *) db_value.data);
353 		}
354 
355 		if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY)
356 		{
357 			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
358 				"praliases: %s: get value at cursor: %s\n",
359 				db_name, sm_errstring(result));
360 			goto fatal;
361 		}
362 	}
363 	else for (; *argv != NULL; ++argv)
364 	{
365 		int get_res;
366 
367 		memset(&db_key, '\0', sizeof db_key);
368 		memset(&db_value, '\0', sizeof db_value);
369 		db_key.data = *argv;
370 		db_key.size = strlen(*argv);
371 		get_res = database->smdb_get(database, &db_key, &db_value, 0);
372 		if (get_res == SMDBE_NOT_FOUND)
373 		{
374 			db_key.size++;
375 			get_res = database->smdb_get(database, &db_key,
376 						     &db_value, 0);
377 		}
378 		if (get_res == SMDBE_OK)
379 		{
380 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
381 					     "%.*s:%.*s\n",
382 					     (int) db_key.size,
383 					     (char *) db_key.data,
384 					     (int) db_value.size,
385 					     (char *) db_value.data);
386 		}
387 		else
388 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
389 					     "%s: No such key\n",
390 					     (char *)db_key.data);
391 	}
392 
393  fatal:
394 	if (cursor != NULL)
395 		(void) cursor->smdbc_close(cursor);
396 	if (database != NULL)
397 		(void) database->smdb_close(database);
398 	if (colon != NULL)
399 		*colon = ':';
400 	return;
401 }
402