pw_copy.c revision 104744
1177591Sedwin/*- 258787Sru * Copyright (c) 1990, 1993, 1994 319874Swollman * The Regents of the University of California. All rights reserved. 419874Swollman * 5149514Swollman * Redistribution and use in source and binary forms, with or without 619874Swollman * modification, are permitted provided that the following conditions 719874Swollman * are met: 837998Sdes * 1. Redistributions of source code must retain the above copyright 919874Swollman * notice, this list of conditions and the following disclaimer. 1019874Swollman * 2. Redistributions in binary form must reproduce the above copyright 1119874Swollman * notice, this list of conditions and the following disclaimer in the 1219874Swollman * documentation and/or other materials provided with the distribution. 1319874Swollman * 3. All advertising materials mentioning features or use of this software 1419874Swollman * must display the following acknowledgement: 1586222Swollman * This product includes software developed by the University of 1619874Swollman * California, Berkeley and its contributors. 1719874Swollman * 4. Neither the name of the University nor the names of its contributors 1819874Swollman * may be used to endorse or promote products derived from this software 1919874Swollman * without specific prior written permission. 2019874Swollman * 2119874Swollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2219874Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2319874Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2419874Swollman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2519874Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2619874Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2719874Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2819874Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2919874Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3019874Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3119874Swollman * SUCH DAMAGE. 3219874Swollman * 3319874Swollman * $FreeBSD: head/release/picobsd/tinyware/passwd/pw_copy.c 104744 2002-10-10 00:32:55Z alfred $ 3419874Swollman */ 3519874Swollman 36114173Swollman#ifndef lint 3737998Sdesstatic const char sccsid[] = "@(#)pw_copy.c 8.4 (Berkeley) 4/2/94"; 3837998Sdes#endif /* not lint */ 3943014Swollman 4019874Swollman#include <sys/cdefs.h> 4175267Swollman__FBSDID("$FreeBSD: head/release/picobsd/tinyware/passwd/pw_copy.c 104744 2002-10-10 00:32:55Z alfred $"); 42171948Sedwin 4358787Sru/* 44136638Swollman * This module is used to copy the master password file, replacing a single 45177591Sedwin * record, by chpass(1) and passwd(1). 46177591Sedwin */ 47136638Swollman 48163302Sru#include <err.h> 49149514Swollman#include <pwd.h> 50136638Swollman#include <stdio.h> 51136638Swollman#include <string.h> 52136638Swollman#include <unistd.h> 53136638Swollman 54136638Swollman#if 0 5519874Swollman#include <pw_scan.h> 5619874Swollman#endif 5719874Swollmanextern int pw_big_ids_warning; 58149514Swollmanextern int pw_scan(char *, struct passwd *); 59149514Swollman 6019874Swollman#include <pw_util.h> 6119874Swollman 6275267Swollmanextern char *tempname; 6337998Sdes 6437998Sdes/* for use in pw_copy(). Compare a pw entry to a pw struct. */ 6519874Swollmanstatic int 6619874Swollmanpw_equal(char *buf, struct passwd *pw) 67169811Swollman{ 68169811Swollman struct passwd buf_pw; 69171948Sedwin int len; 70136638Swollman 7119874Swollman len = strlen (buf); 7219874Swollman if (buf[len-1] == '\n') 7319874Swollman buf[len-1] = '\0'; 7475267Swollman return (strcmp(pw->pw_name, buf_pw.pw_name) == 0 7519874Swollman && pw->pw_uid == buf_pw.pw_uid 7619874Swollman && pw->pw_gid == buf_pw.pw_gid 7719874Swollman && strcmp(pw->pw_class, buf_pw.pw_class) == 0 7819874Swollman && (long)pw->pw_change == (long)buf_pw.pw_change 7919874Swollman && (long)pw->pw_expire == (long)buf_pw.pw_expire 8019874Swollman && strcmp(pw->pw_gecos, buf_pw.pw_gecos) == 0 81174242Sedwin && strcmp(pw->pw_dir, buf_pw.pw_dir) == 0 8219874Swollman && strcmp(pw->pw_shell, buf_pw.pw_shell) == 0); 8319874Swollman} 8419874Swollman 8575267Swollmanvoid 8643543Swollmanpw_copy(int ffd, int tfd, struct passwd *pw, struct passwd *old_pw) 87121098Swollman{ 8875267Swollman FILE *from, *to; 8943543Swollman int done; 9043543Swollman char *p, buf[8192]; 91121098Swollman char uidstr[20]; 92121098Swollman char gidstr[20]; 93121098Swollman char chgstr[20]; 94121098Swollman char expstr[20]; 9558787Sru 9658787Sru snprintf(uidstr, sizeof(uidstr), "%lu", (unsigned long)pw->pw_uid); 9775267Swollman snprintf(gidstr, sizeof(gidstr), "%lu", (unsigned long)pw->pw_gid); 9875267Swollman snprintf(chgstr, sizeof(chgstr), "%ld", (long)pw->pw_change); 9975267Swollman snprintf(expstr, sizeof(expstr), "%ld", (long)pw->pw_expire); 10019874Swollman 10167578Swollman if (!(from = fdopen(ffd, "r"))) 10219874Swollman pw_error(_PATH_MASTERPASSWD, 1, 1); 10319874Swollman if (!(to = fdopen(tfd, "w"))) 10419874Swollman pw_error(tempname, 1, 1); 105163302Sru 106163302Sru for (done = 0; fgets(buf, sizeof(buf), from);) { 10719874Swollman if (!strchr(buf, '\n')) { 108158421Swollman warnx("%s: line too long", _PATH_MASTERPASSWD); 109163302Sru pw_error(NULL, 0, 1); 110163302Sru } 111121098Swollman if (done) { 112121098Swollman (void)fprintf(to, "%s", buf); 11319874Swollman if (ferror(to)) 11419874Swollman goto err; 115169811Swollman continue; 116149514Swollman } 117169811Swollman for (p = buf; *p != '\n'; p++) 118163302Sru if (*p != ' ' && *p != '\t') 119163302Sru break; 12019874Swollman if (*p == '#' || *p == '\n') { 121163302Sru (void)fprintf(to, "%s", buf); 12219874Swollman if (ferror(to)) 12319874Swollman goto err; 12419874Swollman continue; 125171948Sedwin } 12619874Swollman if (!(p = strchr(buf, ':'))) { 127163302Sru warnx("%s: corrupted entry", _PATH_MASTERPASSWD); 12819874Swollman pw_error(NULL, 0, 1); 12919874Swollman } 13019874Swollman *p = '\0'; 13119874Swollman if (strcmp(buf, pw->pw_name)) { 13219874Swollman *p = ':'; 13337998Sdes (void)fprintf(to, "%s", buf); 13437998Sdes if (ferror(to)) 13519874Swollman goto err; 13619874Swollman continue; 13719874Swollman } 13819874Swollman *p = ':'; 13919874Swollman if (old_pw && !pw_equal(buf, old_pw)) { 14086222Swollman warnx("%s: entry for %s has changed", 141169811Swollman _PATH_MASTERPASSWD, pw->pw_name); 14219874Swollman pw_error(NULL, 0, 1); 14393799Swollman } 144163302Sru (void)fprintf(to, "%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n", 145163302Sru pw->pw_name, pw->pw_passwd, 146163302Sru pw->pw_fields & _PWF_UID ? uidstr : "", 147163302Sru pw->pw_fields & _PWF_GID ? gidstr : "", 14819874Swollman pw->pw_class, 14919874Swollman pw->pw_fields & _PWF_CHANGE ? chgstr : "", 15019874Swollman pw->pw_fields & _PWF_EXPIRE ? expstr : "", 15119874Swollman pw->pw_gecos, pw->pw_dir, pw->pw_shell); 15219874Swollman done = 1; 15319874Swollman if (ferror(to)) 15419874Swollman goto err; 15519874Swollman } 15619874Swollman if (!done) { 15719874Swollman#ifdef YP 15819874Swollman /* Ultra paranoid: shouldn't happen. */ 15919874Swollman if (getuid()) { 16019874Swollman warnx("%s: not found in %s -- permission denied", 16119874Swollman pw->pw_name, _PATH_MASTERPASSWD); 16219874Swollman pw_error(NULL, 0, 1); 16319874Swollman } else 16419874Swollman#endif /* YP */ 16519874Swollman (void)fprintf(to, "%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n", 166169811Swollman pw->pw_name, pw->pw_passwd, 16719874Swollman pw->pw_fields & _PWF_UID ? uidstr : "", 16819874Swollman pw->pw_fields & _PWF_GID ? gidstr : "", 16919874Swollman pw->pw_class, 17019874Swollman pw->pw_fields & _PWF_CHANGE ? chgstr : "", 17119874Swollman pw->pw_fields & _PWF_EXPIRE ? expstr : "", 17219874Swollman pw->pw_gecos, pw->pw_dir, pw->pw_shell); 17319874Swollman } 174149514Swollman 17519874Swollman if (ferror(to)) 17619874Swollmanerr: pw_error(NULL, 1, 1); 177169811Swollman (void)fclose(to); 17819874Swollman} 17919874Swollman 180171948Sedwin#include <sys/param.h> 18119874Swollman 18219874Swollman#include <err.h> 18319874Swollman#include <errno.h> 184163302Sru#include <fcntl.h> 18519874Swollman#include <pwd.h> 18619874Swollman#include <stdio.h> 18786222Swollman#include <string.h> 18893799Swollman#include <stdlib.h> 189163302Sru#include <unistd.h> 19093799Swollman 19119874Swollman 19219874Swollman/* 19319874Swollman * Some software assumes that IDs are short. We should emit warnings 19419874Swollman * for id's which can not be stored in a short, but we are more liberal 19519874Swollman * by default, warning for IDs greater than USHRT_MAX. 19619874Swollman * 19719874Swollman * If pw_big_ids_warning is anything other than -1 on entry to pw_scan() 19819874Swollman * it will be set based on the existance of PW_SCAN_BIG_IDS in the 19919874Swollman * environment. 20019874Swollman */ 20158787Sruint pw_big_ids_warning = -1; 20219874Swollman 20319874Swollmanint 20419874Swollmanpw_scan(bp, pw) 20519874Swollman char *bp; 20619874Swollman struct passwd *pw; 20786222Swollman{ 20893799Swollman uid_t id; 20919874Swollman int root; 21019874Swollman char *p, *sh; 21143014Swollman 212163302Sru if (pw_big_ids_warning == -1) 213177591Sedwin pw_big_ids_warning = getenv("PW_SCAN_BIG_IDS") == NULL ? 1 : 0; 21419874Swollman 21519874Swollman pw->pw_fields = 0; 21619874Swollman if (!(pw->pw_name = strsep(&bp, ":"))) /* login */ 21719874Swollman goto fmt; 21819874Swollman root = !strcmp(pw->pw_name, "root"); 219169811Swollman if(pw->pw_name[0] && (pw->pw_name[0] != '+' || pw->pw_name[1] == '\0')) 22019874Swollman pw->pw_fields |= _PWF_NAME; 22119874Swollman 22243543Swollman if (!(pw->pw_passwd = strsep(&bp, ":"))) /* passwd */ 22319874Swollman goto fmt; 22419874Swollman if(pw->pw_passwd[0]) pw->pw_fields |= _PWF_PASSWD; 22519874Swollman 22619874Swollman if (!(p = strsep(&bp, ":"))) /* uid */ 22719874Swollman goto fmt; 22819874Swollman if (p[0]) 22919874Swollman pw->pw_fields |= _PWF_UID; 23019874Swollman else { 23119874Swollman if (pw->pw_name[0] != '+' && pw->pw_name[0] != '-') { 23219874Swollman warnx("no uid for user %s", pw->pw_name); 23319874Swollman return (0); 23419874Swollman } 23593799Swollman } 23693799Swollman id = strtoul(p, (char **)NULL, 10); 23793799Swollman if (errno == ERANGE) { 23893799Swollman warnx("%s > max uid value (%lu)", p, ULONG_MAX); 23993799Swollman return (0); 24019874Swollman } 24119874Swollman if (root && id) { 24219874Swollman warnx("root uid should be 0"); 24319874Swollman return (0); 24419874Swollman } 24519874Swollman if (pw_big_ids_warning && id > USHRT_MAX) { 24619874Swollman warnx("%s > recommended max uid value (%u)", p, USHRT_MAX); 24719874Swollman /*return (0);*/ /* THIS SHOULD NOT BE FATAL! */ 24819874Swollman } 24919874Swollman pw->pw_uid = id; 25019874Swollman 25119874Swollman if (!(p = strsep(&bp, ":"))) /* gid */ 25219874Swollman goto fmt; 25375267Swollman if(p[0]) pw->pw_fields |= _PWF_GID; 254169811Swollman id = strtoul(p, (char **)NULL, 10); 255174242Sedwin if (errno == ERANGE) { 25619874Swollman warnx("%s > max gid value (%u)", p, ULONG_MAX); 25719874Swollman return (0); 25819874Swollman } 25919874Swollman if (pw_big_ids_warning && id > USHRT_MAX) { 260149514Swollman warnx("%s > recommended max gid value (%u)", p, USHRT_MAX); 26119874Swollman /* return (0); This should not be fatal! */ 26258787Sru } 26386222Swollman pw->pw_gid = id; 26486222Swollman 26593799Swollman pw->pw_class = strsep(&bp, ":"); /* class */ 26619874Swollman if(pw->pw_class[0]) pw->pw_fields |= _PWF_CLASS; 26719874Swollman 26819874Swollman if (!(p = strsep(&bp, ":"))) /* change */ 269158421Swollman goto fmt; 27019874Swollman if(p[0]) pw->pw_fields |= _PWF_CHANGE; 27119874Swollman pw->pw_change = atol(p); 27219874Swollman 27319874Swollman if (!(p = strsep(&bp, ":"))) /* expire */ 27458787Sru goto fmt; 27558787Sru if(p[0]) pw->pw_fields |= _PWF_EXPIRE; 27664499Swollman pw->pw_expire = atol(p); 27764499Swollman 27858787Sru if (!(pw->pw_gecos = strsep(&bp, ":"))) /* gecos */ 27943014Swollman goto fmt; 28058787Sru if(pw->pw_gecos[0]) pw->pw_fields |= _PWF_GECOS; 28158787Sru 28219874Swollman if (!(pw->pw_dir = strsep(&bp, ":"))) /* directory */ 28319874Swollman goto fmt; 28419874Swollman if(pw->pw_dir[0]) pw->pw_fields |= _PWF_DIR; 28519874Swollman 28619874Swollman if (!(pw->pw_shell = strsep(&bp, ":"))) /* shell */ 28719874Swollman goto fmt; 28819874Swollman 28919874Swollman p = pw->pw_shell; 29019874Swollman if (root && *p) /* empty == /bin/sh */ 29119874Swollman for (setusershell();;) { 29219874Swollman if (!(sh = getusershell())) { 29319874Swollman warnx("warning, unknown root shell"); 29419874Swollman break; 29519874Swollman } 29619874Swollman if (!strcmp(p, sh)) 297121098Swollman break; 29819874Swollman } 29919874Swollman if(p[0]) pw->pw_fields |= _PWF_SHELL; 30019874Swollman 30119874Swollman if ((p = strsep(&bp, ":"))) { /* too many */ 30219874Swollmanfmt: warnx("corrupted entry"); 30319874Swollman return (0); 30419874Swollman } 30519874Swollman return (1); 30619874Swollman} 30719874Swollman