1 /* $NetBSD: mknetid.c,v 1.11 2001/02/19 23:22:51 cgd 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 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Mats O Jansson 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 22 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 #ifndef lint 36 __RCSID("$NetBSD: mknetid.c,v 1.11 2001/02/19 23:22:51 cgd Exp $"); 37 #endif 38 39 /* 40 * Originally written by Mats O Jansson <moj@stacken.kth.se> 41 * Simplified a bit by Jason R. Thorpe <thorpej@NetBSD.ORG> 42 */ 43 44 #include <sys/param.h> 45 #include <sys/queue.h> 46 #include <ctype.h> 47 #include <err.h> 48 #include <grp.h> 49 #include <limits.h> 50 #include <netdb.h> 51 #include <pwd.h> 52 #include <stdio.h> 53 #include <string.h> 54 #include <stdlib.h> 55 #include <unistd.h> 56 #include <util.h> 57 58 #include <rpcsvc/ypclnt.h> 59 60 #include "protos.h" 61 62 struct user { 63 char *usr_name; /* user name */ 64 int usr_uid; /* user uid */ 65 int usr_gid; /* user gid */ 66 int gid_count; /* number of gids */ 67 int gid[NGROUPS]; /* additional gids */ 68 TAILQ_ENTRY(user) read; /* links in read order */ 69 TAILQ_ENTRY(user) hash; /* links in hash order */ 70 }; 71 72 #define HASHMAX 55 73 74 void add_group __P((const char *, const char *)); 75 void add_user __P((const char *, const char *, const char *)); 76 int hashidx __P((char)); 77 int isgsep __P((char)); 78 int main __P((int, char *[])); 79 void print_hosts __P((const char *, const char *)); 80 void print_netid __P((const char *)); 81 void print_passwd_group __P((int, const char *)); 82 void read_group __P((const char *)); 83 void read_passwd __P((const char *)); 84 void usage __P((void)); 85 86 TAILQ_HEAD(user_list, user); 87 struct user_list root; 88 struct user_list hroot[HASHMAX]; 89 90 int 91 main(argc, argv) 92 int argc; 93 char *argv[]; 94 { 95 char *HostFile = _PATH_HOSTS; 96 char *PasswdFile = _PATH_PASSWD; 97 char *GroupFile = _PATH_GROUP; 98 char *NetidFile = "/etc/netid"; 99 100 int qflag, ch; 101 char *domain; 102 103 TAILQ_INIT(&root); 104 for (ch = 0; ch < HASHMAX; ch++) 105 TAILQ_INIT((&hroot[ch])); 106 107 qflag = 0; 108 domain = NULL; 109 110 while ((ch = getopt(argc, argv, "d:g:h:m:p:q")) != -1) { 111 switch (ch) { 112 case 'd': 113 domain = optarg; 114 break; 115 116 case 'g': 117 GroupFile = optarg; 118 break; 119 120 case 'h': 121 HostFile = optarg; 122 break; 123 124 case 'm': 125 NetidFile = optarg; 126 break; 127 128 case 'p': 129 PasswdFile = optarg; 130 break; 131 132 case 'q': 133 qflag++; 134 break; 135 136 default: 137 usage(); 138 } 139 } 140 if (argc != optind) 141 usage(); 142 143 if (domain == NULL) 144 if (yp_get_default_domain(&domain)) 145 errx(1, "Can't get YP domain name"); 146 147 read_passwd(PasswdFile); 148 read_group(GroupFile); 149 150 print_passwd_group(qflag, domain); 151 print_hosts(HostFile, domain); 152 print_netid(NetidFile); 153 154 exit (0); 155 } 156 157 int 158 hashidx(key) 159 char key; 160 { 161 if (key < 'A') 162 return(0); 163 164 if (key <= 'Z') 165 return(1 + key - 'A'); 166 167 if (key < 'a') 168 return(27); 169 170 if (key <= 'z') 171 return(28 + key - 'a'); 172 173 return(54); 174 } 175 176 void 177 add_user(username, uid, gid) 178 const char *username, *uid, *gid; 179 { 180 struct user *u; 181 int idx; 182 183 idx = hashidx(username[0]); 184 185 u = (struct user *)malloc(sizeof(struct user)); 186 if (u == NULL) 187 err(1, "can't allocate user"); 188 memset(u, 0, sizeof(struct user)); 189 190 u->usr_name = strdup(username); 191 if (u->usr_name == NULL) 192 err(1, "can't allocate user name"); 193 194 u->usr_uid = atoi(uid); 195 u->usr_gid = atoi(gid); 196 u->gid_count = -1; 197 198 TAILQ_INSERT_TAIL(&root, u, read); 199 TAILQ_INSERT_TAIL((&hroot[idx]), u, hash); 200 } 201 202 void 203 add_group(username, gid) 204 const char *username, *gid; 205 { 206 struct user *u; 207 int g, idx; 208 209 g = atoi(gid); 210 idx = hashidx(username[0]); 211 212 for (u = hroot[idx].tqh_first; 213 u != NULL; u = u->hash.tqe_next) { 214 if (strcmp(username, u->usr_name) == 0) { 215 if (g != u->usr_gid) { 216 u->gid_count++; 217 if (u->gid_count < NGROUPS) 218 u->gid[u->gid_count] = g; 219 } 220 return; 221 } 222 } 223 } 224 225 void 226 read_passwd(fname) 227 const char *fname; 228 { 229 FILE *pfile; 230 size_t line_no; 231 int colon; 232 size_t len; 233 char *line, *p, *k, *u, *g; 234 235 if ((pfile = fopen(fname, "r")) == NULL) 236 err(1, "%s", fname); 237 238 line_no = 0; 239 for (; 240 (line = fparseln(pfile, &len, &line_no, NULL, FPARSELN_UNESCALL)); 241 free(line)) { 242 if (len == 0) { 243 warnx("%s line %lu: empty line", fname, 244 (unsigned long)line_no); 245 continue; 246 } 247 248 p = line; 249 for (k = p, colon = 0; *k != '\0'; k++) 250 if (*k == ':') 251 colon++; 252 253 if (colon != 6) { 254 warnx("%s line %lu: incorrect number of fields", 255 fname, (unsigned long)line_no); 256 continue; 257 } 258 259 k = p; 260 p = strchr(p, ':'); 261 *p++ = '\0'; 262 263 /* If it's a YP entry, skip it. */ 264 if (*k == '+' || *k == '-') 265 continue; 266 267 /* terminate password */ 268 p = strchr(p, ':'); 269 *p++ = '\0'; 270 271 /* terminate uid */ 272 u = p; 273 p = strchr(p, ':'); 274 *p++ = '\0'; 275 276 /* terminate gid */ 277 g = p; 278 p = strchr(p, ':'); 279 *p++ = '\0'; 280 281 add_user(k, u, g); 282 } 283 (void)fclose(pfile); 284 } 285 286 int 287 isgsep(ch) 288 char ch; 289 { 290 291 switch (ch) { 292 case ',': 293 case ' ': 294 case '\t': 295 case '\0': 296 return (1); 297 } 298 299 return (0); 300 } 301 302 void 303 read_group(fname) 304 const char *fname; 305 { 306 FILE *gfile; 307 size_t line_no; 308 int colon; 309 size_t len; 310 char *line, *p, *k, *u, *g; 311 312 if ((gfile = fopen(fname, "r")) == NULL) 313 err(1, "%s", fname); 314 315 line_no = 0; 316 for (; 317 (line = fparseln(gfile, &len, &line_no, NULL, FPARSELN_UNESCALL)); 318 free(line)) { 319 if (len == 0) { 320 warnx("%s line %lu: empty line", fname, 321 (unsigned long)line_no); 322 continue; 323 } 324 325 p = line; 326 for (k = p, colon = 0; *k != '\0'; k++) 327 if (*k == ':') 328 colon++; 329 330 if (colon != 3) { 331 warnx("%s line %lu: incorrect number of fields", 332 fname, (unsigned long)line_no); 333 continue; 334 } 335 336 /* terminate key */ 337 k = p; 338 p = strchr(p, ':'); 339 *p++ = '\0'; 340 341 if (*k == '+' || *k == '-') 342 continue; 343 344 /* terminate password */ 345 p = strchr(p, ':'); 346 *p++ = '\0'; 347 348 /* terminate gid */ 349 g = p; 350 p = strchr(p, ':'); 351 *p++ = '\0'; 352 353 /* get the group list */ 354 for (u = p; *u != '\0'; u = p) { 355 /* find separator */ 356 for (; isgsep(*p) == 0; p++) 357 ; 358 359 if (*p != '\0') { 360 *p = '\0'; 361 if (u != p) 362 add_group(u, g); 363 p++; 364 } else if (u != p) 365 add_group(u, g); 366 } 367 } 368 (void)fclose(gfile); 369 } 370 371 void 372 print_passwd_group(qflag, domain) 373 int qflag; 374 const char *domain; 375 { 376 struct user *u, *p; 377 int i; 378 379 for (u = root.tqh_first; u != NULL; u = u->read.tqe_next) { 380 for (p = root.tqh_first; p->usr_uid != u->usr_uid; 381 p = p->read.tqe_next) 382 /* empty */ ; 383 if (p != u) { 384 if (!qflag) { 385 warnx("unix.%d@%s %s", u->usr_uid, domain, 386 "multiply defined, ignoring duplicate"); 387 } 388 } else { 389 printf("unix.%d@%s %d:%d", u->usr_uid, domain, 390 u->usr_uid, u->usr_gid); 391 if (u->gid_count >= 0) 392 for (i = 0; i <= u->gid_count; i++) 393 printf(",%d", u->gid[i]); 394 printf("\n"); 395 } 396 } 397 } 398 399 void 400 print_hosts(fname, domain) 401 const char *fname, *domain; 402 { 403 FILE *hfile; 404 size_t len; 405 char *line, *p, *k, *u; 406 407 if ((hfile = fopen(fname, "r")) == NULL) 408 err(1, "%s", fname); 409 410 for (; 411 (line = fparseln(hfile, &len, NULL, NULL, FPARSELN_UNESCALL)); 412 free(line)) { 413 if (len == 0) 414 continue; 415 416 p = line; 417 /* Find the key, replace trailing whitespace will <NUL> */ 418 for (k = p; *p && isspace(*p) == 0; p++) 419 ; 420 while (*p && isspace(*p)) 421 *p++ = '\0'; 422 423 /* Get first hostname. */ 424 for (u = p; *p && !isspace(*p); p++) 425 ; 426 *p = '\0'; 427 428 printf("unix.%s@%s 0:%s\n", u, domain, u); 429 } 430 (void) fclose(hfile); 431 } 432 433 void 434 print_netid(fname) 435 const char *fname; 436 { 437 FILE *mfile; 438 size_t len; 439 char *line, *p, *k, *u; 440 441 mfile = fopen(fname, "r"); 442 if (mfile == NULL) 443 return; 444 445 for (; 446 (line = fparseln(mfile, &len, NULL, NULL, FPARSELN_UNESCALL)); 447 free(line)) { 448 if (len == 0) 449 continue; 450 451 p = line; 452 /* Find the key, replace trailing whitespace will <NUL> */ 453 for (k = p; *p && !isspace(*p); p++) 454 ; 455 while (*p && isspace(*p)) 456 *p++ = '\0'; 457 458 /* Get netid entry. */ 459 for (u = p; *p && !isspace(*p); p++) 460 ; 461 *p = '\0'; 462 463 printf("%s %s\n", k, u); 464 } 465 } 466 467 void 468 usage() 469 { 470 471 fprintf(stderr, "usage: %s %s\n", getprogname(), 472 "[-d domain] [-q] [-p passwdfile] [-g groupfile]"); 473 fprintf(stderr, " %s %s", getprogname(), 474 "[-g groupfile] [-h hostfile] [-m netidfile]"); 475 exit(1); 476 } 477