1 /* $NetBSD: mknetid.c,v 1.7 1997/11/13 18:38:26 thorpej 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.7 1997/11/13 18:38:26 thorpej 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 57 #include <rpcsvc/ypclnt.h> 58 59 #include "protos.h" 60 61 struct user { 62 char *usr_name; /* user name */ 63 int usr_uid; /* user uid */ 64 int usr_gid; /* user gid */ 65 int gid_count; /* number of gids */ 66 int gid[NGROUPS]; /* additional gids */ 67 TAILQ_ENTRY(user) read; /* links in read order */ 68 TAILQ_ENTRY(user) hash; /* links in hash order */ 69 }; 70 71 #define HASHMAX 55 72 73 void add_group __P((const char *, const char *)); 74 void add_user __P((const char *, const char *, const char *)); 75 int hashidx __P((char)); 76 int isgsep __P((char)); 77 int main __P((int, char *[])); 78 void print_hosts __P((const char *, const char *)); 79 void print_netid __P((const char *)); 80 void print_passwd_group __P((int, const char *)); 81 void read_group __P((const char *)); 82 void read_passwd __P((const char *)); 83 void usage __P((void)); 84 85 TAILQ_HEAD(user_list, user); 86 struct user_list root; 87 struct user_list hroot[HASHMAX]; 88 89 extern char *__progname; /* from crt0.o */ 90 91 int 92 main(argc, argv) 93 int argc; 94 char *argv[]; 95 { 96 char *HostFile = _PATH_HOSTS; 97 char *PasswdFile = _PATH_PASSWD; 98 char *GroupFile = _PATH_GROUP; 99 char *NetidFile = "/etc/netid"; 100 101 int qflag, ch; 102 char *domain; 103 104 TAILQ_INIT(&root); 105 for (ch = 0; ch < HASHMAX; ch++) 106 TAILQ_INIT((&hroot[ch])); 107 108 qflag = 0; 109 domain = NULL; 110 111 while ((ch = getopt(argc, argv, "d:g:h:m:p:q")) != -1) { 112 switch (ch) { 113 case 'd': 114 domain = optarg; 115 break; 116 117 case 'g': 118 GroupFile = optarg; 119 break; 120 121 case 'h': 122 HostFile = optarg; 123 break; 124 125 case 'm': 126 NetidFile = optarg; 127 break; 128 129 case 'p': 130 PasswdFile = optarg; 131 break; 132 133 case 'q': 134 qflag++; 135 break; 136 137 default: 138 usage(); 139 } 140 } 141 if (argc != optind) 142 usage(); 143 144 if (domain == NULL) 145 if (yp_get_default_domain(&domain)) 146 errx(1, "Can't get YP domain name"); 147 148 read_passwd(PasswdFile); 149 read_group(GroupFile); 150 151 print_passwd_group(qflag, domain); 152 print_hosts(HostFile, domain); 153 print_netid(NetidFile); 154 155 exit (0); 156 } 157 158 int 159 hashidx(key) 160 char key; 161 { 162 if (key < 'A') 163 return(0); 164 165 if (key <= 'Z') 166 return(1 + key - 'A'); 167 168 if (key < 'a') 169 return(27); 170 171 if (key <= 'z') 172 return(28 + key - 'a'); 173 174 return(54); 175 } 176 177 void 178 add_user(username, uid, gid) 179 const char *username, *uid, *gid; 180 { 181 struct user *u; 182 int idx; 183 184 idx = hashidx(username[0]); 185 186 u = (struct user *)malloc(sizeof(struct user)); 187 if (u == NULL) 188 err(1, "can't allocate user"); 189 memset(u, 0, sizeof(struct user)); 190 191 u->usr_name = strdup(username); 192 if (u->usr_name == NULL) 193 err(1, "can't allocate user name"); 194 195 u->usr_uid = atoi(uid); 196 u->usr_gid = atoi(gid); 197 u->gid_count = -1; 198 199 TAILQ_INSERT_TAIL(&root, u, read); 200 TAILQ_INSERT_TAIL((&hroot[idx]), u, hash); 201 } 202 203 void 204 add_group(username, gid) 205 const char *username, *gid; 206 { 207 struct user *u; 208 int g, idx; 209 210 g = atoi(gid); 211 idx = hashidx(username[0]); 212 213 for (u = hroot[idx].tqh_first; 214 u != NULL; u = u->hash.tqe_next) { 215 if (strcmp(username, u->usr_name) == 0) { 216 if (g != u->usr_gid) { 217 u->gid_count++; 218 if (u->gid_count < NGROUPS) 219 u->gid[u->gid_count] = g; 220 } 221 return; 222 } 223 } 224 } 225 226 void 227 read_passwd(fname) 228 const char *fname; 229 { 230 FILE *pfile; 231 int line_no, colon; 232 size_t len; 233 char *p, *k, *u, *g; 234 235 if ((pfile = fopen(fname, "r")) == NULL) 236 err(1, "%s", fname); 237 238 line_no = 0; 239 while ((p = read_line(pfile, &len, &line_no)) != NULL) { 240 if (len == 0) { 241 warnx("%s line %d: empty line", fname, line_no); 242 continue; 243 } 244 245 for (k = p, colon = 0; *k != '\0'; k++) 246 if (*k == ':') 247 colon++; 248 249 if (colon != 6) { 250 warnx("%s line %d: incorrect number of fields", 251 fname, line_no); 252 continue; 253 } 254 255 k = p; 256 p = strchr(p, ':'); 257 *p++ = '\0'; 258 259 /* If it's a YP entry, skip it. */ 260 if (*k == '+' || *k == '-') 261 continue; 262 263 /* terminate password */ 264 p = strchr(p, ':'); 265 *p++ = '\0'; 266 267 /* terminate uid */ 268 u = p; 269 p = strchr(p, ':'); 270 *p++ = '\0'; 271 272 /* terminate gid */ 273 g = p; 274 p = strchr(p, ':'); 275 *p++ = '\0'; 276 277 add_user(k, u, g); 278 } 279 (void)fclose(pfile); 280 } 281 282 int 283 isgsep(ch) 284 char ch; 285 { 286 287 switch (ch) { 288 case ',': 289 case ' ': 290 case '\t': 291 case '\0': 292 return (1); 293 } 294 295 return (0); 296 } 297 298 void 299 read_group(fname) 300 const char *fname; 301 { 302 FILE *gfile; 303 int line_no, colon; 304 size_t len; 305 char *p, *k, *u, *g; 306 307 if ((gfile = fopen(fname, "r")) == NULL) 308 err(1, "%s", fname); 309 310 line_no = 0; 311 while ((p = read_line(gfile, &len, &line_no)) != NULL) { 312 if (len == 0) { 313 warnx("%s line %d: empty line", fname, line_no); 314 continue; 315 } 316 317 for (k = p, colon = 0; *k != '\0'; k++) 318 if (*k == ':') 319 colon++; 320 321 if (colon != 3) { 322 warnx("%s line %d: incorrect number of fields", 323 fname, line_no); 324 continue; 325 } 326 327 /* terminate key */ 328 k = p; 329 p = strchr(p, ':'); 330 *p++ = '\0'; 331 332 if (*k == '+' || *k == '-') 333 continue; 334 335 /* terminate password */ 336 p = strchr(p, ':'); 337 *p++ = '\0'; 338 339 /* terminate gid */ 340 g = p; 341 p = strchr(p, ':'); 342 *p++ = '\0'; 343 344 /* get the group list */ 345 for (u = p; *u != '\0'; u = p) { 346 /* find separator */ 347 for (; isgsep(*p) == 0; p++) 348 ; 349 350 if (*p != '\0') { 351 *p = '\0'; 352 if (u != p) 353 add_group(u, g); 354 p++; 355 } else if (u != p) 356 add_group(u, g); 357 } 358 } 359 (void)fclose(gfile); 360 } 361 362 void 363 print_passwd_group(qflag, domain) 364 int qflag; 365 const char *domain; 366 { 367 struct user *u, *p; 368 int i; 369 370 for (u = root.tqh_first; u != NULL; u = u->read.tqe_next) { 371 for (p = root.tqh_first; p->usr_uid != u->usr_uid; 372 p = p->read.tqe_next) 373 /* empty */ ; 374 if (p != u) { 375 if (!qflag) { 376 warnx("unix.%d@%s %s", u->usr_uid, domain, 377 "multiply defined, ignoring duplicate"); 378 } 379 } else { 380 printf("unix.%d@%s %d:%d", u->usr_uid, domain, 381 u->usr_uid, u->usr_gid); 382 if (u->gid_count >= 0) 383 for (i = 0; i <= u->gid_count; i++) 384 printf(",%d", u->gid[i]); 385 printf("\n"); 386 } 387 } 388 } 389 390 void 391 print_hosts(fname, domain) 392 const char *fname, *domain; 393 { 394 FILE *hfile; 395 size_t len; 396 char *p, *k, *u; 397 398 if ((hfile = fopen(fname, "r")) == NULL) 399 err(1, "%s", fname); 400 401 while ((p = read_line(hfile, &len, NULL)) != NULL) { 402 if (len == 0 || *p == '#') 403 continue; 404 405 /* Find the key, replace trailing whitespace will <NUL> */ 406 for (k = p; *p && isspace(*p) == 0; p++) 407 ; 408 while (*p && isspace(*p)) 409 *p++ = '\0'; 410 411 /* Get first hostname. */ 412 for (u = p; *p && !isspace(*p); p++) 413 ; 414 *p = '\0'; 415 416 printf("unix.%s@%s 0:%s\n", u, domain, u); 417 } 418 (void) fclose(hfile); 419 } 420 421 void 422 print_netid(fname) 423 const char *fname; 424 { 425 FILE *mfile; 426 size_t len; 427 char *p, *k, *u; 428 429 mfile = fopen(fname, "r"); 430 if (mfile == NULL) 431 return; 432 433 while ((p = read_line(mfile, &len, NULL)) != NULL) { 434 if (len == 0 || *p == '#') 435 continue; 436 437 /* Find the key, replace trailing whitespace will <NUL> */ 438 for (k = p; *p && !isspace(*p); p++) 439 ; 440 while (*p && isspace(*p)) 441 *p++ = '\0'; 442 443 /* Get netid entry. */ 444 for (u = p; *p && !isspace(*p); p++) 445 ; 446 *p = '\0'; 447 448 printf("%s %s\n", k, u); 449 } 450 } 451 452 void 453 usage() 454 { 455 456 fprintf(stderr, "usage: %s %s\n", __progname, 457 "[-d domain] [-q] [-p passwdfile] [-g groupfile]"); 458 fprintf(stderr, " %s %s", __progname, 459 "[-g groupfile] [-h hostfile] [-m netidfile]"); 460 exit(1); 461 } 462