xref: /titanic_50/usr/src/cmd/sendmail/aux/praliases.c (revision fa9e4066f08beec538e775443c5be79dd423fcab)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
15 
16 #include <sm/gen.h>
17 
18 SM_IDSTR(copyright,
19 "@(#) Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.\n\
20 	All rights reserved.\n\
21      Copyright (c) 1983 Eric P. Allman.  All rights reserved.\n\
22      Copyright (c) 1988, 1993\n\
23 	The Regents of the University of California.  All rights reserved.\n")
24 
25 SM_IDSTR(id, "@(#)$Id: praliases.c,v 8.91 2001/03/29 21:15:53 rodney Exp $")
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 # define DELIMITERS		" ,/"
58 # define PATH_SEPARATOR		':'
59 
60 int
61 main(argc, argv)
62 	int argc;
63 	char **argv;
64 {
65 	char *cfile;
66 	char *filename = NULL;
67 	SM_FILE_T *cfp;
68 	int ch;
69 	char afilebuf[MAXLINE];
70 	char buf[MAXLINE];
71 	struct passwd *pw;
72 	static char rnamebuf[MAXNAME];
73 	extern char *optarg;
74 	extern int optind;
75 
76 	clrbitmap(DontBlameSendmail);
77 	RunAsUid = RealUid = getuid();
78 	RunAsGid = RealGid = getgid();
79 	pw = getpwuid(RealUid);
80 	if (pw != NULL)
81 	{
82 		if (strlen(pw->pw_name) > MAXNAME - 1)
83 			pw->pw_name[MAXNAME] = 0;
84 		sm_snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);
85 	}
86 	else
87 		(void) sm_snprintf(rnamebuf, sizeof rnamebuf,
88 		    "Unknown UID %d", (int) RealUid);
89 	RunAsUserName = RealUserName = rnamebuf;
90 
91 	cfile = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL);
92 	while ((ch = getopt(argc, argv, "C:f:")) != -1)
93 	{
94 		switch ((char)ch) {
95 		case 'C':
96 			cfile = optarg;
97 			break;
98 		case 'f':
99 			filename = optarg;
100 			break;
101 		case '?':
102 		default:
103 			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
104 			    "usage: praliases [-C cffile] [-f aliasfile]\n");
105 			exit(EX_USAGE);
106 		}
107 	}
108 	argc -= optind;
109 	argv += optind;
110 
111 	if (filename != NULL)
112 	{
113 		praliases(filename, argc, argv);
114 		exit(EX_OK);
115 	}
116 
117 	if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY,
118 			      NULL)) == NULL)
119 	{
120 		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
121 				     "praliases: %s: %s\n", cfile,
122 				     sm_errstring(errno));
123 		exit(EX_NOINPUT);
124 	}
125 
126 	while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL)
127 	{
128 		register char *b, *p;
129 
130 		b = strchr(buf, '\n');
131 		if (b != NULL)
132 			*b = '\0';
133 
134 		b = buf;
135 		switch (*b++)
136 		{
137 		  case 'O':		/* option -- see if alias file */
138 			if (sm_strncasecmp(b, " AliasFile", 10) == 0 &&
139 			    !(isascii(b[10]) && isalnum(b[10])))
140 			{
141 				/* new form -- find value */
142 				b = strchr(b, '=');
143 				if (b == NULL)
144 					continue;
145 				while (isascii(*++b) && isspace(*b))
146 					continue;
147 			}
148 			else if (*b++ != 'A')
149 			{
150 				/* something else boring */
151 				continue;
152 			}
153 
154 			/* this is the A or AliasFile option -- save it */
155 			if (sm_strlcpy(afilebuf, b, sizeof afilebuf) >=
156 			    sizeof afilebuf)
157 			{
158 				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
159 				    "praliases: AliasFile filename too long: %.30s\n",
160 					b);
161 				(void) sm_io_close(cfp, SM_TIME_DEFAULT);
162 				exit(EX_CONFIG);
163 			}
164 			b = afilebuf;
165 
166 			for (p = b; p != NULL; )
167 			{
168 				while (isascii(*p) && isspace(*p))
169 					p++;
170 				if (*p == '\0')
171 					break;
172 				b = p;
173 
174 				p = strpbrk(p, DELIMITERS);
175 
176 				/* find end of spec */
177 				if (p != NULL)
178 				{
179 					bool quoted = false;
180 
181 					for (; *p != '\0'; p++)
182 					{
183 						/*
184 						**  Don't break into a quoted
185 						**  string.
186 						*/
187 
188 						if (*p == '"')
189 							quoted = !quoted;
190 						else if (*p == ',' && !quoted)
191 							break;
192 					}
193 
194 					/* No more alias specs follow */
195 					if (*p == '\0')
196 					{
197 						/* chop trailing whitespace */
198 						while (isascii(*p) &&
199 						       isspace(*p) &&
200 						       p > b)
201 							p--;
202 						*p = '\0';
203 						p = NULL;
204 					}
205 				}
206 
207 				if (p != NULL)
208 				{
209 					char *e = p - 1;
210 
211 					/* chop trailing whitespace */
212 					while (isascii(*e) &&
213 					       isspace(*e) &&
214 					       e > b)
215 						e--;
216 					*++e = '\0';
217 					*p++ = '\0';
218 				}
219 				praliases(b, argc, argv);
220 			}
221 
222 		  default:
223 			continue;
224 		}
225 	}
226 	(void) sm_io_close(cfp, SM_TIME_DEFAULT);
227 	exit(EX_OK);
228 	/* NOTREACHED */
229 	return EX_OK;
230 }
231 
232 static void
233 praliases(filename, argc, argv)
234 	char *filename;
235 	int argc;
236 	char **argv;
237 {
238 	int result;
239 	char *colon;
240 	char *db_name;
241 	char *db_type;
242 	SMDB_DATABASE *database = NULL;
243 	SMDB_CURSOR *cursor = NULL;
244 	SMDB_DBENT db_key, db_value;
245 	SMDB_DBPARAMS params;
246 	SMDB_USER_INFO user_info;
247 
248 	colon = strchr(filename, PATH_SEPARATOR);
249 	if (colon == NULL)
250 	{
251 		db_name = filename;
252 		db_type = SMDB_TYPE_DEFAULT;
253 	}
254 	else
255 	{
256 		*colon = '\0';
257 		db_name = colon + 1;
258 		db_type = filename;
259 	}
260 
261 	/* clean off arguments */
262 	for (;;)
263 	{
264 		while (isascii(*db_name) && isspace(*db_name))
265 			db_name++;
266 
267 		if (*db_name != '-')
268 			break;
269 		while (*db_name != '\0' &&
270 		       !(isascii(*db_name) && isspace(*db_name)))
271 			db_name++;
272 	}
273 
274 	/* Skip non-file based DB types */
275 	if (db_type != NULL && *db_type != '\0')
276 	{
277 		if (db_type != SMDB_TYPE_DEFAULT &&
278 		    strcmp(db_type, "hash") != 0 &&
279 		    strcmp(db_type, "btree") != 0 &&
280 		    strcmp(db_type, "dbm") != 0)
281 		{
282 			sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
283 				      "praliases: Skipping non-file based alias type %s\n",
284 				db_type);
285 			return;
286 		}
287 	}
288 
289 	if (*db_name == '\0' || (db_type != NULL && *db_type == '\0'))
290 	{
291 		if (colon != NULL)
292 			*colon = ':';
293 		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
294 		    "praliases: illegal alias specification: %s\n", filename);
295 		goto fatal;
296 	}
297 
298 	memset(&params, '\0', sizeof params);
299 	params.smdbp_cache_size = 1024 * 1024;
300 
301 	user_info.smdbu_id = RunAsUid;
302 	user_info.smdbu_group_id = RunAsGid;
303 	(void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
304 			  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 		sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
311 			      "praliases: %s: open: %s\n",
312 			      db_name, sm_errstring(result));
313 		goto fatal;
314 	}
315 
316 	if (argc == 0)
317 	{
318 		memset(&db_key, '\0', sizeof db_key);
319 		memset(&db_value, '\0', sizeof db_value);
320 
321 		result = database->smdb_cursor(database, &cursor, 0);
322 		if (result != SMDBE_OK)
323 		{
324 			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
325 			    "praliases: %s: set cursor: %s\n", db_name,
326 			    sm_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 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
346 					     "%.*s:%.*s\n",
347 					     (int) db_key.size,
348 					     (char *) db_key.data,
349 					     (int) db_value.size,
350 					     (char *) db_value.data);
351 		}
352 
353 		if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY)
354 		{
355 			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
356 				"praliases: %s: get value at cursor: %s\n",
357 				db_name, sm_errstring(result));
358 			goto fatal;
359 		}
360 	}
361 	else for (; *argv != NULL; ++argv)
362 	{
363 		int get_res;
364 
365 		memset(&db_key, '\0', sizeof db_key);
366 		memset(&db_value, '\0', sizeof db_value);
367 		db_key.data = *argv;
368 		db_key.size = strlen(*argv);
369 		get_res = database->smdb_get(database, &db_key, &db_value, 0);
370 		if (get_res == SMDBE_NOT_FOUND)
371 		{
372 			db_key.size++;
373 			get_res = database->smdb_get(database, &db_key,
374 						     &db_value, 0);
375 		}
376 		if (get_res == SMDBE_OK)
377 		{
378 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
379 					     "%.*s:%.*s\n",
380 					     (int) db_key.size,
381 					     (char *) db_key.data,
382 					     (int) db_value.size,
383 					     (char *) db_value.data);
384 		}
385 		else
386 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
387 					     "%s: No such key\n",
388 					     (char *)db_key.data);
389 	}
390 
391  fatal:
392 	if (cursor != NULL)
393 		(void) cursor->smdbc_close(cursor);
394 	if (database != NULL)
395 		(void) database->smdb_close(database);
396 	if (colon != NULL)
397 		*colon = ':';
398 	return;
399 }
400