1 /*- 2 * SPDX-License-Identifier: BSD-4-Clause 3 * 4 * Copyright (c) 1995, 1996 5 * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul. 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 #include <err.h> 37 #include <fcntl.h> 38 #include <limits.h> 39 #include <stdint.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <time.h> 44 #include <unistd.h> 45 #include <rpc/rpc.h> 46 #include <rpcsvc/yp.h> 47 #include <sys/param.h> 48 #include <sys/types.h> 49 #include <sys/stat.h> 50 #include "yp_extern.h" 51 #include "ypxfr_extern.h" 52 53 char *yp_dir = ""; /* No particular default needed. */ 54 int debug = 1; 55 56 static void 57 usage(void) 58 { 59 fprintf(stderr, "%s\n%s\n%s\n%s\n", 60 "usage: yp_mkdb -c", 61 " yp_mkdb -u dbname", 62 " yp_mkdb [-c] [-b] [-s] [-f] [-i inputfile] [-o outputfile]", 63 " [-d domainname ] [-m mastername] inputfile dbname"); 64 exit(1); 65 } 66 67 #define PERM_SECURE (S_IRUSR|S_IWUSR) 68 static DB * 69 open_db(char *path, int flags) 70 { 71 extern HASHINFO openinfo; 72 73 return(dbopen(path, flags, PERM_SECURE, DB_HASH, &openinfo)); 74 } 75 76 static void 77 unwind(char *map) 78 { 79 DB *dbp; 80 DBT key, data; 81 82 dbp = open_db(map, O_RDONLY); 83 84 if (dbp == NULL) 85 err(1, "open_db(%s) failed", map); 86 87 key.data = NULL; 88 while (yp_next_record(dbp, &key, &data, 1, 1) == YP_TRUE) 89 printf("%.*s %.*s\n", (int)key.size, (char *)key.data, 90 (int)data.size, (char *)data.data); 91 92 (void)(dbp->close)(dbp); 93 } 94 95 int 96 main(int argc, char *argv[]) 97 { 98 int ch; 99 int un = 0; 100 int clear = 0; 101 int filter_plusminus = 0; 102 char *infile = NULL; 103 char *map = NULL; 104 char *domain = NULL; 105 char *infilename = NULL; 106 char *outfilename = NULL; 107 char *mastername = NULL; 108 int interdom = 0; 109 int secure = 0; 110 DB *dbp; 111 DBT key, data; 112 char buf[10240]; 113 char *keybuf, *datbuf; 114 FILE *ifp; 115 char hname[MAXHOSTNAMELEN + 2]; 116 117 while ((ch = getopt(argc, argv, "uhcbsfd:i:o:m:")) != -1) { 118 switch (ch) { 119 case 'f': 120 filter_plusminus++; 121 break; 122 case 'u': 123 un++; 124 break; 125 case 'c': 126 clear++; 127 break; 128 case 'b': 129 interdom++; 130 break; 131 case 's': 132 secure++; 133 break; 134 case 'd': 135 domain = optarg; 136 break; 137 case 'i': 138 infilename = optarg; 139 break; 140 case 'o': 141 outfilename = optarg; 142 break; 143 case 'm': 144 mastername = optarg; 145 break; 146 case 'h': 147 default: 148 usage(); 149 break; 150 } 151 } 152 153 argc -= optind; 154 argv += optind; 155 156 if (un) { 157 map = argv[0]; 158 if (map == NULL) 159 usage(); 160 unwind(map); 161 exit(0); 162 163 } 164 165 infile = argv[0]; 166 map = argv[1]; 167 168 if (infile == NULL || map == NULL) { 169 if (clear) 170 goto doclear; 171 usage(); 172 } 173 174 if (mastername == NULL) { 175 if (gethostname((char *)&hname, sizeof(hname)) == -1) 176 err(1, "gethostname() failed"); 177 mastername = (char *)&hname; 178 } 179 180 /* 181 * Note that while we can read from stdin, we can't 182 * write to stdout; the db library doesn't let you 183 * write to a file stream like that. 184 */ 185 if (!strcmp(infile, "-")) { 186 ifp = stdin; 187 } else { 188 if ((ifp = fopen(infile, "r")) == NULL) 189 err(1, "failed to open %s", infile); 190 } 191 192 if ((dbp = open_db(map, O_RDWR|O_EXLOCK|O_EXCL|O_CREAT)) == NULL) 193 err(1, "open_db(%s) failed", map); 194 195 if (interdom) { 196 key.data = "YP_INTERDOMAIN"; 197 key.size = sizeof("YP_INTERDOMAIN") - 1; 198 data.data = ""; 199 data.size = 0; 200 yp_put_record(dbp, &key, &data, 0); 201 } 202 203 if (secure) { 204 key.data = "YP_SECURE"; 205 key.size = sizeof("YP_SECURE") - 1; 206 data.data = ""; 207 data.size = 0; 208 yp_put_record(dbp, &key, &data, 0); 209 } 210 211 key.data = "YP_MASTER_NAME"; 212 key.size = sizeof("YP_MASTER_NAME") - 1; 213 data.data = mastername; 214 data.size = strlen(mastername); 215 yp_put_record(dbp, &key, &data, 0); 216 217 key.data = "YP_LAST_MODIFIED"; 218 key.size = sizeof("YP_LAST_MODIFIED") - 1; 219 snprintf(buf, sizeof(buf), "%jd", (intmax_t)time(NULL)); 220 data.data = (char *)&buf; 221 data.size = strlen(buf); 222 yp_put_record(dbp, &key, &data, 0); 223 224 if (infilename) { 225 key.data = "YP_INPUT_FILE"; 226 key.size = sizeof("YP_INPUT_FILE") - 1; 227 data.data = infilename; 228 data.size = strlen(infilename); 229 yp_put_record(dbp, &key, &data, 0); 230 } 231 232 if (outfilename) { 233 key.data = "YP_OUTPUT_FILE"; 234 key.size = sizeof("YP_OUTPUT_FILE") - 1; 235 data.data = outfilename; 236 data.size = strlen(outfilename); 237 yp_put_record(dbp, &key, &data, 0); 238 } 239 240 if (domain) { 241 key.data = "YP_DOMAIN_NAME"; 242 key.size = sizeof("YP_DOMAIN_NAME") - 1; 243 data.data = domain; 244 data.size = strlen(domain); 245 yp_put_record(dbp, &key, &data, 0); 246 } 247 248 while (fgets((char *)&buf, sizeof(buf), ifp)) { 249 char *sep = NULL; 250 int rval; 251 252 /* NUL terminate */ 253 if ((sep = strchr(buf, '\n'))) 254 *sep = '\0'; 255 256 /* handle backslash line continuations */ 257 while (buf[strlen(buf) - 1] == '\\') { 258 fgets((char *)&buf[strlen(buf) - 1], 259 sizeof(buf) - strlen(buf), ifp); 260 if ((sep = strchr(buf, '\n'))) 261 *sep = '\0'; 262 } 263 264 /* find the separation between the key and data */ 265 if ((sep = strpbrk(buf, " \t")) == NULL) { 266 warnx("bad input -- no white space: %s", buf); 267 continue; 268 } 269 270 /* separate the strings */ 271 keybuf = (char *)&buf; 272 datbuf = sep + 1; 273 *sep = '\0'; 274 275 /* set datbuf to start at first non-whitespace character */ 276 while (*datbuf == ' ' || *datbuf == '\t') 277 datbuf++; 278 279 /* Check for silliness. */ 280 if (filter_plusminus) { 281 if (*keybuf == '+' || *keybuf == '-' || 282 *datbuf == '+' || *datbuf == '-') { 283 warnx("bad character at " 284 "start of line: %s", buf); 285 continue; 286 } 287 } 288 289 if (strlen(keybuf) > YPMAXRECORD) { 290 warnx("key too long: %s", keybuf); 291 continue; 292 } 293 294 if (!strlen(keybuf)) { 295 warnx("no key -- check source file for blank lines"); 296 continue; 297 } 298 299 if (strlen(datbuf) > YPMAXRECORD) { 300 warnx("data too long: %s", datbuf); 301 continue; 302 } 303 304 key.data = keybuf; 305 key.size = strlen(keybuf); 306 data.data = datbuf; 307 data.size = strlen(datbuf); 308 309 if ((rval = yp_put_record(dbp, &key, &data, 0)) != YP_TRUE) { 310 switch (rval) { 311 case YP_FALSE: 312 warnx("duplicate key '%s' - skipping", keybuf); 313 break; 314 case YP_BADDB: 315 default: 316 err(1,"failed to write new record - exiting"); 317 break; 318 } 319 } 320 321 } 322 323 (void)(dbp->close)(dbp); 324 325 doclear: 326 if (clear) { 327 char in = 0; 328 char *out = NULL; 329 int stat; 330 if ((stat = callrpc("localhost", YPPROG,YPVERS, YPPROC_CLEAR, 331 (xdrproc_t)xdr_void, &in, 332 (xdrproc_t)xdr_void, out)) != RPC_SUCCESS) { 333 warnx("failed to send 'clear' to local ypserv: %s", 334 clnt_sperrno((enum clnt_stat) stat)); 335 } 336 } 337 338 exit(0); 339 } 340