praliases.c revision 42580
1/*
2 * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
3 * Copyright (c) 1983 Eric P. Allman.  All rights reserved.
4 * Copyright (c) 1988, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * By using this file, you agree to the terms and conditions set
8 * forth in the LICENSE file which can be found at the top level of
9 * the sendmail distribution.
10 *
11 */
12
13#ifndef lint
14static char copyright[] =
15"@(#) Copyright (c) 1988, 1993\n\
16	The Regents of the University of California.  All rights reserved.\n";
17#endif /* not lint */
18
19#ifndef lint
20static char sccsid[] = "@(#)praliases.c	8.21 (Berkeley) 12/27/1998";
21#endif /* not lint */
22
23#if !defined(NDBM) && !defined(NEWDB)
24  ERROR README:	You must define one of NDBM or NEWDB in order to compile
25  ERROR README:	praliases.
26#endif
27
28#ifdef NDBM
29# include <ndbm.h>
30#endif
31#ifndef NOT_SENDMAIL
32# define NOT_SENDMAIL
33#endif
34#include <sendmail.h>
35#include <pathnames.h>
36#ifdef NEWDB
37# include <db.h>
38# ifndef DB_VERSION_MAJOR
39#  define DB_VERSION_MAJOR 1
40# endif
41#endif
42
43#if defined(IRIX64) || defined(IRIX5) || defined(IRIX6) || \
44    defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__)
45# ifndef HASSTRERROR
46#  define HASSTRERROR	1	/* has strerror(3) */
47# endif
48#endif
49
50#if !HASSTRERROR
51extern char	*strerror __P((int));
52#endif
53
54static void praliases __P((char *, int, char **));
55#ifdef NDBM
56static void praliases_dbm __P((char *, int, char **));
57#endif
58
59int
60main(argc, argv)
61	int argc;
62	char **argv;
63{
64	extern char *optarg;
65	extern int optind;
66	char *cfile;
67#if _FFR_GRAB_ALIASFILE_OPTION
68	char *filename = NULL;
69#else
70	char *filename = "/etc/aliases";
71#endif
72	FILE *cfp;
73	int ch;
74	char afilebuf[MAXLINE];
75	char buf[MAXLINE];
76
77	cfile = _PATH_SENDMAILCF;
78#if _FFR_GRAB_ALIASFILE_OPTION
79	while ((ch = getopt(argc, argv, "C:f:")) != -1)
80#else
81	while ((ch = getopt(argc, argv, "f:")) != -1)
82#endif
83	{
84		switch ((char)ch) {
85		case 'C':
86			cfile = optarg;
87			break;
88		case 'f':
89			filename = optarg;
90			break;
91		case '?':
92		default:
93			(void)fprintf(stderr,
94#if _FFR_GRAB_ALIASFILE_OPTION
95				"usage: praliases [-C cffile] [-f aliasfile]\n");
96#else
97				"usage: praliases [-f aliasfile]\n");
98#endif
99			exit(EX_USAGE);
100		}
101	}
102	argc -= optind;
103	argv += optind;
104
105	if (filename != NULL)
106	{
107		praliases(filename, argc, argv);
108		exit(EX_OK);
109	}
110
111	if ((cfp = fopen(cfile, "r")) == NULL)
112	{
113		fprintf(stderr, "praliases: ");
114		perror(cfile);
115		exit(EX_NOINPUT);
116	}
117
118	while (fgets(buf, sizeof(buf), cfp) != NULL)
119	{
120		register char *b, *p;
121
122		b = buf;
123		switch (*b++)
124		{
125		  case 'O':		/* option -- see if alias file */
126			if (strncasecmp(b, " AliasFile", 10) == 0 &&
127			    !(isascii(b[10]) && isalnum(b[10])))
128			{
129				/* new form -- find value */
130				b = strchr(b, '=');
131				if (b == NULL)
132					continue;
133				while (isascii(*++b) && isspace(*b))
134					continue;
135			}
136			else if (*b++ != 'A')
137			{
138				/* something else boring */
139				continue;
140			}
141
142			/* this is the A or AliasFile option -- save it */
143			if (strlen(b) >= sizeof afilebuf)
144			{
145				fprintf(stderr,
146					"AliasFile filename too long: %.30s...\n",
147					b);
148				(void) fclose(cfp);
149				exit(EX_CONFIG);
150			}
151			strcpy(afilebuf, b);
152			b = afilebuf;
153
154			for (p = b; p != NULL; )
155			{
156				while (isascii(*p) && isspace(*p))
157					p++;
158				if (*p == '\0')
159					break;
160				b = p;
161
162				p = strpbrk(p, " ,/");
163				/* find end of spec */
164				if (p != NULL)
165					p = strpbrk(p, ",\n");
166				if (p != NULL)
167					*p++ = '\0';
168
169				praliases(b, argc, argv);
170			}
171
172		  default:
173			continue;
174		}
175	}
176	(void) fclose(cfp);
177	exit(EX_OK);
178}
179
180static void
181praliases(filename, argc, argv)
182	char *filename;
183	int  argc;
184	char **argv;
185{
186#ifdef NEWDB
187	DB *db;
188	DBT newdbkey, newdbcontent;
189	char buf[MAXNAME];
190#endif
191	char *class;
192
193	class = strchr(filename, ':');
194	if (class != NULL)
195	{
196		if (strncasecmp(filename, "dbm:", 4) == 0)
197		{
198#ifdef NDBM
199			praliases_dbm(class + 1, argc, argv);
200			return;
201#else
202			fprintf(stderr, "class dbm not available\n");
203			exit(EX_DATAERR);
204#endif
205		}
206		filename = class + 1;
207	}
208#ifdef NEWDB
209	if (strlen(filename) + 4 >= sizeof buf)
210	{
211		fprintf(stderr, "Alias filename too long: %.30s...\n", filename);
212		exit(EX_USAGE);
213	}
214	(void) strcpy(buf, filename);
215	(void) strcat(buf, ".db");
216# if DB_VERSION_MAJOR < 2
217	db = dbopen(buf, O_RDONLY, 0444, DB_HASH, NULL);
218# else
219	db = NULL;
220	errno = db_open(buf, DB_HASH, DB_RDONLY, 0444, NULL, NULL, &db);
221# endif
222	if (db != NULL)
223	{
224		if (!argc)
225		{
226# if DB_VERSION_MAJOR > 1
227			DBC *dbc;
228# endif
229			bzero(&newdbkey, sizeof newdbkey);
230			bzero(&newdbcontent, sizeof newdbcontent);
231
232# if DB_VERSION_MAJOR < 2
233			while(!db->seq(db, &newdbkey, &newdbcontent, R_NEXT))
234# else
235#  if DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >=6
236			if ((errno = db->cursor(db, NULL, &dbc, 0)) == 0)
237#  else
238			if ((errno = db->cursor(db, NULL, &dbc)) == 0)
239#  endif
240			{
241				while ((errno = dbc->c_get(dbc, &newdbkey,
242							   &newdbcontent,
243							   DB_NEXT)) == 0)
244# endif
245				printf("%.*s:%.*s\n",
246					(int) newdbkey.size,
247					(char *) newdbkey.data,
248					(int) newdbcontent.size,
249					(char *) newdbcontent.data);
250# if DB_VERSION_MAJOR > 1
251				(void) dbc->c_close(dbc);
252			}
253			else
254			{
255				fprintf(stderr,
256					"praliases: %s: Could not set cursor: %s\n",
257					buf, strerror(errno));
258				errno = db->close(db, 0);
259				exit(EX_DATAERR);
260			}
261# endif
262		}
263		else for (; *argv; ++argv)
264		{
265			bzero(&newdbkey, sizeof newdbkey);
266			bzero(&newdbcontent, sizeof newdbcontent);
267			newdbkey.data = *argv;
268			newdbkey.size = strlen(*argv) + 1;
269# if DB_VERSION_MAJOR < 2
270			if (!db->get(db, &newdbkey, &newdbcontent, 0))
271# else
272			if ((errno = db->get(db, NULL, &newdbkey,
273					     &newdbcontent, 0)) == 0)
274# endif
275				printf("%s:%.*s\n", (char *) newdbkey.data,
276					(int) newdbcontent.size,
277					(char *) newdbcontent.data);
278			else
279				printf("%s: No such key\n",
280					(char *) newdbkey.data);
281		}
282# if DB_VERSION_MAJOR < 2
283		(void)db->close(db);
284# else
285		errno = db->close(db, 0);
286# endif
287	}
288	else
289	{
290#endif
291#ifdef NDBM
292		praliases_dbm(filename, argc, argv);
293#endif
294#ifdef NEWDB
295	}
296#endif
297}
298
299#ifdef NDBM
300static void
301praliases_dbm(filename, argc, argv)
302	char *filename;
303	int  argc;
304	char **argv;
305{
306	DBM *dbp;
307	datum content, key;
308
309	if ((dbp = dbm_open(filename, O_RDONLY, 0)) == NULL)
310	{
311		(void)fprintf(stderr,
312		    "praliases: %s: %s\n", filename, strerror(errno));
313		exit(EX_OSFILE);
314	}
315	if (!argc)
316	{
317		for (key = dbm_firstkey(dbp);
318		    key.dptr != NULL; key = dbm_nextkey(dbp))
319		{
320			content = dbm_fetch(dbp, key);
321			(void)printf("%.*s:%.*s\n",
322				(int) key.dsize, key.dptr,
323				(int) content.dsize, content.dptr);
324		}
325	}
326	else
327	{
328		for (; *argv; ++argv)
329		{
330			/*
331			**  Use the sendmail adaptive algorithm of trying
332			**  the key first without, then if needed with,
333			**  the terminating NULL byte.
334			*/
335			key.dptr = *argv;
336			key.dsize = strlen(*argv);
337			content = dbm_fetch(dbp, key);
338			if (content.dptr == NULL)
339			{
340				key.dsize++;
341				content = dbm_fetch(dbp, key);
342			}
343			if (content.dptr != NULL)
344				(void)printf("%s:%.*s\n", key.dptr,
345					(int) content.dsize, content.dptr);
346			else
347				(void)printf("%s: No such key\n", key.dptr);
348		}
349	}
350	dbm_close(dbp);
351}
352#endif
353
354#if !HASSTRERROR
355
356char *
357strerror(eno)
358	int eno;
359{
360	extern int sys_nerr;
361	extern char *sys_errlist[];
362	static char ebuf[60];
363
364	if (eno >= 0 && eno < sys_nerr)
365		return sys_errlist[eno];
366	(void) sprintf(ebuf, "Error %d", eno);
367	return ebuf;
368}
369
370#endif /* !HASSTRERROR */
371