xref: /openbsd-src/usr.sbin/ypserv/mkalias/mkalias.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: mkalias.c,v 1.6 2001/02/05 14:47:17 deraadt Exp $ */
2 
3 /*
4  * Copyright (c) 1997 Mats O Jansson <moj@stacken.kth.se>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by Mats O Jansson
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
22  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
25  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef LINT
35 static char rcsid[] = "$OpenBSD: mkalias.c,v 1.6 2001/02/05 14:47:17 deraadt Exp $";
36 #endif
37 
38 #include <ctype.h>
39 #include <fcntl.h>
40 #include <netdb.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <sys/param.h>
45 #include <sys/types.h>
46 #include <netinet/in.h>
47 #include <arpa/nameser.h>
48 #include <resolv.h>
49 #include "ypdb.h"
50 #include "ypdef.h"
51 
52 extern char *__progname;		/* from crt0.o */
53 
54 void
55 split_address(address, len, user, host)
56 char *address;
57 int    len;
58 char  *user, *host;
59 {
60 	char *c,*s,*r;
61 	int  i = 0;
62 
63 	if (index(address,'@')) {
64 
65 		s = user;
66 
67 		for(c = address; i < len; i++) {
68 			if (*c == '@') {
69 				*s = '\0';
70 				s = host;
71 			} else {
72 				*s++ = *c;
73 			}
74 			c++;
75 		}
76 		*s = '\0';
77 
78 	}
79 
80 	if (r = rindex(address,'!')) {
81 
82 		s = host;
83 
84 		for(c = address; i < len; i++) {
85 			if (c == r) {
86 				*s = '\0';
87 				s = user;
88 			} else {
89 				*s++ = *c;
90 			}
91 			c++;
92 		}
93 		*s = '\0';
94 
95 	}
96 
97 }
98 
99 int
100 check_host(address, host, dflag, uflag, Eflag)
101 char *address, *host;
102 int   dflag, uflag, Eflag;
103 {
104 	char answer[PACKETSZ];
105 	int  status;
106 
107 	if ((dflag && index(address,'@')) ||
108 	    (uflag && index(address,'!'))) return(0);
109 
110 	if ((_res.options & RES_INIT) == 0)
111 		res_init();
112 
113 	status = res_search(host, C_IN, T_AAAA, answer, sizeof(answer));
114 
115 	if (status == -1)
116 		status = res_search(host, C_IN, T_A, answer, sizeof(answer));
117 
118 	if ((status == -1) && Eflag)
119 		status = res_search(host, C_IN, T_MX, answer, sizeof(answer));
120 
121 	return(status == -1);
122 }
123 
124 void
125 capitalize(name,len)
126 char *name;
127 int len;
128 {
129 	char last = ' ';
130 	char *c;
131 	int  i = 0;
132 
133 	for(c = name; i < len; i++) {
134 		if (*c == '.') last = '.';
135 		c++;
136 	}
137 
138 	i = 0;
139 	if (last == '.') {
140 		for(c = name; i < len; i++) {
141 			if (last == '.') {
142 				*c = toupper(*c);
143 			}
144 			last = *c++;
145 		}
146 	}
147 
148 }
149 
150 int
151 main (argc,argv)
152 int argc;
153 char *argv[];
154 {
155 	int	usage = 0;
156 	int	eflag = 0;
157 	int	dflag = 0;
158 	int	nflag = 0;
159 	int	sflag = 0;
160 	int	uflag = 0;
161 	int	vflag = 0;
162 	int	Eflag = 0;
163 	int	ch, fd;
164 	char	*input = NULL;
165 	char	*output = NULL;
166 	DBM	*db;
167 	datum	key,val;
168 	char	*slash;
169 	DBM	*new_db = NULL;
170 	static	char mapname[] = "ypdbXXXXXXXXXX";
171 	char	db_mapname[MAXPATHLEN],db_outfile[MAXPATHLEN],
172 		db_tempname[MAXPATHLEN];
173 	int	status;
174 	char	user[4096],host[4096]; /* XXX: DB bsize = 4096 in ypdb.c */
175 	char	datestr[11];
176 	char	myname[MAXHOSTNAMELEN];
177 
178 	while ((ch = getopt(argc, argv, "Edensuv")) != -1)
179 		switch(ch) {
180 		case 'E':
181 			eflag++;	/* Check hostname */
182 			Eflag++;	/* .. even check MX records */
183 			break;
184 		case 'd':
185 			dflag++;	/* Don't check DNS hostname */
186 			break;
187 		case 'e':
188 			eflag++;	/* Check hostname */
189 			break;
190 		case 'n':
191 			nflag++;	/* Capitalize name parts */
192 			break;
193 		case 's':
194 			sflag++;	/* Don't know... */
195 			break;
196 		case 'u':
197 			uflag++;	/* Don't check UUCP hostname */
198 			break;
199 		case 'v':
200 			vflag++;	/* Verbose */
201 			break;
202 		default:
203 			usage++;
204 			break;
205 		}
206 
207 	if (optind == argc) {
208 		usage++;
209 	} else {
210 		input = argv[optind++];
211 		if (optind < argc)
212 			output = argv[optind++];
213 		if (optind < argc)
214 			usage++;
215 	}
216 
217 	if (usage) {
218 		fprintf(stderr,
219 			"usage: %s [-v] [-e|-E [-d] [-u]] [-n] input [output]\n",
220 			__progname);
221 		exit(1);
222 	}
223 
224 	db = ypdb_open(input, O_RDONLY, 0444);
225 	if (db == NULL) {
226 		fprintf(stderr,
227 			"%s: Unable to open input database %s\n",
228 			__progname,
229 			input);
230 		exit(1);
231 	}
232 
233 	if (output != NULL) {
234 		if (strlen(output) + strlen(YPDB_SUFFIX) > MAXPATHLEN) {
235 			fprintf(stderr,"%s: %s: file name too long\n",
236 			        __progname, output);
237 		}
238 		snprintf(db_outfile, sizeof(db_outfile),
239 			 "%s%s", output, YPDB_SUFFIX);
240 
241 		slash = strrchr(output, '/');
242 		if (slash != NULL)
243 			slash[1] = 0; 			/* truncate to dir */
244 		else
245 			*output = 0;			/* elminate */
246 
247 		/* note: output is now directory where map goes ! */
248 
249 		if (strlen(output) + strlen(mapname)
250 				+ strlen(YPDB_SUFFIX) > MAXPATHLEN) {
251 			fprintf(stderr,"%s: %s: directory name too long\n",
252 				__progname, output);
253 			exit(1);
254 		}
255 
256 		snprintf(db_tempname, sizeof(db_tempname), "%s%s", output,
257 			mapname);
258 		fd = mkstemp(db_tempname);
259 		if (fd == -1)
260 			goto fail;
261 		close(fd);
262 
263 		snprintf(db_mapname, sizeof(db_mapname), "%s%s", db_tempname,
264 			YPDB_SUFFIX);
265 		new_db = ypdb_open(db_tempname, O_RDWR|O_CREAT, 0444);
266 		if (new_db == NULL) {
267 fail:
268 			if (fd != -1)
269 				unlink(db_tempname);
270 			fprintf(stderr,
271 				"%s: Unable to open output database %s\n",
272 				__progname,
273 				db_outfile);
274 			exit(1);
275 		}
276 	}
277 
278 	for (key = ypdb_firstkey(db);
279 	     key.dptr != NULL;
280 	     key = ypdb_nextkey(db)) {
281 
282 	        val = ypdb_fetch(db,key);
283 
284 		if (val.dptr == NULL) continue;		/* No value */
285 		if ((*key.dptr == '@') && (key.dsize == 1))
286 			continue;			/* Sendmail token */
287 		if (strncmp(key.dptr, "YP_", 3)==0)	/* YP token */
288 			continue;
289 		if (index(val.dptr,',')) continue;	/* List... */
290 		if (index(val.dptr,'|')) continue;	/* Pipe... */
291 
292 		if (!((index(val.dptr,'@')) ||
293 		      (index(val.dptr,'!')))) continue;	/* Skip local users */
294 
295 		split_address(val.dptr,val.dsize,user,host);
296 
297 		if (eflag && check_host(val.dptr, host, dflag, uflag, Eflag)) {
298 			printf("Invalid host %s in %*.*s:%*.*s\n",
299 			       host,
300 			       key.dsize, key.dsize, key.dptr,
301 			       val.dsize, val.dsize, val.dptr);
302 			continue;
303 		}
304 
305 		if (nflag) {
306 			capitalize(key.dptr,key.dsize);
307 		}
308 
309 		if (new_db != NULL) {
310 			status = ypdb_store(new_db, val, key, YPDB_INSERT);
311 			if (status != 0) {
312 				printf("%s: problem storing %*.*s %*.*s\n",
313 				       __progname,
314 				       val.dsize, val.dsize, val.dptr,
315 				       key.dsize, key.dsize, key.dptr);
316 			}
317 		}
318 
319 		if (vflag) {
320 			printf("%*.*s --> %*.*s\n",
321 			       val.dsize, val.dsize, val.dptr,
322 			       key.dsize, key.dsize, key.dptr);
323 		}
324 
325 	}
326 
327 	if (new_db != NULL) {
328 	  	snprintf(datestr, sizeof datestr, "%010u", time(NULL));
329 		key.dptr = YP_LAST_KEY;
330 		key.dsize = strlen(YP_LAST_KEY);
331 		val.dptr = datestr;
332 		val.dsize = strlen(datestr);
333 		status = ypdb_store(new_db, key, val, YPDB_INSERT);
334 		if (status != 0) {
335 			printf("%s: problem storing %*.*s %*.*s\n",
336 			       __progname,
337 			       key.dsize, key.dsize, key.dptr,
338 			       val.dsize, val.dsize, val.dptr);
339 		}
340 	}
341 
342 	if (new_db != NULL) {
343 	  	gethostname(myname, sizeof(myname));
344 		key.dptr = YP_MASTER_KEY;
345 		key.dsize = strlen(YP_MASTER_KEY);
346 		val.dptr = myname;
347 		val.dsize = strlen(myname);
348 		status = ypdb_store(new_db, key, val, YPDB_INSERT);
349 		if (status != 0) {
350 			printf("%s: problem storing %*.*s %*.*s\n",
351 			       __progname,
352 			       key.dsize, key.dsize, key.dptr,
353 			       val.dsize, val.dsize, val.dptr);
354 		}
355 	}
356 
357 
358 
359 	ypdb_close(db);
360 
361 	if (new_db != NULL) {
362 		ypdb_close(new_db);
363 		if (rename(db_mapname,db_outfile) < 0) {
364 			perror("rename");
365 			fprintf(stderr,"rename %s -> %s failed!\n", db_mapname,
366 				db_outfile);
367 			exit(1);
368 		}
369 	}
370 
371 	return(0);
372 
373 }
374