1 /* $OpenBSD: mkalias.c,v 1.21 2007/09/04 14:37:53 fgsch 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 #ifndef lint 30 static const char rcsid[] = "$OpenBSD: mkalias.c,v 1.21 2007/09/04 14:37:53 fgsch Exp $"; 31 #endif 32 33 #include <ctype.h> 34 #include <fcntl.h> 35 #include <netdb.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <unistd.h> 40 #include <sys/param.h> 41 #include <sys/types.h> 42 #include <netinet/in.h> 43 #include <arpa/nameser.h> 44 #include <resolv.h> 45 #include <err.h> 46 #include "ypdb.h" 47 #include "ypdef.h" 48 49 static void 50 split_address(char *address, size_t len, char *user, char *host) 51 { 52 char *c, *s, *r; 53 int i = 0; 54 55 if (memchr(address, '@', len)) { 56 s = user; 57 for (c = address; i < len; i++) { 58 if (*c == '@') { 59 *s = '\0'; 60 s = host; 61 } else { 62 *s++ = *c; 63 } 64 c++; 65 } 66 *s = '\0'; 67 } 68 69 if ((r = memrchr(address, '!', len))) { 70 s = host; 71 for (c = address; i < len; i++) { 72 if (c == r) { 73 *s = '\0'; 74 s = user; 75 } else { 76 *s++ = *c; 77 } 78 c++; 79 } 80 *s = '\0'; 81 } 82 } 83 84 static int 85 check_host(char *address, size_t len, char *host, int dflag, int uflag, int Eflag) 86 { 87 u_char answer[PACKETSZ]; 88 int status; 89 90 if ((dflag && memchr(address, '@', len)) || 91 (uflag && memchr(address, '!', len))) 92 return(0); 93 94 if ((_res.options & RES_INIT) == 0) 95 res_init(); 96 97 status = res_search(host, C_IN, T_AAAA, answer, sizeof(answer)); 98 99 if (status == -1) 100 status = res_search(host, C_IN, T_A, answer, sizeof(answer)); 101 102 if (status == -1 && Eflag) 103 status = res_search(host, C_IN, T_MX, answer, sizeof(answer)); 104 105 return(status == -1); 106 } 107 108 static void 109 capitalize(char *name, int len) 110 { 111 char last = ' '; 112 char *c; 113 int i = 0; 114 115 for (c = name; i < len; i++) { 116 if (*c == '.') 117 last = '.'; 118 c++; 119 } 120 121 i = 0; 122 if (last == '.') { 123 for (c = name; i < len; i++) { 124 if (last == '.') 125 *c = (char)toupper(*c); 126 last = *c++; 127 } 128 } 129 } 130 131 static void 132 usage(void) 133 { 134 fprintf(stderr, 135 "usage: mkalias [-v] [-e|-E [-d] [-u]] [-n] input [output]\n"); 136 exit(1); 137 } 138 139 int 140 main(int argc, char *argv[]) 141 { 142 int eflag = 0, dflag = 0, nflag = 0, sflag = 0; 143 int uflag = 0, vflag = 0, Eflag = 0; 144 int status, ch, fd; 145 char *input = NULL, *output = NULL; 146 DBM *db; 147 datum key, val; 148 DBM *new_db = NULL; 149 static char mapname[] = "ypdbXXXXXXXXXX"; 150 char db_mapname[MAXPATHLEN], db_outfile[MAXPATHLEN]; 151 char db_tempname[MAXPATHLEN]; 152 char user[4096], host[4096]; /* XXX: DB bsize = 4096 in ypdb.c */ 153 char myname[MAXHOSTNAMELEN], datestr[11], *slash; 154 155 while ((ch = getopt(argc, argv, "Edensuv")) != -1) 156 switch (ch) { 157 case 'E': 158 eflag++; /* Check hostname */ 159 Eflag++; /* .. even check MX records */ 160 break; 161 case 'd': 162 dflag++; /* Don't check DNS hostname */ 163 break; 164 case 'e': 165 eflag++; /* Check hostname */ 166 break; 167 case 'n': 168 nflag++; /* Capitalize name parts */ 169 break; 170 case 's': 171 sflag++; /* Don't know... */ 172 break; 173 case 'u': 174 uflag++; /* Don't check UUCP hostname */ 175 break; 176 case 'v': 177 vflag++; /* Verbose */ 178 break; 179 default: 180 usage(); 181 break; 182 } 183 184 if (optind == argc) 185 usage(); 186 187 input = argv[optind++]; 188 if (optind < argc) 189 output = argv[optind++]; 190 if (optind < argc) 191 usage(); 192 193 db = ypdb_open(input, O_RDONLY, 0444); 194 if (db == NULL) { 195 err(1, "Unable to open input database %s", input); 196 /* NOTREACHED */ 197 } 198 199 if (output != NULL) { 200 if (strlen(output) + strlen(YPDB_SUFFIX) > MAXPATHLEN) { 201 errx(1, "%s: file name too long", output); 202 /* NOTREACHED */ 203 } 204 205 snprintf(db_outfile, sizeof(db_outfile), 206 "%s%s", output, YPDB_SUFFIX); 207 208 slash = strrchr(output, '/'); 209 if (slash != NULL) 210 slash[1] = 0; /* truncate to dir */ 211 else 212 *output = 0; /* eliminate */ 213 214 /* note: output is now directory where map goes ! */ 215 216 if (strlen(output) + strlen(mapname) + 217 strlen(YPDB_SUFFIX) > MAXPATHLEN) { 218 errx(1, "%s: directory name too long", output); 219 /* NOTREACHED */ 220 } 221 222 snprintf(db_tempname, sizeof(db_tempname), "%s%s%s", output, 223 mapname, YPDB_SUFFIX); 224 fd = mkstemps(db_tempname, 3); 225 if (fd == -1) 226 goto fail; 227 close(fd); 228 229 strncpy(db_mapname, db_tempname, strlen(db_tempname) - 3); 230 db_mapname[sizeof(db_mapname) - 1] = '\0'; 231 232 new_db = ypdb_open(db_mapname, O_RDWR|O_TRUNC, 0444); 233 if (new_db == NULL) { 234 fail: 235 if (fd != -1) 236 unlink(db_tempname); 237 err(1, "Unable to open output database %s", 238 db_outfile); 239 /* NOTREACHED */ 240 } 241 } 242 243 for (key = ypdb_firstkey(db); key.dptr != NULL; 244 key = ypdb_nextkey(db)) { 245 val = ypdb_fetch(db, key); 246 247 if (val.dptr == NULL) 248 continue; /* No value */ 249 if (*key.dptr == '@' && key.dsize == 1) 250 continue; /* Sendmail token */ 251 if (strncmp(key.dptr, "YP_", 3)==0) /* YP token */ 252 continue; 253 if (memchr(val.dptr, ',', val.dsize)) 254 continue; /* List... */ 255 if (memchr(val.dptr, '|', val.dsize)) 256 continue; /* Pipe... */ 257 258 if (!(memchr(val.dptr, '@', val.dsize) || 259 memchr(val.dptr, '!', val.dsize))) 260 continue; /* Skip local users */ 261 262 split_address(val.dptr, val.dsize, user, host); 263 264 if (eflag && check_host(val.dptr, val.dsize, host, dflag, uflag, Eflag)) { 265 warnx("Invalid host %s in %*.*s:%*.*s", 266 host, key.dsize, key.dsize, key.dptr, 267 val.dsize, val.dsize, val.dptr); 268 continue; 269 } 270 271 if (nflag) 272 capitalize(key.dptr, key.dsize); 273 274 if (new_db != NULL) { 275 status = ypdb_store(new_db, val, key, YPDB_INSERT); 276 if (status != 0) { 277 warnx("problem storing %*.*s %*.*s", 278 val.dsize, val.dsize, val.dptr, 279 key.dsize, key.dsize, key.dptr); 280 } 281 } 282 283 if (vflag) { 284 printf("%*.*s --> %*.*s\n", 285 val.dsize, val.dsize, val.dptr, 286 key.dsize, key.dsize, key.dptr); 287 } 288 289 } 290 291 if (new_db != NULL) { 292 snprintf(datestr, sizeof datestr, "%010u", time(NULL)); 293 key.dptr = YP_LAST_KEY; 294 key.dsize = strlen(YP_LAST_KEY); 295 val.dptr = datestr; 296 val.dsize = strlen(datestr); 297 status = ypdb_store(new_db, key, val, YPDB_INSERT); 298 if (status != 0) { 299 warnx("problem storing %*.*s %*.*s", 300 key.dsize, key.dsize, key.dptr, 301 val.dsize, val.dsize, val.dptr); 302 } 303 } 304 305 if (new_db != NULL) { 306 gethostname(myname, sizeof(myname)); 307 key.dptr = YP_MASTER_KEY; 308 key.dsize = strlen(YP_MASTER_KEY); 309 val.dptr = myname; 310 val.dsize = strlen(myname); 311 status = ypdb_store(new_db, key, val, YPDB_INSERT); 312 if (status != 0) { 313 warnx("problem storing %*.*s %*.*s", 314 key.dsize, key.dsize, key.dptr, 315 val.dsize, val.dsize, val.dptr); 316 } 317 } 318 319 ypdb_close(db); 320 321 if (new_db != NULL) { 322 ypdb_close(new_db); 323 if (rename(db_tempname, db_outfile) < 0) { 324 err(1, "rename %s -> %s failed", db_tempname, 325 db_outfile); 326 /* NOTREACHED */ 327 } 328 } 329 return(0); 330 } 331