#include <stdio.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <pwd.h>
#include <grp.h>
#include <err.h>
#include <netdb.h>
#include <limits.h>
#include <rpcsvc/ypclnt.h>
struct user {
char *usr_name;
int usr_uid;
int usr_gid;
int gid_count;
int gid[NGROUPS_MAX];
struct user *prev, *next;
struct user *hprev, *hnext;
};
char *HostFile = _PATH_HOSTS;
char *PasswdFile = _PATH_PASSWD;
char *MasterPasswdFile = _PATH_MASTERPASSWD;
char *GroupFile = _PATH_GROUP;
char *NetidFile = "/etc/netid";
#define HASHMAX 55
struct user *root = NULL, *tail = NULL;
struct user *hroot[HASHMAX], *htail[HASHMAX];
static int
read_line(FILE *fp, char *buf, int size)
{
int done = 0;
do {
while (fgets(buf, size, fp)) {
int len = strlen(buf);
done += len;
if (len > 1 && buf[len-2] == '\\' &&
buf[len-1] == '\n') {
int ch;
buf += len - 2;
size -= len - 2;
*buf = '\n'; buf[1] = '\0';
while ((ch = getc(fp)) != EOF &&
isascii(ch) && isspace(ch))
;
(void) ungetc(ch, fp);
} else {
return done;
}
}
} while (size > 0 && !feof(fp));
return done;
}
static int
hashidx(char key)
{
if (key < 'A')
return (0);
if (key <= 'Z')
return (1 + key - 'A');
if (key < 'a')
return (27);
if (key <= 'z')
return (28 + key - 'a');
return (54);
}
static void
add_user(char *username, char *uid, char *gid)
{
struct user *u;
int idx;
u = malloc(sizeof(struct user));
if (u == NULL)
err(1, "malloc");
bzero(u, sizeof(struct user));
u->usr_name = strdup(username);
if (u->usr_name == NULL)
err(1, "strdup");
u->usr_uid = atoi(uid);
u->usr_gid = atoi(gid);
u->gid_count = -1;
if (root == NULL) {
root = tail = u;
} else {
u->prev = tail;
tail->next = u;
tail = u;
}
idx = hashidx(username[0]);
if (hroot[idx] == NULL) {
hroot[idx] = htail[idx] = u;
} else {
u->hprev = htail[idx];
htail[idx]->hnext = u;
htail[idx] = u;
}
}
static void
add_group(char *username, char *gid)
{
struct user *u;
int idx, g;
idx = hashidx(username[0]);
u = hroot[idx];
g = atoi(gid);
while (u != NULL) {
if (strcmp(username, u->usr_name) == 0) {
if (g != u->usr_gid) {
u->gid_count++;
if (u->gid_count < NGROUPS_MAX)
u->gid[u->gid_count] = atoi(gid);
}
u = htail[idx];
}
u = u->hnext;
}
}
static void
read_passwd(FILE *pfile, char *fname)
{
char line[1024], *p, *k, *u, *g;
int line_no = 0, len, colon;
while (read_line(pfile, line, sizeof(line))) {
line_no++;
len = strlen(line);
if (len > 0) {
if (line[0] == '#')
continue;
}
if (line[len-1] != '\n') {
fprintf(stderr, "line %d in \"%s\" is too long\n",
line_no, fname);
} else {
line[len-1] = '\0';
}
p = (char *)&line;
k = p; colon = 0;
while (*k != '\0') {
if (*k == ':')
colon++;
k++;
}
if (colon > 0) {
k = p;
while (*p != ':')
p++;
if (*p==':')
*p++ = '\0';
if (strlen(k) == 1) {
if (*k == '+')
continue;
}
}
if (colon < 4) {
fprintf(stderr, "syntax error at line %d in \"%s\"\n",
line_no, fname);
continue;
}
while (*p != ':')
p++;
if (*p==':')
*p++ = '\0';
u = p;
while (*p != ':')
p++;
if (*p==':')
*p++ = '\0';
g = p;
while (*p != ':')
p++;
if (*p==':')
*p++ = '\0';
while (*p != '\0')
p++;
add_user(k, u, g);
}
}
static int
isgsep(char ch)
{
switch (ch) {
case ',':
case ' ':
case '\t':
case '\0':
return (1);
default:
return (0);
}
}
static void
read_group(FILE *gfile, char *fname)
{
char line[2048], *p, *k, *u, *g;
int line_no = 0, len, colon;
while (read_line(gfile, line, sizeof(line))) {
line_no++;
len = strlen(line);
if (len > 0) {
if (line[0] == '#')
continue;
}
if (line[len-1] != '\n') {
fprintf(stderr, "line %d in \"%s\" is too long\n",
line_no, fname);
} else {
line[len-1] = '\0';
}
p = (char *)&line;
k = p; colon = 0;
while (*k != '\0') {
if (*k == ':')
colon++;
k++;
}
if (colon > 0) {
k = p;
while (*p != ':')
p++;
if (*p==':')
*p++ = '\0';
if (strlen(k) == 1) {
if (*k == '+')
continue;
}
}
if (colon < 3) {
fprintf(stderr, "syntax error at line %d in \"%s\"\n",
line_no, fname);
continue;
}
while (*p != ':')
p++;
if (*p==':')
*p++ = '\0';
g = p;
while (*p != ':')
p++;
if (*p==':')
*p++ = '\0';
u = p;
while (*u != '\0') {
while (!isgsep(*p))
p++;
if (*p != '\0') {
*p = '\0';
if (u != p)
add_group(u, g);
p++;
} else {
if (u != p)
add_group(u, g);
}
u = p;
}
}
}
static void
print_passwd_group(int qflag, char *domain)
{
struct user *u, *p;
int i;
u = root;
while (u != NULL) {
p = root;
while (p->usr_uid != u->usr_uid)
p = p->next;
if (p != u) {
if (!qflag) {
fprintf(stderr, "mknetid: unix.%d@%s %s\n",
u->usr_uid, domain,
"multiply defined, other definitions ignored");
}
} else {
printf("unix.%d@%s %d:%d",
u->usr_uid, domain, u->usr_uid, u->usr_gid);
if (u->gid_count >= 0) {
i = 0;
while (i <= u->gid_count) {
printf(",%d", u->gid[i]);
i++;
}
}
printf("\n");
}
u = u->next;
}
}
static void
print_hosts(FILE *pfile, char *fname, char *domain)
{
char line[1024], *p, *u;
int line_no = 0, len;
while (read_line(pfile, line, sizeof(line))) {
line_no++;
len = strlen(line);
if (len > 0) {
if (line[0] == '#')
continue;
}
if (line[len-1] != '\n') {
fprintf(stderr, "line %d in \"%s\" is too long\n",
line_no, fname);
} else {
line[len-1] = '\0';
}
p = (char *)&line;
while (!isspace((unsigned char)*p))
p++;
while (isspace((unsigned char)*p))
*p++ = '\0';
u = p;
while (p != NULL) {
if (*p == '\0') {
p = NULL;
} else {
if (!isspace((unsigned char)*p)) {
p++;
} else {
*p = '\0';
p = NULL;
}
}
}
printf("unix.%s@%s 0:%s\n", u, domain, u);
}
}
static void
print_netid(FILE *mfile, char *fname)
{
char line[1024], *p, *k, *u;
int line_no = 0, len;
while (read_line(mfile, line, sizeof(line))) {
line_no++;
len = strlen(line);
if (len > 0) {
if (line[0] == '#')
continue;
}
if (line[len-1] != '\n') {
fprintf(stderr, "line %d in \"%s\" is too long\n",
line_no, fname);
} else {
line[len-1] = '\0';
}
p = (char *)&line;
k = p;
while (!isspace((unsigned char)*p))
p++;
while (isspace((unsigned char)*p))
*p++ = '\0';
u = p;
while (p != NULL) {
if (*p == '\0') {
p = NULL;
} else {
if (!isspace((unsigned char)*p)) {
p++;
} else {
*p = '\0';
p = NULL;
}
}
}
printf("%s %s\n", k, u);
}
}
static void
usage(void)
{
fprintf(stderr, "usage: mknetid [-q] [-d domain] [-g groupfile] "
"[-h hostfile] [-m netidfile]\n"
" [-P master.passwdfile] [-p passwdfile]\n");
exit(1);
}
int
main(int argc, char *argv[])
{
FILE *pfile, *gfile, *hfile, *mfile;
int qflag = 0, ch;
char *domain = NULL;
while ((ch = getopt(argc, argv, "d:g:h:m:p:P:q")) != -1)
switch (ch) {
case 'd':
domain = optarg;
break;
case 'g':
GroupFile = optarg;
break;
case 'h':
HostFile = optarg;
break;
case 'm':
NetidFile = optarg;
break;
case 'p':
PasswdFile = optarg;
break;
case 'P':
MasterPasswdFile = optarg;
break;
case 'q':
qflag = 1;
break;
default:
usage();
break;
}
if (argc > optind)
usage();
if (domain == NULL)
yp_get_default_domain(&domain);
pfile = fopen(PasswdFile, "r");
if (pfile == NULL)
pfile = fopen(MasterPasswdFile, "r");
if (pfile == NULL)
err(1, "%s", MasterPasswdFile);
gfile = fopen(GroupFile, "r");
if (gfile == NULL)
err(1, "%s", GroupFile);
hfile = fopen(HostFile, "r");
if (hfile == NULL)
err(1, "%s", HostFile);
mfile = fopen(NetidFile, "r");
read_passwd(pfile, PasswdFile);
read_group(gfile, GroupFile);
print_passwd_group(qflag, domain);
print_hosts(hfile, HostFile, domain);
if (mfile != NULL)
print_netid(mfile, NetidFile);
return 0;
}