]> git.saurik.com Git - apple/network_cmds.git/blob - rpc_yppasswdd.tproj/yppasswdd_mkpw.c
network_cmds-245.1.3.tar.gz
[apple/network_cmds.git] / rpc_yppasswdd.tproj / yppasswdd_mkpw.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /* $OpenBSD: yppasswdd_mkpw.c,v 1.16 1997/11/17 23:56:20 gene Exp $ */
24
25 /*
26 * Copyright (c) 1994 Mats O Jansson <moj@stacken.kth.se>
27 * All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by Mats O Jansson
40 * 4. The name of the author may not be used to endorse or promote products
41 * derived from this software without specific prior written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
44 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
45 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
47 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
54 */
55
56 #ifndef LINT
57 static char rcsid[] = "$OpenBSD: yppasswdd_mkpw.c,v 1.16 1997/11/17 23:56:20 gene Exp $";
58 #endif
59
60 #include <sys/param.h>
61 #include <sys/types.h>
62 #include <sys/stat.h>
63 #include <stdio.h>
64 #include <fcntl.h>
65 #include <rpc/rpc.h>
66 #include <rpcsvc/yppasswd.h>
67 #include <db.h>
68 #include <pwd.h>
69 #include <stdlib.h>
70 #include <unistd.h>
71 #include <util.h>
72 #include <ctype.h>
73 #include <string.h>
74 #include <syslog.h>
75 #include <err.h>
76
77 extern int noshell;
78 extern int nogecos;
79 extern int nopw;
80 extern int make;
81 extern char make_arg[];
82
83 static void _pw_copy(int, int, struct passwd *);
84
85 /* This is imported from OpenBSD's libutil because it's argument
86 * incompatible with NetBSD's. However, the NetBSD libutil is
87 * at least what the prototypes suggest is in System.framework,
88 * even though I can't find the code. I assume it will be there
89 * eventually. We need to use NetBSD's because it works with the
90 * pwd_mkdb binary that's shipped with Rhapsody. This is an area
91 * where OpenBSD diverges; however, we wanted to keep the OpenBSD
92 * rpc.yppasswdd because the rest of our YP code is from OpenBSD.
93 * What a mess.
94 */
95 static void
96 _pw_copy(ffd, tfd, pw)
97 int ffd, tfd;
98 struct passwd *pw;
99 {
100 FILE *from, *to;
101 int done;
102 char *p, buf[8192];
103
104 if (!(from = fdopen(ffd, "r")))
105 pw_error(_PATH_MASTERPASSWD, 1, 1);
106 if (!(to = fdopen(tfd, "w")))
107 pw_error(_PATH_MASTERPASSWD_LOCK, 1, 1);
108
109 for (done = 0; fgets(buf, sizeof(buf), from);) {
110 if (!strchr(buf, '\n')) {
111 warnx("%s: line too long", _PATH_MASTERPASSWD);
112 pw_error(NULL, 0, 1);
113 }
114 if (done) {
115 (void)fprintf(to, "%s", buf);
116 if (ferror(to))
117 goto err;
118 continue;
119 }
120 if (!(p = strchr(buf, ':'))) {
121 warnx("%s: corrupted entry", _PATH_MASTERPASSWD);
122 pw_error(NULL, 0, 1);
123 }
124 *p = '\0';
125 if (strcmp(buf, pw->pw_name)) {
126 *p = ':';
127 (void)fprintf(to, "%s", buf);
128 if (ferror(to))
129 goto err;
130 continue;
131 }
132 (void)fprintf(to, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
133 pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid,
134 pw->pw_class, pw->pw_change, pw->pw_expire, pw->pw_gecos,
135 pw->pw_dir, pw->pw_shell);
136 done = 1;
137 if (ferror(to))
138 goto err;
139 }
140 if (!done)
141 (void)fprintf(to, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
142 pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid,
143 pw->pw_class, pw->pw_change, pw->pw_expire, pw->pw_gecos,
144 pw->pw_dir, pw->pw_shell);
145
146 if (ferror(to))
147 err:
148 pw_error(NULL, 0, 1);
149 (void)fclose(to);
150 }
151
152
153 int
154 badchars(base)
155 char *base;
156 {
157 int ampr = 0;
158 char *s;
159
160 for (s = base; *s; s++) {
161 if (*s == '&')
162 ampr++;
163 if (!isprint(*s))
164 return 1;
165 if (strchr(":\n\t\r", *s))
166 return 1;
167 }
168 if (ampr > 10)
169 return 1;
170 return 0;
171 }
172
173 int
174 subst(s, from, to)
175 char *s;
176 char from, to;
177 {
178 int n = 0;
179
180 while (*s) {
181 if (*s == from) {
182 *s = to;
183 n++;
184 }
185 s++;
186 }
187 return (n);
188 }
189
190 int
191 make_passwd(argp)
192 yppasswd *argp;
193 {
194 struct passwd pw;
195 int pfd, tfd;
196 char buf[10], *bp = NULL, *p, *t;
197 int n;
198 ssize_t cnt;
199 size_t resid;
200 struct stat st;
201
202 pw_init();
203 pfd = open(_PATH_MASTERPASSWD, O_RDONLY);
204 if (pfd < 0)
205 goto fail;
206 if (fstat(pfd, &st))
207 goto fail;
208 p = bp = malloc((resid = st.st_size) + 1);
209 do {
210 cnt = read(pfd, p, resid);
211 if (cnt < 0)
212 goto fail;
213 p += cnt;
214 resid -= cnt;
215 } while (resid > 0);
216 close(pfd);
217 pfd = -1;
218 *p = '\0'; /* Buf oflow prevention */
219
220 p = bp;
221 subst(p, '\n', '\0');
222 for (n = 1; p < bp + st.st_size; n++, p = t) {
223 t = strchr(p, '\0') + 1;
224 /* Rhapsody allows the passwd file to have comments in it. */
225 if (p[0] == '#') {
226 continue;
227 }
228 cnt = subst(p, ':', '\0');
229 if (cnt != 9) {
230 syslog(LOG_WARNING, "bad entry at line %d of %s", n,
231 _PATH_MASTERPASSWD);
232 continue;
233 }
234
235 if (strcmp(p, argp->newpw.pw_name) == 0)
236 break;
237 }
238 if (p >= bp + st.st_size)
239 goto fail;
240
241 #define EXPAND(e) e = p; while (*p++);
242 EXPAND(pw.pw_name);
243 EXPAND(pw.pw_passwd);
244 pw.pw_uid = atoi(p); EXPAND(t);
245 pw.pw_gid = atoi(p); EXPAND(t);
246 EXPAND(pw.pw_class);
247 pw.pw_change = (time_t)atol(p); EXPAND(t);
248 pw.pw_expire = (time_t)atol(p); EXPAND(t);
249 EXPAND(pw.pw_gecos);
250 EXPAND(pw.pw_dir);
251 EXPAND(pw.pw_shell);
252
253 /* crypt() is broken under Rhapsody. It doesn't deal with
254 * empty keys or salts like other Unices.
255 */
256 if (pw.pw_passwd[0] != '\0' && argp->oldpass != NULL && argp->oldpass[0] != '\0') {
257 if (strcmp(crypt(argp->oldpass, pw.pw_passwd), pw.pw_passwd) != 0)
258 goto fail;
259 }
260
261 if (!nopw && badchars(argp->newpw.pw_passwd))
262 goto fail;
263 if (!nogecos && badchars(argp->newpw.pw_gecos))
264 goto fail;
265 if (!nogecos && badchars(argp->newpw.pw_shell))
266 goto fail;
267
268 /*
269 * Get the new password. Reset passwd change time to zero; when
270 * classes are implemented, go and get the "offset" value for this
271 * class and reset the timer.
272 */
273 if (!nopw) {
274 pw.pw_passwd = argp->newpw.pw_passwd;
275 pw.pw_change = 0;
276 }
277 if (!nogecos)
278 pw.pw_gecos = argp->newpw.pw_gecos;
279 if (!noshell)
280 pw.pw_shell = argp->newpw.pw_shell;
281
282 for (n = 0, p = pw.pw_gecos; *p; p++)
283 if (*p == '&')
284 n = n + strlen(pw.pw_name) - 1;
285 if (strlen(pw.pw_name) + 1 + strlen(pw.pw_passwd) + 1 +
286 strlen((sprintf(buf, "%d", pw.pw_uid), buf)) + 1 +
287 strlen((sprintf(buf, "%d", pw.pw_gid), buf)) + 1 +
288 strlen(pw.pw_gecos) + n + 1 + strlen(pw.pw_dir) + 1 +
289 strlen(pw.pw_shell) >= 1023)
290 goto fail;
291
292 pfd = open(_PATH_MASTERPASSWD, O_RDONLY, 0);
293 if (pfd < 0) {
294 syslog(LOG_ERR, "cannot open %s", _PATH_MASTERPASSWD);
295 goto fail;
296 }
297
298 tfd = pw_lock(0);
299 if (tfd < 0)
300 goto fail;
301
302 _pw_copy(pfd, tfd, &pw);
303 pw_mkdb();
304 free(bp);
305
306 if (fork() == 0) {
307 chdir("/var/yp");
308 (void)umask(022);
309 system(make_arg);
310 exit(0);
311 }
312 return (0);
313
314 fail:
315 if (bp)
316 free(bp);
317 if (pfd >= 0)
318 close(pfd);
319 return (1);
320 }