1*0a77b69aSchristos /* $NetBSD: mknetid.c,v 1.19 2013/10/19 17:16:38 christos Exp $ */
260aa689cSthorpej
360aa689cSthorpej /*
460aa689cSthorpej * Copyright (c) 1996 Mats O Jansson <moj@stacken.kth.se>
560aa689cSthorpej * All rights reserved.
660aa689cSthorpej *
760aa689cSthorpej * Redistribution and use in source and binary forms, with or without
860aa689cSthorpej * modification, are permitted provided that the following conditions
960aa689cSthorpej * are met:
1060aa689cSthorpej * 1. Redistributions of source code must retain the above copyright
1160aa689cSthorpej * notice, this list of conditions and the following disclaimer.
1260aa689cSthorpej * 2. Redistributions in binary form must reproduce the above copyright
1360aa689cSthorpej * notice, this list of conditions and the following disclaimer in the
1460aa689cSthorpej * documentation and/or other materials provided with the distribution.
1560aa689cSthorpej *
1660aa689cSthorpej * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
1760aa689cSthorpej * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1860aa689cSthorpej * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1960aa689cSthorpej * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
2060aa689cSthorpej * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2160aa689cSthorpej * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2260aa689cSthorpej * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2360aa689cSthorpej * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2460aa689cSthorpej * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2560aa689cSthorpej * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2660aa689cSthorpej * SUCH DAMAGE.
2760aa689cSthorpej */
2860aa689cSthorpej
292a43cbe6Slukem #include <sys/cdefs.h>
302a43cbe6Slukem #ifndef lint
31*0a77b69aSchristos __RCSID("$NetBSD: mknetid.c,v 1.19 2013/10/19 17:16:38 christos Exp $");
322a43cbe6Slukem #endif
332a43cbe6Slukem
3460aa689cSthorpej /*
3560aa689cSthorpej * Originally written by Mats O Jansson <moj@stacken.kth.se>
36cacf2d0fSgrant * Simplified a bit by Jason R. Thorpe <thorpej@NetBSD.org>
3760aa689cSthorpej */
3860aa689cSthorpej
3960aa689cSthorpej #include <sys/param.h>
4060aa689cSthorpej #include <sys/queue.h>
4160aa689cSthorpej #include <ctype.h>
4260aa689cSthorpej #include <err.h>
4360aa689cSthorpej #include <grp.h>
4460aa689cSthorpej #include <limits.h>
4560aa689cSthorpej #include <netdb.h>
4660aa689cSthorpej #include <pwd.h>
4760aa689cSthorpej #include <stdio.h>
4860aa689cSthorpej #include <string.h>
4960aa689cSthorpej #include <stdlib.h>
5060aa689cSthorpej #include <unistd.h>
5160aa689cSthorpej
523d8138fcSthorpej #include <rpcsvc/ypclnt.h>
533d8138fcSthorpej
5460aa689cSthorpej #include "protos.h"
5560aa689cSthorpej
5660aa689cSthorpej struct user {
5760aa689cSthorpej char *usr_name; /* user name */
5860aa689cSthorpej int usr_uid; /* user uid */
5960aa689cSthorpej int usr_gid; /* user gid */
6060aa689cSthorpej int gid_count; /* number of gids */
6160aa689cSthorpej int gid[NGROUPS]; /* additional gids */
6260aa689cSthorpej TAILQ_ENTRY(user) read; /* links in read order */
6360aa689cSthorpej TAILQ_ENTRY(user) hash; /* links in hash order */
6460aa689cSthorpej };
6560aa689cSthorpej
6660aa689cSthorpej #define HASHMAX 55
6760aa689cSthorpej
688583b49cSjoerg static void add_group(const char *, const char *);
698583b49cSjoerg static void add_user(const char *, const char *, const char *);
708583b49cSjoerg static int hashidx(char);
718583b49cSjoerg static int isgsep(char);
728583b49cSjoerg static void print_hosts(const char *, const char *);
738583b49cSjoerg static void print_netid(const char *);
748583b49cSjoerg static void print_passwd_group(int, const char *);
758583b49cSjoerg static void read_group(const char *);
768583b49cSjoerg static void read_passwd(const char *);
778583b49cSjoerg __dead static void usage(void);
7860aa689cSthorpej
7960aa689cSthorpej TAILQ_HEAD(user_list, user);
808583b49cSjoerg static struct user_list root;
818583b49cSjoerg static struct user_list hroot[HASHMAX];
8260aa689cSthorpej
8360aa689cSthorpej int
main(int argc,char * argv[])845c90fa67Swiz main(int argc, char *argv[])
8560aa689cSthorpej {
86d3d3aa62Slukem const char *HostFile = _PATH_HOSTS;
87d3d3aa62Slukem const char *PasswdFile = _PATH_PASSWD;
88d3d3aa62Slukem const char *GroupFile = _PATH_GROUP;
89d3d3aa62Slukem const char *NetidFile = "/etc/netid";
90f4fb444bSlukem
9160aa689cSthorpej int qflag, ch;
9260aa689cSthorpej char *domain;
9360aa689cSthorpej
9460aa689cSthorpej TAILQ_INIT(&root);
9560aa689cSthorpej for (ch = 0; ch < HASHMAX; ch++)
9660aa689cSthorpej TAILQ_INIT((&hroot[ch]));
9760aa689cSthorpej
9860aa689cSthorpej qflag = 0;
9960aa689cSthorpej domain = NULL;
10060aa689cSthorpej
10160aa689cSthorpej while ((ch = getopt(argc, argv, "d:g:h:m:p:q")) != -1) {
10260aa689cSthorpej switch (ch) {
10360aa689cSthorpej case 'd':
10460aa689cSthorpej domain = optarg;
10560aa689cSthorpej break;
10660aa689cSthorpej
10760aa689cSthorpej case 'g':
10860aa689cSthorpej GroupFile = optarg;
10960aa689cSthorpej break;
11060aa689cSthorpej
11160aa689cSthorpej case 'h':
11260aa689cSthorpej HostFile = optarg;
11360aa689cSthorpej break;
11460aa689cSthorpej
11560aa689cSthorpej case 'm':
11660aa689cSthorpej NetidFile = optarg;
11760aa689cSthorpej break;
11860aa689cSthorpej
11960aa689cSthorpej case 'p':
12060aa689cSthorpej PasswdFile = optarg;
12160aa689cSthorpej break;
12260aa689cSthorpej
12360aa689cSthorpej case 'q':
12460aa689cSthorpej qflag++;
12560aa689cSthorpej break;
12660aa689cSthorpej
12760aa689cSthorpej default:
12860aa689cSthorpej usage();
12960aa689cSthorpej }
13060aa689cSthorpej }
131f4fb444bSlukem if (argc != optind)
13260aa689cSthorpej usage();
13360aa689cSthorpej
13460aa689cSthorpej if (domain == NULL)
13560aa689cSthorpej if (yp_get_default_domain(&domain))
1366ea62c33Slukem errx(1, "Can't get YP domain name");
13760aa689cSthorpej
138f4fb444bSlukem read_passwd(PasswdFile);
139f4fb444bSlukem read_group(GroupFile);
14060aa689cSthorpej
14160aa689cSthorpej print_passwd_group(qflag, domain);
142f4fb444bSlukem print_hosts(HostFile, domain);
143f4fb444bSlukem print_netid(NetidFile);
14460aa689cSthorpej
14560aa689cSthorpej exit (0);
14660aa689cSthorpej }
14760aa689cSthorpej
1488583b49cSjoerg static int
hashidx(char key)1495c90fa67Swiz hashidx(char key)
15060aa689cSthorpej {
15160aa689cSthorpej if (key < 'A')
15260aa689cSthorpej return(0);
15360aa689cSthorpej
15460aa689cSthorpej if (key <= 'Z')
15560aa689cSthorpej return(1 + key - 'A');
15660aa689cSthorpej
15760aa689cSthorpej if (key < 'a')
15860aa689cSthorpej return(27);
15960aa689cSthorpej
16060aa689cSthorpej if (key <= 'z')
16160aa689cSthorpej return(28 + key - 'a');
16260aa689cSthorpej
16360aa689cSthorpej return(54);
16460aa689cSthorpej }
16560aa689cSthorpej
1668583b49cSjoerg static void
add_user(const char * username,const char * uid,const char * gid)1675c90fa67Swiz add_user(const char *username, const char *uid, const char *gid)
16860aa689cSthorpej {
16960aa689cSthorpej struct user *u;
17060aa689cSthorpej int idx;
17160aa689cSthorpej
17260aa689cSthorpej idx = hashidx(username[0]);
17360aa689cSthorpej
17460aa689cSthorpej u = (struct user *)malloc(sizeof(struct user));
17560aa689cSthorpej if (u == NULL)
17660aa689cSthorpej err(1, "can't allocate user");
17760aa689cSthorpej memset(u, 0, sizeof(struct user));
17860aa689cSthorpej
179f4fb444bSlukem u->usr_name = strdup(username);
18060aa689cSthorpej if (u->usr_name == NULL)
18160aa689cSthorpej err(1, "can't allocate user name");
18260aa689cSthorpej
18360aa689cSthorpej u->usr_uid = atoi(uid);
18460aa689cSthorpej u->usr_gid = atoi(gid);
18560aa689cSthorpej u->gid_count = -1;
18660aa689cSthorpej
18760aa689cSthorpej TAILQ_INSERT_TAIL(&root, u, read);
18860aa689cSthorpej TAILQ_INSERT_TAIL((&hroot[idx]), u, hash);
18960aa689cSthorpej }
19060aa689cSthorpej
1918583b49cSjoerg static void
add_group(const char * username,const char * gid)1925c90fa67Swiz add_group(const char *username, const char *gid)
19360aa689cSthorpej {
19460aa689cSthorpej struct user *u;
19560aa689cSthorpej int g, idx;
19660aa689cSthorpej
19760aa689cSthorpej g = atoi(gid);
19860aa689cSthorpej idx = hashidx(username[0]);
19960aa689cSthorpej
20060aa689cSthorpej for (u = hroot[idx].tqh_first;
20160aa689cSthorpej u != NULL; u = u->hash.tqe_next) {
20260aa689cSthorpej if (strcmp(username, u->usr_name) == 0) {
20360aa689cSthorpej if (g != u->usr_gid) {
20460aa689cSthorpej u->gid_count++;
20560aa689cSthorpej if (u->gid_count < NGROUPS)
20660aa689cSthorpej u->gid[u->gid_count] = g;
20760aa689cSthorpej }
20860aa689cSthorpej return;
20960aa689cSthorpej }
21060aa689cSthorpej }
21160aa689cSthorpej }
21260aa689cSthorpej
2138583b49cSjoerg static void
read_passwd(const char * fname)2145c90fa67Swiz read_passwd(const char *fname)
21560aa689cSthorpej {
216f4fb444bSlukem FILE *pfile;
21741dc2c91Skleink size_t line_no;
21841dc2c91Skleink int colon;
219ade3ce97Sthorpej size_t len;
220811d7dcaSlukem char *line, *p, *k, *u, *g;
22160aa689cSthorpej
222f4fb444bSlukem if ((pfile = fopen(fname, "r")) == NULL)
223f4fb444bSlukem err(1, "%s", fname);
22460aa689cSthorpej
225f4fb444bSlukem line_no = 0;
226211a72a8Slukem for (;
227811d7dcaSlukem (line = fparseln(pfile, &len, &line_no, NULL, FPARSELN_UNESCALL));
228811d7dcaSlukem free(line)) {
229f4fb444bSlukem if (len == 0) {
23041dc2c91Skleink warnx("%s line %lu: empty line", fname,
23141dc2c91Skleink (unsigned long)line_no);
23260aa689cSthorpej continue;
233f4fb444bSlukem }
23460aa689cSthorpej
235811d7dcaSlukem p = line;
23660aa689cSthorpej for (k = p, colon = 0; *k != '\0'; k++)
23760aa689cSthorpej if (*k == ':')
23860aa689cSthorpej colon++;
23960aa689cSthorpej
240f4fb444bSlukem if (colon != 6) {
24141dc2c91Skleink warnx("%s line %lu: incorrect number of fields",
24241dc2c91Skleink fname, (unsigned long)line_no);
24360aa689cSthorpej continue;
24460aa689cSthorpej }
24560aa689cSthorpej
246f4fb444bSlukem k = p;
247f4fb444bSlukem p = strchr(p, ':');
248f4fb444bSlukem *p++ = '\0';
249f4fb444bSlukem
250f4fb444bSlukem /* If it's a YP entry, skip it. */
251f4fb444bSlukem if (*k == '+' || *k == '-')
252f4fb444bSlukem continue;
253f4fb444bSlukem
25460aa689cSthorpej /* terminate password */
255f4fb444bSlukem p = strchr(p, ':');
25660aa689cSthorpej *p++ = '\0';
25760aa689cSthorpej
25860aa689cSthorpej /* terminate uid */
259f4fb444bSlukem u = p;
260f4fb444bSlukem p = strchr(p, ':');
26160aa689cSthorpej *p++ = '\0';
26260aa689cSthorpej
26360aa689cSthorpej /* terminate gid */
264f4fb444bSlukem g = p;
265f4fb444bSlukem p = strchr(p, ':');
26660aa689cSthorpej *p++ = '\0';
26760aa689cSthorpej
26860aa689cSthorpej add_user(k, u, g);
26960aa689cSthorpej }
270f4fb444bSlukem (void)fclose(pfile);
27160aa689cSthorpej }
27260aa689cSthorpej
2738583b49cSjoerg static int
isgsep(char ch)2745c90fa67Swiz isgsep(char ch)
27560aa689cSthorpej {
27660aa689cSthorpej
27760aa689cSthorpej switch (ch) {
27860aa689cSthorpej case ',':
27960aa689cSthorpej case ' ':
28060aa689cSthorpej case '\t':
28160aa689cSthorpej case '\0':
28260aa689cSthorpej return (1);
28360aa689cSthorpej }
28460aa689cSthorpej
28560aa689cSthorpej return (0);
28660aa689cSthorpej }
28760aa689cSthorpej
2888583b49cSjoerg static void
read_group(const char * fname)2895c90fa67Swiz read_group(const char *fname)
29060aa689cSthorpej {
291f4fb444bSlukem FILE *gfile;
29241dc2c91Skleink size_t line_no;
29341dc2c91Skleink int colon;
294ade3ce97Sthorpej size_t len;
295811d7dcaSlukem char *line, *p, *k, *u, *g;
29660aa689cSthorpej
297f4fb444bSlukem if ((gfile = fopen(fname, "r")) == NULL)
298f4fb444bSlukem err(1, "%s", fname);
29960aa689cSthorpej
300f4fb444bSlukem line_no = 0;
301211a72a8Slukem for (;
302811d7dcaSlukem (line = fparseln(gfile, &len, &line_no, NULL, FPARSELN_UNESCALL));
303811d7dcaSlukem free(line)) {
304f4fb444bSlukem if (len == 0) {
30541dc2c91Skleink warnx("%s line %lu: empty line", fname,
30641dc2c91Skleink (unsigned long)line_no);
30760aa689cSthorpej continue;
30860aa689cSthorpej }
30960aa689cSthorpej
310811d7dcaSlukem p = line;
31160aa689cSthorpej for (k = p, colon = 0; *k != '\0'; k++)
31260aa689cSthorpej if (*k == ':')
31360aa689cSthorpej colon++;
31460aa689cSthorpej
315f4fb444bSlukem if (colon != 3) {
31641dc2c91Skleink warnx("%s line %lu: incorrect number of fields",
31741dc2c91Skleink fname, (unsigned long)line_no);
31860aa689cSthorpej continue;
31960aa689cSthorpej }
32060aa689cSthorpej
321f4fb444bSlukem /* terminate key */
322f4fb444bSlukem k = p;
323f4fb444bSlukem p = strchr(p, ':');
324f4fb444bSlukem *p++ = '\0';
325f4fb444bSlukem
326f4fb444bSlukem if (*k == '+' || *k == '-')
327f4fb444bSlukem continue;
328f4fb444bSlukem
32960aa689cSthorpej /* terminate password */
330f4fb444bSlukem p = strchr(p, ':');
33160aa689cSthorpej *p++ = '\0';
33260aa689cSthorpej
33360aa689cSthorpej /* terminate gid */
334f4fb444bSlukem g = p;
335f4fb444bSlukem p = strchr(p, ':');
33660aa689cSthorpej *p++ = '\0';
33760aa689cSthorpej
33860aa689cSthorpej /* get the group list */
33960aa689cSthorpej for (u = p; *u != '\0'; u = p) {
34060aa689cSthorpej /* find separator */
341f4fb444bSlukem for (; isgsep(*p) == 0; p++)
342f4fb444bSlukem ;
34360aa689cSthorpej
34460aa689cSthorpej if (*p != '\0') {
34560aa689cSthorpej *p = '\0';
34660aa689cSthorpej if (u != p)
34760aa689cSthorpej add_group(u, g);
34860aa689cSthorpej p++;
34960aa689cSthorpej } else if (u != p)
35060aa689cSthorpej add_group(u, g);
35160aa689cSthorpej }
35260aa689cSthorpej }
353f4fb444bSlukem (void)fclose(gfile);
35460aa689cSthorpej }
35560aa689cSthorpej
3568583b49cSjoerg static void
print_passwd_group(int qflag,const char * domain)3575c90fa67Swiz print_passwd_group(int qflag, const char *domain)
35860aa689cSthorpej {
35960aa689cSthorpej struct user *u, *p;
36060aa689cSthorpej int i;
36160aa689cSthorpej
36260aa689cSthorpej for (u = root.tqh_first; u != NULL; u = u->read.tqe_next) {
36360aa689cSthorpej for (p = root.tqh_first; p->usr_uid != u->usr_uid;
36460aa689cSthorpej p = p->read.tqe_next)
36560aa689cSthorpej /* empty */ ;
36660aa689cSthorpej if (p != u) {
36760aa689cSthorpej if (!qflag) {
36860aa689cSthorpej warnx("unix.%d@%s %s", u->usr_uid, domain,
36960aa689cSthorpej "multiply defined, ignoring duplicate");
37060aa689cSthorpej }
37160aa689cSthorpej } else {
37260aa689cSthorpej printf("unix.%d@%s %d:%d", u->usr_uid, domain,
37360aa689cSthorpej u->usr_uid, u->usr_gid);
37460aa689cSthorpej if (u->gid_count >= 0)
37560aa689cSthorpej for (i = 0; i <= u->gid_count; i++)
37660aa689cSthorpej printf(",%d", u->gid[i]);
37760aa689cSthorpej printf("\n");
37860aa689cSthorpej }
37960aa689cSthorpej }
38060aa689cSthorpej }
38160aa689cSthorpej
3828583b49cSjoerg static void
print_hosts(const char * fname,const char * domain)3835c90fa67Swiz print_hosts(const char *fname, const char *domain)
38460aa689cSthorpej {
385f4fb444bSlukem FILE *hfile;
386ade3ce97Sthorpej size_t len;
387*0a77b69aSchristos char *line, *p, *u;
38860aa689cSthorpej
389f4fb444bSlukem if ((hfile = fopen(fname, "r")) == NULL)
390f4fb444bSlukem err(1, "%s", fname);
39160aa689cSthorpej
392211a72a8Slukem for (;
393811d7dcaSlukem (line = fparseln(hfile, &len, NULL, NULL, FPARSELN_UNESCALL));
394811d7dcaSlukem free(line)) {
395211a72a8Slukem if (len == 0)
39660aa689cSthorpej continue;
39760aa689cSthorpej
398811d7dcaSlukem p = line;
39960aa689cSthorpej /* Find the key, replace trailing whitespace will <NUL> */
400*0a77b69aSchristos for (; *p && isspace((unsigned char)*p) == 0; p++)
401f4fb444bSlukem ;
4023cca093eSdsl while (*p && isspace((unsigned char)*p))
40360aa689cSthorpej *p++ = '\0';
40460aa689cSthorpej
40560aa689cSthorpej /* Get first hostname. */
4063cca093eSdsl for (u = p; *p && !isspace((unsigned char)*p); p++)
407f4fb444bSlukem ;
40860aa689cSthorpej *p = '\0';
40960aa689cSthorpej
41060aa689cSthorpej printf("unix.%s@%s 0:%s\n", u, domain, u);
41160aa689cSthorpej }
412f4fb444bSlukem (void) fclose(hfile);
41360aa689cSthorpej }
41460aa689cSthorpej
4158583b49cSjoerg static void
print_netid(const char * fname)4165c90fa67Swiz print_netid(const char *fname)
41760aa689cSthorpej {
418f4fb444bSlukem FILE *mfile;
419ade3ce97Sthorpej size_t len;
420811d7dcaSlukem char *line, *p, *k, *u;
42160aa689cSthorpej
422f4fb444bSlukem mfile = fopen(fname, "r");
423f4fb444bSlukem if (mfile == NULL)
424f4fb444bSlukem return;
42560aa689cSthorpej
426211a72a8Slukem for (;
427811d7dcaSlukem (line = fparseln(mfile, &len, NULL, NULL, FPARSELN_UNESCALL));
428811d7dcaSlukem free(line)) {
429211a72a8Slukem if (len == 0)
43060aa689cSthorpej continue;
43160aa689cSthorpej
432811d7dcaSlukem p = line;
43360aa689cSthorpej /* Find the key, replace trailing whitespace will <NUL> */
4343cca093eSdsl for (k = p; *p && !isspace((unsigned char)*p); p++)
435f4fb444bSlukem ;
4363cca093eSdsl while (*p && isspace((unsigned char)*p))
43760aa689cSthorpej *p++ = '\0';
43860aa689cSthorpej
43960aa689cSthorpej /* Get netid entry. */
4403cca093eSdsl for (u = p; *p && !isspace((unsigned char)*p); p++)
441f4fb444bSlukem ;
44260aa689cSthorpej *p = '\0';
44360aa689cSthorpej
44460aa689cSthorpej printf("%s %s\n", k, u);
44560aa689cSthorpej }
44660aa689cSthorpej }
44760aa689cSthorpej
4488583b49cSjoerg static void
usage(void)4495c90fa67Swiz usage(void)
45060aa689cSthorpej {
45160aa689cSthorpej
45225bdbb66Scgd fprintf(stderr, "usage: %s %s\n", getprogname(),
45360aa689cSthorpej "[-d domain] [-q] [-p passwdfile] [-g groupfile]");
45425bdbb66Scgd fprintf(stderr, " %s %s", getprogname(),
45560aa689cSthorpej "[-g groupfile] [-h hostfile] [-m netidfile]");
4563d8138fcSthorpej exit(1);
45760aa689cSthorpej }
458