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