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