pw_copy.c revision 229779
1139826Simp/*- 253541Sshin * Copyright (c) 1990, 1993, 1994 353541Sshin * The Regents of the University of California. All rights reserved. 453541Sshin * 553541Sshin * Redistribution and use in source and binary forms, with or without 653541Sshin * modification, are permitted provided that the following conditions 753541Sshin * are met: 853541Sshin * 1. Redistributions of source code must retain the above copyright 953541Sshin * notice, this list of conditions and the following disclaimer. 1053541Sshin * 2. Redistributions in binary form must reproduce the above copyright 1153541Sshin * notice, this list of conditions and the following disclaimer in the 1253541Sshin * documentation and/or other materials provided with the distribution. 1353541Sshin * 3. All advertising materials mentioning features or use of this software 1453541Sshin * must display the following acknowledgement: 1553541Sshin * This product includes software developed by the University of 1653541Sshin * California, Berkeley and its contributors. 1753541Sshin * 4. Neither the name of the University nor the names of its contributors 1853541Sshin * may be used to endorse or promote products derived from this software 1953541Sshin * without specific prior written permission. 2053541Sshin * 2153541Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2253541Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2353541Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2453541Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2553541Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2653541Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2753541Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2853541Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2953541Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3053541Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3153541Sshin * SUCH DAMAGE. 32139826Simp */ 3353541Sshin 3453541Sshin#ifndef lint 3553541Sshinstatic const char sccsid[] = "@(#)pw_copy.c 8.4 (Berkeley) 4/2/94"; 3653541Sshin#endif /* not lint */ 3753541Sshin 3853541Sshin#include <sys/cdefs.h> 3953541Sshin__FBSDID("$FreeBSD: head/release/picobsd/tinyware/passwd/pw_copy.c 229779 2012-01-07 16:09:43Z uqs $"); 4053541Sshin 4153541Sshin/* 4253541Sshin * This module is used to copy the master password file, replacing a single 4353541Sshin * record, by chpass(1) and passwd(1). 4453541Sshin */ 4553541Sshin 4653541Sshin#include <err.h> 4753541Sshin#include <pwd.h> 4853541Sshin#include <stdio.h> 4953541Sshin#include <string.h> 5053541Sshin#include <unistd.h> 5153541Sshin 5253541Sshin#if 0 5353541Sshin#include <pw_scan.h> 5453541Sshin#endif 5553541Sshinextern int pw_big_ids_warning; 5653541Sshinextern int pw_scan(char *, struct passwd *); 5753541Sshin 5853541Sshin#include <pw_util.h> 5953541Sshin 6053541Sshinextern char *tempname; 6153541Sshin 6253541Sshin/* for use in pw_copy(). Compare a pw entry to a pw struct. */ 6355009Sshinstatic int 6478064Sumepw_equal(char *buf, struct passwd *pw) 6555009Sshin{ 6653541Sshin struct passwd buf_pw; 6795759Stanimura int len; 6895759Stanimura 6953541Sshin len = strlen (buf); 7095759Stanimura if (buf[len-1] == '\n') 7153541Sshin buf[len-1] = '\0'; 7295759Stanimura return (strcmp(pw->pw_name, buf_pw.pw_name) == 0 7395759Stanimura && pw->pw_uid == buf_pw.pw_uid 7453541Sshin && pw->pw_gid == buf_pw.pw_gid 7553541Sshin && strcmp(pw->pw_class, buf_pw.pw_class) == 0 7695759Stanimura && (long)pw->pw_change == (long)buf_pw.pw_change 7753541Sshin && (long)pw->pw_expire == (long)buf_pw.pw_expire 78148385Sume && strcmp(pw->pw_gecos, buf_pw.pw_gecos) == 0 7953541Sshin && strcmp(pw->pw_dir, buf_pw.pw_dir) == 0 8053541Sshin && strcmp(pw->pw_shell, buf_pw.pw_shell) == 0); 8195759Stanimura} 8253541Sshin 8353541Sshinvoid 8453541Sshinpw_copy(int ffd, int tfd, struct passwd *pw, struct passwd *old_pw) 8553541Sshin{ 8653541Sshin FILE *from, *to; 8795759Stanimura int done; 8895759Stanimura char *p, buf[8192]; 8962587Sitojun char uidstr[20]; 9095759Stanimura char gidstr[20]; 9156723Sshin char chgstr[20]; 9253541Sshin char expstr[20]; 9395759Stanimura 9453541Sshin snprintf(uidstr, sizeof(uidstr), "%lu", (unsigned long)pw->pw_uid); 9595759Stanimura snprintf(gidstr, sizeof(gidstr), "%lu", (unsigned long)pw->pw_gid); 9662587Sitojun snprintf(chgstr, sizeof(chgstr), "%ld", (long)pw->pw_change); 9753541Sshin snprintf(expstr, sizeof(expstr), "%ld", (long)pw->pw_expire); 9853541Sshin 9953541Sshin if (!(from = fdopen(ffd, "r"))) 10053541Sshin pw_error(_PATH_MASTERPASSWD, 1, 1); 10153541Sshin if (!(to = fdopen(tfd, "w"))) 10253541Sshin pw_error(tempname, 1, 1); 103105199Ssam 104105199Ssam for (done = 0; fgets(buf, sizeof(buf), from);) { 105105199Ssam if (!strchr(buf, '\n')) { 106105199Ssam warnx("%s: line too long", _PATH_MASTERPASSWD); 107105199Ssam pw_error(NULL, 0, 1); 10853541Sshin } 10953541Sshin if (done) { 11053541Sshin (void)fprintf(to, "%s", buf); 11153541Sshin if (ferror(to)) 11253541Sshin goto err; 11353541Sshin continue; 11453541Sshin } 11553541Sshin for (p = buf; *p != '\n'; p++) 11653541Sshin if (*p != ' ' && *p != '\t') 11753541Sshin break; 11853541Sshin if (*p == '#' || *p == '\n') { 11953541Sshin (void)fprintf(to, "%s", buf); 12053541Sshin if (ferror(to)) 12153541Sshin goto err; 12278064Sume continue; 12378064Sume } 12453541Sshin if (!(p = strchr(buf, ':'))) { 12553541Sshin warnx("%s: corrupted entry", _PATH_MASTERPASSWD); 12653541Sshin pw_error(NULL, 0, 1); 12753541Sshin } 12853541Sshin *p = '\0'; 12953541Sshin if (strcmp(buf, pw->pw_name)) { 13053541Sshin *p = ':'; 13153541Sshin (void)fprintf(to, "%s", buf); 13253541Sshin if (ferror(to)) 13353541Sshin goto err; 13453541Sshin continue; 13553541Sshin } 13653541Sshin *p = ':'; 13753541Sshin if (old_pw && !pw_equal(buf, old_pw)) { 13878064Sume warnx("%s: entry for %s has changed", 139121901Sume _PATH_MASTERPASSWD, pw->pw_name); 14053541Sshin pw_error(NULL, 0, 1); 14178064Sume } 14278064Sume (void)fprintf(to, "%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n", 14383934Sbrooks pw->pw_name, pw->pw_passwd, 14478064Sume pw->pw_fields & _PWF_UID ? uidstr : "", 14578064Sume pw->pw_fields & _PWF_GID ? gidstr : "", 14678064Sume pw->pw_class, 14753541Sshin pw->pw_fields & _PWF_CHANGE ? chgstr : "", 14878064Sume pw->pw_fields & _PWF_EXPIRE ? expstr : "", 149121901Sume pw->pw_gecos, pw->pw_dir, pw->pw_shell); 15053541Sshin done = 1; 151132714Srwatson if (ferror(to)) 15253541Sshin goto err; 153132714Srwatson } 154132714Srwatson if (!done) { 155132714Srwatson#ifdef YP 156132714Srwatson /* Ultra paranoid: shouldn't happen. */ 15753541Sshin if (getuid()) { 158132714Srwatson warnx("%s: not found in %s -- permission denied", 15953541Sshin pw->pw_name, _PATH_MASTERPASSWD); 16053541Sshin pw_error(NULL, 0, 1); 161132714Srwatson } else 16253541Sshin#endif /* YP */ 16353541Sshin (void)fprintf(to, "%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n", 164132714Srwatson pw->pw_name, pw->pw_passwd, 16553541Sshin pw->pw_fields & _PWF_UID ? uidstr : "", 16653541Sshin pw->pw_fields & _PWF_GID ? gidstr : "", 167132714Srwatson pw->pw_class, 16878064Sume pw->pw_fields & _PWF_CHANGE ? chgstr : "", 16978064Sume pw->pw_fields & _PWF_EXPIRE ? expstr : "", 170151459Ssuz pw->pw_gecos, pw->pw_dir, pw->pw_shell); 17178064Sume } 17278064Sume 173132714Srwatson if (ferror(to)) 17478064Sumeerr: pw_error(NULL, 1, 1); 17553541Sshin (void)fclose(to); 17653541Sshin} 17753541Sshin 17878064Sume#include <sys/param.h> 179125941Sume 18078064Sume#include <err.h> 18178064Sume#include <errno.h> 18278064Sume#include <fcntl.h> 183125396Sume#include <pwd.h> 18478064Sume#include <stdio.h> 185125941Sume#include <string.h> 18678064Sume#include <stdlib.h> 18778064Sume#include <unistd.h> 188105199Ssam 189105199Ssam 190125941Sume/* 19153541Sshin * Some software assumes that IDs are short. We should emit warnings 19297658Stanimura * for id's which can not be stored in a short, but we are more liberal 19397658Stanimura * by default, warning for IDs greater than USHRT_MAX. 194121674Sume * 19553541Sshin * If pw_big_ids_warning is anything other than -1 on entry to pw_scan() 19653541Sshin * it will be set based on the existence of PW_SCAN_BIG_IDS in the 19753541Sshin * environment. 198121901Sume */ 19953541Sshinint pw_big_ids_warning = -1; 20053541Sshin 20153541Sshinint 20253541Sshinpw_scan(bp, pw) 20378064Sume char *bp; 20497658Stanimura struct passwd *pw; 20553541Sshin{ 20653541Sshin uid_t id; 20753541Sshin int root; 208132714Srwatson char *p, *sh; 20953541Sshin 21053541Sshin if (pw_big_ids_warning == -1) 21153541Sshin pw_big_ids_warning = getenv("PW_SCAN_BIG_IDS") == NULL ? 1 : 0; 212125941Sume 21378064Sume pw->pw_fields = 0; 21478064Sume if (!(pw->pw_name = strsep(&bp, ":"))) /* login */ 21578064Sume goto fmt; 216125396Sume root = !strcmp(pw->pw_name, "root"); 21778064Sume if(pw->pw_name[0] && (pw->pw_name[0] != '+' || pw->pw_name[1] == '\0')) 218125941Sume pw->pw_fields |= _PWF_NAME; 21978064Sume 22078064Sume if (!(pw->pw_passwd = strsep(&bp, ":"))) /* passwd */ 221105199Ssam goto fmt; 222105199Ssam if(pw->pw_passwd[0]) pw->pw_fields |= _PWF_PASSWD; 223149224Ssuz 224105199Ssam if (!(p = strsep(&bp, ":"))) /* uid */ 225125941Sume goto fmt; 22653541Sshin if (p[0]) 22797658Stanimura pw->pw_fields |= _PWF_UID; 22897658Stanimura else { 229121674Sume if (pw->pw_name[0] != '+' && pw->pw_name[0] != '-') { 23053541Sshin warnx("no uid for user %s", pw->pw_name); 23153541Sshin return (0); 23253541Sshin } 233121901Sume } 23453541Sshin id = strtoul(p, (char **)NULL, 10); 23553541Sshin if (errno == ERANGE) { 23653541Sshin warnx("%s > max uid value (%lu)", p, ULONG_MAX); 23778064Sume return (0); 23897658Stanimura } 23953541Sshin if (root && id) { 240132714Srwatson warnx("root uid should be 0"); 24153541Sshin return (0); 24278064Sume } 24378064Sume if (pw_big_ids_warning && id > USHRT_MAX) { 24478064Sume warnx("%s > recommended max uid value (%u)", p, USHRT_MAX); 24553541Sshin /*return (0);*/ /* THIS SHOULD NOT BE FATAL! */ 24653541Sshin } 24753541Sshin pw->pw_uid = id; 24853541Sshin 24953541Sshin if (!(p = strsep(&bp, ":"))) /* gid */ 25053541Sshin goto fmt; 25153541Sshin if(p[0]) pw->pw_fields |= _PWF_GID; 25253541Sshin id = strtoul(p, (char **)NULL, 10); 25353541Sshin if (errno == ERANGE) { 25453541Sshin warnx("%s > max gid value (%u)", p, ULONG_MAX); 255134655Srwatson return (0); 25653541Sshin } 25753541Sshin if (pw_big_ids_warning && id > USHRT_MAX) { 25853541Sshin warnx("%s > recommended max gid value (%u)", p, USHRT_MAX); 25962587Sitojun /* return (0); This should not be fatal! */ 26062587Sitojun } 26162587Sitojun pw->pw_gid = id; 26262587Sitojun 26362587Sitojun pw->pw_class = strsep(&bp, ":"); /* class */ 26462587Sitojun if(pw->pw_class[0]) pw->pw_fields |= _PWF_CLASS; 26562587Sitojun 26662587Sitojun if (!(p = strsep(&bp, ":"))) /* change */ 26762587Sitojun goto fmt; 26878064Sume if(p[0]) pw->pw_fields |= _PWF_CHANGE; 26978064Sume pw->pw_change = atol(p); 270125776Sume 27198211Shsu if (!(p = strsep(&bp, ":"))) /* expire */ 27262587Sitojun goto fmt; 27362587Sitojun if(p[0]) pw->pw_fields |= _PWF_EXPIRE; 27462587Sitojun pw->pw_expire = atol(p); 27562587Sitojun 27662587Sitojun if (!(pw->pw_gecos = strsep(&bp, ":"))) /* gecos */ 27762587Sitojun goto fmt; 27862587Sitojun if(pw->pw_gecos[0]) pw->pw_fields |= _PWF_GECOS; 27962587Sitojun 28062587Sitojun if (!(pw->pw_dir = strsep(&bp, ":"))) /* directory */ 28162587Sitojun goto fmt; 28262587Sitojun if(pw->pw_dir[0]) pw->pw_fields |= _PWF_DIR; 28362587Sitojun 28462587Sitojun if (!(pw->pw_shell = strsep(&bp, ":"))) /* shell */ 28562587Sitojun goto fmt; 28662587Sitojun 28762587Sitojun p = pw->pw_shell; 28878064Sume if (root && *p) /* empty == /bin/sh */ 28962587Sitojun for (setusershell();;) { 29062587Sitojun if (!(sh = getusershell())) { 29162587Sitojun warnx("warning, unknown root shell"); 292125776Sume break; 29378064Sume } 29462587Sitojun if (!strcmp(p, sh)) 29562587Sitojun break; 29662587Sitojun } 297125776Sume if(p[0]) pw->pw_fields |= _PWF_SHELL; 29878064Sume 29962587Sitojun if ((p = strsep(&bp, ":"))) { /* too many */ 30062587Sitojunfmt: warnx("corrupted entry"); 301133192Srwatson return (0); 302133192Srwatson } 303125776Sume return (1); 30462587Sitojun} 30562587Sitojun