1 /*        $NetBSD: mkalias.c,v 1.18 2011/08/30 21:10:28 joerg 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  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 #ifndef lint
31 __RCSID("$NetBSD: mkalias.c,v 1.18 2011/08/30 21:10:28 joerg Exp $");
32 #endif
33 
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <netinet/in.h>
37 #include <arpa/nameser.h>
38 
39 #include <ctype.h>
40 #include <err.h>
41 #include <netdb.h>
42 #include <resolv.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <time.h>
47 #include <unistd.h>
48 
49 #include <rpc/rpc.h>
50 
51 #include "protos.h"
52 #include "ypdb.h"
53 #include "ypdef.h"
54 
55 static void         capitalize(char *, int);
56 static int          check_host(char *, char *, int, int, int);
57 static void         split_address(char *, int, char *, char *);
58 __dead static void  usage(void);
59 
60 static void
split_address(char * address,int len,char * user,char * host)61 split_address(char *address, int len, char *user, char *host)
62 {
63           char *c, *s, *r;
64           int  i = 0;
65 
66           if ((strchr(address, '@')) != NULL) {
67 
68                     s = user;
69 
70                     for(c = address; i < len; i++) {
71                               if (*c == '@') {
72                                         *s = '\0';
73                                         s = host;
74                               } else
75                                         *s++ = *c;
76                               c++;
77                     }
78                     *s = '\0';
79           }
80 
81           if ((r = strrchr(address, '!')) != NULL) {
82 
83                     s = host;
84 
85                     for(c = address; i < len; i++) {
86                               if (c == r) {
87                                         *s = '\0';
88                                         s = user;
89                               } else
90                                         *s++ = *c;
91                               c++;
92                     }
93                     *s = '\0';
94           }
95 }
96 
97 static int
check_host(char * address,char * host,int dflag,int uflag,int Eflag)98 check_host(char *address, char *host, int dflag, int uflag, int Eflag)
99 {
100           u_char answer[PACKETSZ];
101           int  status;
102 
103           if ((dflag && strchr(address, '@')) ||
104               (uflag && strchr(address, '!')))
105                     return(0);
106 
107           if ((_res.options & RES_INIT) == 0)
108                     res_init();
109 
110           status = res_search(host, C_IN, T_AAAA, answer, sizeof(answer));
111 
112           if (status == -1)
113                     status = res_search(host, C_IN, T_A, answer, sizeof(answer));
114 
115           if ((status == -1) && Eflag)
116                     status = res_search(host, C_IN, T_MX, answer, sizeof(answer));
117 
118           return(status == -1);
119 }
120 
121 static void
capitalize(char * name,int len)122 capitalize(char *name, int len)
123 {
124           char last = ' ';
125           char *c;
126           int  i = 0;
127 
128           for(c = name; i < len; i++) {
129                     if (*c == '.') last = '.';
130                     c++;
131           }
132 
133           i = 0;
134           if (last == '.') {
135                     for(c = name; i < len; i++) {
136                               if (last == '.')
137                                         *c = toupper((unsigned char)*c);
138                               last = *c++;
139                     }
140           }
141 }
142 
143 int
main(int argc,char * argv[])144 main(int argc, char *argv[])
145 {
146           int       eflag = 0;
147           int       dflag = 0;
148           int       nflag = 0;
149           int       sflag = 0;
150           int       uflag = 0;
151           int       vflag = 0;
152           int       Eflag = 0;
153           int       ch;
154           char      *input = NULL;
155           char      *output = NULL;
156           DBM       *db;
157           datum     key, val;
158           char      *slash;
159           DBM       *new_db = NULL;
160           static    const char template[] = "ypdbXXXXXX";
161           char      db_mapname[MAXPATHLEN], db_outfile[MAXPATHLEN];
162           int       status;
163           char      user[4096], host[4096]; /* XXX: DB bsize = 4096 in ypdb.c */
164           char      datestr[11];
165           char      myname[MAXHOSTNAMELEN];
166 
167           while ((ch = getopt(argc, argv, "Edensuv")) != -1) {
168                     switch(ch) {
169                     case 'd':
170                               dflag++;            /* Don't check DNS hostname */
171                               break;
172 
173                     case 'e':
174                               eflag++;            /* Check hostname */
175                               break;
176 
177                     case 'E':
178                               eflag++;            /* Check hostname */
179                               Eflag++;            /* .. even check MX records */
180                               break;
181 
182                     case 'n':
183                               nflag++;            /* Capitalize name parts */
184                               break;
185 
186                     case 's':
187                               sflag++;            /* Don't know... */
188                               break;
189 
190                     case 'u':
191                               uflag++;            /* Don't check UUCP hostname */
192                               break;
193 
194                     case 'v':
195                               vflag++;            /* Verbose */
196                               break;
197 
198                     default:
199                               usage();
200                     }
201           }
202 
203           if (optind == argc)
204                     usage();
205 
206           input = argv[optind++];
207           if (optind < argc)
208                     output = argv[optind++];
209           if (optind < argc)
210                     usage();
211 
212           db = ypdb_open(input);
213           if (db == NULL)
214                     err(1, "Unable to open input database `%s'", input);
215 
216           if (output != NULL) {
217                     if (strlen(output) + strlen(YPDB_SUFFIX) >
218                         (sizeof(db_outfile) + 1))
219                               warnx("file name `%s' too long", output);
220                     snprintf(db_outfile, sizeof(db_outfile),
221                                "%s%s", output, YPDB_SUFFIX);
222 
223                     slash = strrchr(output, '/');
224                     if (slash != NULL)
225                               slash[1] = 0;                           /* truncate to dir */
226                     else
227                               *output = 0;                            /* elminate */
228 
229                     /* note: output is now directory where map goes ! */
230 
231                     if (strlen(output) + strlen(template) + strlen(YPDB_SUFFIX) >
232                         (sizeof(db_mapname) - 1))
233                               errx(1, "Directory name `%s' too long", output);
234 
235                     snprintf(db_mapname, sizeof(db_mapname), "%s%s",
236                         output, template);
237 
238                     new_db = ypdb_mktemp(db_mapname);
239                     if (new_db == NULL)
240                               err(1, "Unable to open output database `%s'",
241                                   db_outfile);
242           }
243 
244           for (key = ypdb_firstkey(db);
245                key.dptr != NULL;
246                key = ypdb_nextkey(db)) {
247 
248                   val = ypdb_fetch(db, key);
249 
250                     if (val.dptr == NULL)
251                               continue;                     /* No value */
252                     if ((*key.dptr == '@') && (key.dsize == 1))
253                               continue;                     /* Sendmail token */
254                     if (strncmp(key.dptr, "YP_", 3)==0)     /* YP token */
255                               continue;
256                     if (strchr(val.dptr, ','))              /* List... */
257                               continue;
258                     if (strchr(val.dptr, '|'))              /* Pipe... */
259                               continue;
260 
261                     if (!((strchr(val.dptr, '@')) ||
262                         (strchr(val.dptr, '!'))))
263                               continue;                     /* Skip local users */
264 
265                     split_address(val.dptr, val.dsize, user, host);
266 
267                     if (eflag && check_host(val.dptr, host, dflag, uflag, Eflag)) {
268                               printf("Invalid host %s in %*.*s:%*.*s\n", host,
269                                      key.dsize, key.dsize, key.dptr,
270                                      val.dsize, val.dsize, val.dptr);
271                               continue;
272                     }
273 
274                     if (nflag)
275                               capitalize(key.dptr, key.dsize);
276 
277                     if (new_db != NULL) {
278                               status = ypdb_store(new_db, val, key, YPDB_INSERT);
279                               if (status != 0) {
280                                         printf("%s: problem storing %*.*s %*.*s\n",
281                                                getprogname(),
282                                                val.dsize, val.dsize, val.dptr,
283                                                key.dsize, key.dsize, key.dptr);
284                               }
285                     }
286 
287                     if (vflag) {
288                               printf("%*.*s --> %*.*s\n",
289                                      val.dsize, val.dsize, val.dptr,
290                                      key.dsize, key.dsize, key.dptr);
291                     }
292 
293           }
294 
295           if (new_db != NULL) {
296                     snprintf(datestr, sizeof(datestr), "%010d", (int)time(NULL));
297                     key.dptr = __UNCONST(YP_LAST_KEY);
298                     key.dsize = strlen(YP_LAST_KEY);
299                     val.dptr = datestr;
300                     val.dsize = strlen(datestr);
301                     status = ypdb_store(new_db, key, val, YPDB_INSERT);
302                     if (status != 0)
303                               warnx("problem storing %*.*s %*.*s",
304                                      key.dsize, key.dsize, key.dptr,
305                                      val.dsize, val.dsize, val.dptr);
306           }
307 
308           if (new_db != NULL) {
309                     localhostname(myname, sizeof(myname) - 1);
310                     key.dptr = __UNCONST(YP_MASTER_KEY);
311                     key.dsize = strlen(YP_MASTER_KEY);
312                     val.dptr = myname;
313                     val.dsize = strlen(myname);
314                     status = ypdb_store(new_db, key, val, YPDB_INSERT);
315                     if (status != 0)
316                               warnx("problem storing %*.*s %*.*s",
317                                      key.dsize, key.dsize, key.dptr,
318                                      val.dsize, val.dsize, val.dptr);
319           }
320 
321           ypdb_close(db);
322 
323           if (new_db != NULL) {
324                     ypdb_close(new_db);
325                     if (rename(db_mapname, db_outfile) < 0)
326                               err(1, "rename `%s' to `%s' failed", db_mapname,
327                                         db_outfile);
328           }
329 
330           exit(0);
331 }
332 
333 static void
usage(void)334 usage(void)
335 {
336           fprintf(stderr,
337                     "usage: %s [-e|-E [-d] [-u]] [-n] [-v] input [output]\n",
338                     getprogname());
339           exit(1);
340 }
341