xref: /freebsd/contrib/sendmail/praliases/praliases.c (revision daf1cffce2e07931f27c6c6998652e90df6ba87e)
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
14 static 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
20 static 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
51 extern char	*strerror __P((int));
52 #endif
53 
54 static void praliases __P((char *, int, char **));
55 #ifdef NDBM
56 static void praliases_dbm __P((char *, int, char **));
57 #endif
58 
59 int
60 main(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 
180 static void
181 praliases(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
300 static void
301 praliases_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 
356 char *
357 strerror(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