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