1 /* $OpenBSD: mknetid.c,v 1.22 2015/02/09 23:00:15 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 1996 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 <stdio.h> 30 #include <unistd.h> 31 #include <ctype.h> 32 #include <string.h> 33 #include <stdlib.h> 34 #include <pwd.h> 35 #include <grp.h> 36 #include <err.h> 37 #include <netdb.h> 38 #include <limits.h> 39 40 #include <rpcsvc/ypclnt.h> 41 42 struct user { 43 char *usr_name; /* user name */ 44 int usr_uid; /* user uid */ 45 int usr_gid; /* user gid */ 46 int gid_count; /* number of gids */ 47 int gid[NGROUPS_MAX]; /* additional gids */ 48 struct user *prev, *next; /* links in read order */ 49 struct user *hprev, *hnext; /* links in hash order */ 50 }; 51 52 char *HostFile = _PATH_HOSTS; 53 char *PasswdFile = _PATH_PASSWD; 54 char *MasterPasswdFile = _PATH_MASTERPASSWD; 55 char *GroupFile = _PATH_GROUP; 56 char *NetidFile = "/etc/netid"; 57 58 #define HASHMAX 55 59 60 struct user *root = NULL, *tail = NULL; 61 struct user *hroot[HASHMAX], *htail[HASHMAX]; 62 63 static int 64 read_line(FILE *fp, char *buf, int size) 65 { 66 int done = 0; 67 68 do { 69 while (fgets(buf, size, fp)) { 70 int len = strlen(buf); 71 72 done += len; 73 if (len > 1 && buf[len-2] == '\\' && 74 buf[len-1] == '\n') { 75 int ch; 76 77 buf += len - 2; 78 size -= len - 2; 79 *buf = '\n'; buf[1] = '\0'; 80 81 /* 82 * Skip leading white space on next line 83 */ 84 while ((ch = getc(fp)) != EOF && 85 isascii(ch) && isspace(ch)) 86 ; 87 (void) ungetc(ch, fp); 88 } else { 89 return done; 90 } 91 } 92 } while (size > 0 && !feof(fp)); 93 94 return done; 95 } 96 97 static int 98 hashidx(char key) 99 { 100 if (key < 'A') 101 return (0); 102 if (key <= 'Z') 103 return (1 + key - 'A'); 104 if (key < 'a') 105 return (27); 106 if (key <= 'z') 107 return (28 + key - 'a'); 108 return (54); 109 } 110 111 static void 112 add_user(char *username, char *uid, char *gid) 113 { 114 struct user *u; 115 int idx; 116 117 u = malloc(sizeof(struct user)); 118 if (u == NULL) 119 err(1, "malloc"); 120 bzero(u, sizeof(struct user)); 121 u->usr_name = strdup(username); 122 if (u->usr_name == NULL) 123 err(1, "strdup"); 124 u->usr_uid = atoi(uid); 125 u->usr_gid = atoi(gid); 126 u->gid_count = -1; 127 if (root == NULL) { 128 root = tail = u; 129 } else { 130 u->prev = tail; 131 tail->next = u; 132 tail = u; 133 } 134 idx = hashidx(username[0]); 135 if (hroot[idx] == NULL) { 136 hroot[idx] = htail[idx] = u; 137 } else { 138 u->hprev = htail[idx]; 139 htail[idx]->hnext = u; 140 htail[idx] = u; 141 } 142 } 143 144 static void 145 add_group(char *username, char *gid) 146 { 147 struct user *u; 148 int idx, g; 149 150 idx = hashidx(username[0]); 151 u = hroot[idx]; 152 g = atoi(gid); 153 154 while (u != NULL) { 155 if (strcmp(username, u->usr_name) == 0) { 156 if (g != u->usr_gid) { 157 u->gid_count++; 158 if (u->gid_count < NGROUPS_MAX) 159 u->gid[u->gid_count] = atoi(gid); 160 } 161 u = htail[idx]; 162 } 163 u = u->hnext; 164 } 165 } 166 167 static void 168 read_passwd(FILE *pfile, char *fname) 169 { 170 char line[1024], *p, *k, *u, *g; 171 int line_no = 0, len, colon; 172 173 while (read_line(pfile, line, sizeof(line))) { 174 line_no++; 175 len = strlen(line); 176 177 if (len > 0) { 178 if (line[0] == '#') 179 continue; 180 } 181 182 /* 183 * Check if we have the whole line 184 */ 185 if (line[len-1] != '\n') { 186 fprintf(stderr, "line %d in \"%s\" is too long\n", 187 line_no, fname); 188 } else { 189 line[len-1] = '\0'; 190 } 191 192 p = (char *)&line; 193 194 k = p; colon = 0; 195 while (*k != '\0') { 196 if (*k == ':') 197 colon++; 198 k++; 199 } 200 201 if (colon > 0) { 202 k = p; /* save start of key */ 203 while (*p != ':') 204 p++; /* find first "colon" */ 205 if (*p==':') 206 *p++ = '\0'; /* terminate key */ 207 if (strlen(k) == 1) { 208 if (*k == '+') 209 continue; 210 } 211 } 212 213 if (colon < 4) { 214 fprintf(stderr, "syntax error at line %d in \"%s\"\n", 215 line_no, fname); 216 continue; 217 } 218 219 while (*p != ':') 220 p++; /* find second "colon" */ 221 if (*p==':') 222 *p++ = '\0'; /* terminate passwd */ 223 u = p; 224 while (*p != ':') 225 p++; /* find third "colon" */ 226 if (*p==':') 227 *p++ = '\0'; /* terminate uid */ 228 g = p; 229 while (*p != ':') 230 p++; /* find fourth "colon" */ 231 if (*p==':') 232 *p++ = '\0'; /* terminate gid */ 233 while (*p != '\0') 234 p++; /* find end of string */ 235 236 add_user(k, u, g); 237 } 238 } 239 240 static int 241 isgsep(char ch) 242 { 243 switch (ch) { 244 case ',': 245 case ' ': 246 case '\t': 247 case '\0': 248 return (1); 249 default: 250 return (0); 251 } 252 } 253 254 static void 255 read_group(FILE *gfile, char *fname) 256 { 257 char line[2048], *p, *k, *u, *g; 258 int line_no = 0, len, colon; 259 260 while (read_line(gfile, line, sizeof(line))) { 261 line_no++; 262 len = strlen(line); 263 264 if (len > 0) { 265 if (line[0] == '#') 266 continue; 267 } 268 269 /* 270 * Check if we have the whole line 271 */ 272 if (line[len-1] != '\n') { 273 fprintf(stderr, "line %d in \"%s\" is too long\n", 274 line_no, fname); 275 } else { 276 line[len-1] = '\0'; 277 } 278 279 p = (char *)&line; 280 281 k = p; colon = 0; 282 while (*k != '\0') { 283 if (*k == ':') 284 colon++; 285 k++; 286 } 287 288 if (colon > 0) { 289 k = p; /* save start of key */ 290 while (*p != ':') 291 p++; /* find first "colon" */ 292 if (*p==':') 293 *p++ = '\0'; /* terminate key */ 294 if (strlen(k) == 1) { 295 if (*k == '+') 296 continue; 297 } 298 } 299 300 if (colon < 3) { 301 fprintf(stderr, "syntax error at line %d in \"%s\"\n", 302 line_no, fname); 303 continue; 304 } 305 306 while (*p != ':') 307 p++; /* find second "colon" */ 308 if (*p==':') 309 *p++ = '\0'; /* terminate passwd */ 310 g = p; 311 while (*p != ':') 312 p++; /* find third "colon" */ 313 if (*p==':') 314 *p++ = '\0'; /* terminate gid */ 315 316 u = p; 317 318 while (*u != '\0') { 319 while (!isgsep(*p)) 320 p++; /* find separator */ 321 if (*p != '\0') { 322 *p = '\0'; 323 if (u != p) 324 add_group(u, g); 325 p++; 326 } else { 327 if (u != p) 328 add_group(u, g); 329 } 330 u = p; 331 } 332 } 333 } 334 335 static void 336 print_passwd_group(int qflag, char *domain) 337 { 338 struct user *u, *p; 339 int i; 340 341 u = root; 342 343 while (u != NULL) { 344 p = root; 345 while (p->usr_uid != u->usr_uid) 346 p = p->next; 347 348 if (p != u) { 349 if (!qflag) { 350 fprintf(stderr, "mknetid: unix.%d@%s %s\n", 351 u->usr_uid, domain, 352 "multiply defined, other definitions ignored"); 353 } 354 } else { 355 printf("unix.%d@%s %d:%d", 356 u->usr_uid, domain, u->usr_uid, u->usr_gid); 357 if (u->gid_count >= 0) { 358 i = 0; 359 while (i <= u->gid_count) { 360 printf(",%d", u->gid[i]); 361 i++; 362 } 363 } 364 printf("\n"); 365 } 366 u = u->next; 367 } 368 } 369 370 static void 371 print_hosts(FILE *pfile, char *fname, char *domain) 372 { 373 char line[1024], *p, *u; 374 int line_no = 0, len; 375 376 while (read_line(pfile, line, sizeof(line))) { 377 line_no++; 378 len = strlen(line); 379 380 if (len > 0) { 381 if (line[0] == '#') 382 continue; 383 } 384 385 /* 386 * Check if we have the whole line 387 */ 388 if (line[len-1] != '\n') { 389 fprintf(stderr, "line %d in \"%s\" is too long\n", 390 line_no, fname); 391 } else { 392 line[len-1] = '\0'; 393 } 394 395 p = (char *)&line; 396 397 while (!isspace((unsigned char)*p)) 398 p++; /* find first "space" */ 399 while (isspace((unsigned char)*p)) 400 *p++ = '\0'; /* replace space with <NUL> */ 401 402 u = p; 403 while (p != NULL) { 404 if (*p == '\0') { 405 p = NULL; 406 } else { 407 if (!isspace((unsigned char)*p)) { 408 p++; 409 } else { 410 *p = '\0'; 411 p = NULL; 412 } 413 } 414 } 415 416 printf("unix.%s@%s 0:%s\n", u, domain, u); 417 } 418 } 419 420 static void 421 print_netid(FILE *mfile, char *fname) 422 { 423 char line[1024], *p, *k, *u; 424 int line_no = 0, len; 425 426 while (read_line(mfile, line, sizeof(line))) { 427 line_no++; 428 len = strlen(line); 429 430 if (len > 0) { 431 if (line[0] == '#') 432 continue; 433 } 434 435 /* 436 * Check if we have the whole line 437 */ 438 if (line[len-1] != '\n') { 439 fprintf(stderr, "line %d in \"%s\" is too long\n", 440 line_no, fname); 441 } else { 442 line[len-1] = '\0'; 443 } 444 445 p = (char *)&line; 446 447 k = p; /* save start of key */ 448 while (!isspace((unsigned char)*p)) 449 p++; /* find first "space" */ 450 while (isspace((unsigned char)*p)) 451 *p++ = '\0'; /* replace space with <NUL> */ 452 453 u = p; 454 while (p != NULL) { 455 if (*p == '\0') { 456 p = NULL; 457 } else { 458 if (!isspace((unsigned char)*p)) { 459 p++; 460 } else { 461 *p = '\0'; 462 p = NULL; 463 } 464 } 465 } 466 467 printf("%s %s\n", k, u); 468 } 469 } 470 471 static void 472 usage(void) 473 { 474 fprintf(stderr, "usage: mknetid [-q] [-d domain] [-g groupfile] " 475 "[-h hostfile] [-m netidfile]\n" 476 " [-P master.passwdfile] [-p passwdfile]\n"); 477 exit(1); 478 } 479 480 int 481 main(int argc, char *argv[]) 482 { 483 FILE *pfile, *gfile, *hfile, *mfile; 484 int qflag = 0, ch; 485 char *domain = NULL; 486 487 while ((ch = getopt(argc, argv, "d:g:h:m:p:P:q")) != -1) 488 switch (ch) { 489 case 'd': 490 domain = optarg; 491 break; 492 case 'g': 493 GroupFile = optarg; 494 break; 495 case 'h': 496 HostFile = optarg; 497 break; 498 case 'm': 499 NetidFile = optarg; 500 break; 501 case 'p': 502 PasswdFile = optarg; 503 break; 504 case 'P': 505 MasterPasswdFile = optarg; 506 break; 507 case 'q': 508 qflag = 1; 509 break; 510 default: 511 usage(); 512 break; 513 } 514 515 if (argc > optind) 516 usage(); 517 518 if (domain == NULL) 519 yp_get_default_domain(&domain); 520 521 pfile = fopen(PasswdFile, "r"); 522 if (pfile == NULL) 523 pfile = fopen(MasterPasswdFile, "r"); 524 if (pfile == NULL) 525 err(1, "%s", MasterPasswdFile); 526 527 gfile = fopen(GroupFile, "r"); 528 if (gfile == NULL) 529 err(1, "%s", GroupFile); 530 531 hfile = fopen(HostFile, "r"); 532 if (hfile == NULL) 533 err(1, "%s", HostFile); 534 535 mfile = fopen(NetidFile, "r"); 536 537 read_passwd(pfile, PasswdFile); 538 read_group(gfile, GroupFile); 539 540 print_passwd_group(qflag, domain); 541 print_hosts(hfile, HostFile, domain); 542 543 if (mfile != NULL) 544 print_netid(mfile, NetidFile); 545 546 return 0; 547 } 548