1/* $NetBSD: mkalias.c,v 1.17 2009/10/20 00:51:14 snj 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.17 2009/10/20 00:51:14 snj 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 55static void capitalize(char *, int); 56static int check_host(char *, char *, int, int, int); 57static void split_address(char *, int, char *, char *); 58__dead static void usage(void); 59 60static void 61split_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 97static int 98check_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 121static void 122capitalize(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 143int 144main(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 333static void 334usage(void) 335{ 336 fprintf(stderr, 337 "usage: %s [-e|-E [-d] [-u]] [-n] [-v] input [output]\n", 338 getprogname()); 339 exit(1); 340} 341