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