xref: /original-bsd/old/mkpasswd/mkpasswd.c (revision 0a33e010)
1 /*
2  * Copyright (c) 1980, 1983 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1980, 1983 Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)mkpasswd.c	5.6 (Berkeley) 06/01/90";
16 #endif /* not lint */
17 
18 #include <sys/param.h>
19 #include <sys/file.h>
20 #include <ndbm.h>
21 #include <pwd.h>
22 #include <stdio.h>
23 
24 static FILE *_pw_fp;
25 static struct passwd _pw_passwd;
26 static off_t offset;
27 
28 #define	MAXLINELENGTH	1024
29 static char line[MAXLINELENGTH];
30 
31 /*
32  * Mkpasswd does two things -- use the ``arg'' file to create ``arg''.{pag,dir}
33  * for ndbm, and, if the -p flag is on, create a password file in the original
34  * format.  It doesn't use the getpwent(3) routines because it has to figure
35  * out offsets for the encrypted passwords to put in the dbm files.  One other
36  * problem is that, since the addition of shadow passwords, getpwent(3) has to
37  * use the dbm databases rather than simply scanning the actual file.  This
38  * required the addition of a flag field to the dbm database to distinguish
39  * between a record keyed by name, and one keyed by uid.
40  */
41 
42 main(argc, argv)
43 	int argc;
44 	char **argv;
45 {
46 	extern int errno, optind;
47 	register char *flag, *p, *t;
48 	register int makeold;
49 	FILE *oldfp;
50 	DBM *dp;
51 	datum key, content;
52 	int ch;
53 	char buf[8192], nbuf[50], *strerror();
54 
55 	makeold = 0;
56 	while ((ch = getopt(argc, argv, "pv")) != EOF)
57 		switch(ch) {
58 		case 'p':			/* create ``password.orig'' */
59 			makeold = 1;
60 			/* FALLTHROUGH */
61 		case 'v':			/* backward compatible */
62 			break;
63 		case '?':
64 		default:
65 			usage();
66 		}
67 	argc -= optind;
68 	argv += optind;
69 
70 	if (argc != 1)
71 		usage();
72 
73 	if (!(_pw_fp = fopen(*argv, "r"))) {
74 		(void)fprintf(stderr,
75 		    "mkpasswd: %s: can't open for reading.\n", *argv);
76 		exit(1);
77 	}
78 
79 	rmall(*argv);
80 	(void)umask(0);
81 
82 	/* open old password format file, dbm files */
83 	if (makeold) {
84 		int oldfd;
85 
86 		(void)sprintf(buf, "%s.orig", *argv);
87 		if ((oldfd = open(buf, O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0) {
88 			(void)fprintf(stderr, "mkpasswd: %s: %s\n", buf,
89 			    strerror(errno));
90 			exit(1);
91 		}
92 		if (!(oldfp = fdopen(oldfd, "w"))) {
93 			(void)fprintf(stderr, "mkpasswd: %s: fdopen failed.\n",
94 			    buf);
95 			exit(1);
96 		}
97 	}
98 	if (!(dp = dbm_open(*argv, O_WRONLY|O_CREAT|O_EXCL, 0644))) {
99 		(void)fprintf(stderr, "mkpasswd: %s: %s\n", *argv,
100 		    strerror(errno));
101 		exit(1);
102 	}
103 
104 	content.dptr = buf;
105 	while (scanpw()) {
106 		/* create dbm entry */
107 		p = buf;
108 #define	COMPACT(e)	t = e; while (*p++ = *t++);
109 		COMPACT(_pw_passwd.pw_name);
110 		(void)sprintf(nbuf, "%ld", offset);
111 		COMPACT(nbuf);
112 		bcopy((char *)&_pw_passwd.pw_uid, p, sizeof(int));
113 		p += sizeof(int);
114 		bcopy((char *)&_pw_passwd.pw_gid, p, sizeof(int));
115 		p += sizeof(int);
116 		bcopy((char *)&_pw_passwd.pw_change, p, sizeof(time_t));
117 		p += sizeof(time_t);
118 		COMPACT(_pw_passwd.pw_class);
119 		COMPACT(_pw_passwd.pw_gecos);
120 		COMPACT(_pw_passwd.pw_dir);
121 		COMPACT(_pw_passwd.pw_shell);
122 		bcopy((char *)&_pw_passwd.pw_expire, p, sizeof(time_t));
123 		p += sizeof(time_t);
124 		flag = p;
125 		*p++ = _PW_KEYBYNAME;
126 		content.dsize = p - buf;
127 #ifdef debug
128 		(void)printf("store %s, uid %d\n", _pw_passwd.pw_name,
129 		    _pw_passwd.pw_uid);
130 #endif
131 		key.dptr = _pw_passwd.pw_name;
132 		key.dsize = strlen(_pw_passwd.pw_name);
133 		if (dbm_store(dp, key, content, DBM_INSERT) < 0)
134 			goto bad;
135 		key.dptr = (char *)&_pw_passwd.pw_uid;
136 		key.dsize = sizeof(int);
137 		*flag = _PW_KEYBYUID;
138 		if (dbm_store(dp, key, content, DBM_INSERT) < 0)
139 			goto bad;
140 
141 		/* create original format password file entry */
142 		if (!makeold)
143 			continue;
144 		fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n", _pw_passwd.pw_name,
145 		    _pw_passwd.pw_uid, _pw_passwd.pw_gid, _pw_passwd.pw_gecos,
146 		    _pw_passwd.pw_dir, _pw_passwd.pw_shell);
147 	}
148 	dbm_close(dp);
149 	exit(0);
150 
151 bad:	(void)fprintf(stderr, "mkpasswd: dbm_store failed.\n");
152 	rmall(*argv);
153 	exit(1);
154 }
155 
156 rmall(fname)
157 	char *fname;
158 {
159 	register char *p;
160 	char buf[MAXPATHLEN], *strcpy();
161 
162 	for (p = strcpy(buf, fname); *p; ++p);
163 	bcopy(".pag", p, 5);
164 	(void)unlink(buf);
165 	bcopy(".dir", p, 5);
166 	(void)unlink(buf);
167 	bcopy(".orig", p, 6);
168 	(void)unlink(buf);
169 }
170 
171 usage()
172 {
173 	(void)fprintf(stderr, "usage: mkpasswd [-p] passwd_file\n");
174 	exit(1);
175 }
176 
177 /* from libc/gen/getpwent.c */
178 
179 static
180 scanpw()
181 {
182 	register char *cp;
183 	long atol(), ftell();
184 	char *bp;
185 	char *fgets(), *strsep(), *index();
186 
187 	for (;;) {
188 		offset = ftell(_pw_fp);
189 		if (!(fgets(line, sizeof(line), _pw_fp)))
190 			return(0);
191 		/* skip lines that are too big */
192 		if (!index(line, '\n')) {
193 			int ch;
194 
195 			while ((ch = getc(_pw_fp)) != '\n' && ch != EOF)
196 				;
197 			continue;
198 		}
199 		bp = line;
200 		_pw_passwd.pw_name = strsep(&bp, ":\n");
201 		_pw_passwd.pw_passwd = strsep(&bp, ":\n");
202 		offset += _pw_passwd.pw_passwd - line;
203 		if (!(cp = strsep(&bp, ":\n")))
204 			continue;
205 		_pw_passwd.pw_uid = atoi(cp);
206 		if (!(cp = strsep(&bp, ":\n")))
207 			continue;
208 		_pw_passwd.pw_gid = atoi(cp);
209 		_pw_passwd.pw_class = strsep(&bp, ":\n");
210 		if (!(cp = strsep(&bp, ":\n")))
211 			continue;
212 		_pw_passwd.pw_change = atol(cp);
213 		if (!(cp = strsep(&bp, ":\n")))
214 			continue;
215 		_pw_passwd.pw_expire = atol(cp);
216 		_pw_passwd.pw_gecos = strsep(&bp, ":\n");
217 		_pw_passwd.pw_dir = strsep(&bp, ":\n");
218 		_pw_passwd.pw_shell = strsep(&bp, ":\n");
219 		return(1);
220 	}
221 	/* NOTREACHED */
222 }
223