pw_copy.c revision 104744
198514Sluigi/*- 298514Sluigi * Copyright (c) 1990, 1993, 1994 398514Sluigi * The Regents of the University of California. All rights reserved. 498514Sluigi * 598514Sluigi * Redistribution and use in source and binary forms, with or without 698514Sluigi * modification, are permitted provided that the following conditions 798514Sluigi * are met: 898514Sluigi * 1. Redistributions of source code must retain the above copyright 998514Sluigi * notice, this list of conditions and the following disclaimer. 1098514Sluigi * 2. Redistributions in binary form must reproduce the above copyright 1198514Sluigi * notice, this list of conditions and the following disclaimer in the 1298514Sluigi * documentation and/or other materials provided with the distribution. 1398514Sluigi * 3. All advertising materials mentioning features or use of this software 1498514Sluigi * must display the following acknowledgement: 1598514Sluigi * This product includes software developed by the University of 1698514Sluigi * California, Berkeley and its contributors. 1798514Sluigi * 4. Neither the name of the University nor the names of its contributors 1898514Sluigi * may be used to endorse or promote products derived from this software 1998514Sluigi * without specific prior written permission. 2098514Sluigi * 2198514Sluigi * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2298514Sluigi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2398514Sluigi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2498514Sluigi * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2598514Sluigi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2698514Sluigi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2798514Sluigi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2898514Sluigi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2998514Sluigi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3098514Sluigi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3198514Sluigi * SUCH DAMAGE. 3298514Sluigi * 3398514Sluigi * $FreeBSD: head/release/picobsd/tinyware/passwd/pw_copy.c 104744 2002-10-10 00:32:55Z alfred $ 3498514Sluigi */ 3598514Sluigi 3698514Sluigi#ifndef lint 3798514Sluigistatic const char sccsid[] = "@(#)pw_copy.c 8.4 (Berkeley) 4/2/94"; 3898514Sluigi#endif /* not lint */ 3998514Sluigi 4098514Sluigi#include <sys/cdefs.h> 4198514Sluigi__FBSDID("$FreeBSD: head/release/picobsd/tinyware/passwd/pw_copy.c 104744 2002-10-10 00:32:55Z alfred $"); 4298514Sluigi 4398514Sluigi/* 4498514Sluigi * This module is used to copy the master password file, replacing a single 4598514Sluigi * record, by chpass(1) and passwd(1). 4698514Sluigi */ 4798514Sluigi 4898514Sluigi#include <err.h> 4998514Sluigi#include <pwd.h> 5098514Sluigi#include <stdio.h> 5198514Sluigi#include <string.h> 5298514Sluigi#include <unistd.h> 5398514Sluigi 5498514Sluigi#if 0 5598514Sluigi#include <pw_scan.h> 5698514Sluigi#endif 5798514Sluigiextern int pw_big_ids_warning; 58104744Salfredextern int pw_scan(char *, struct passwd *); 5998514Sluigi 6098514Sluigi#include <pw_util.h> 6198514Sluigi 6298514Sluigiextern char *tempname; 6398514Sluigi 6498514Sluigi/* for use in pw_copy(). Compare a pw entry to a pw struct. */ 6598514Sluigistatic int 6698514Sluigipw_equal(char *buf, struct passwd *pw) 6798514Sluigi{ 6898514Sluigi struct passwd buf_pw; 6998514Sluigi int len; 7098514Sluigi 7198514Sluigi len = strlen (buf); 7298514Sluigi if (buf[len-1] == '\n') 7398514Sluigi buf[len-1] = '\0'; 7498514Sluigi return (strcmp(pw->pw_name, buf_pw.pw_name) == 0 7598514Sluigi && pw->pw_uid == buf_pw.pw_uid 7698514Sluigi && pw->pw_gid == buf_pw.pw_gid 7798514Sluigi && strcmp(pw->pw_class, buf_pw.pw_class) == 0 7898514Sluigi && (long)pw->pw_change == (long)buf_pw.pw_change 7998514Sluigi && (long)pw->pw_expire == (long)buf_pw.pw_expire 8098514Sluigi && strcmp(pw->pw_gecos, buf_pw.pw_gecos) == 0 8198514Sluigi && strcmp(pw->pw_dir, buf_pw.pw_dir) == 0 8298514Sluigi && strcmp(pw->pw_shell, buf_pw.pw_shell) == 0); 8398514Sluigi} 8498514Sluigi 8598514Sluigivoid 8698514Sluigipw_copy(int ffd, int tfd, struct passwd *pw, struct passwd *old_pw) 8798514Sluigi{ 8898514Sluigi FILE *from, *to; 8998514Sluigi int done; 9098514Sluigi char *p, buf[8192]; 9198514Sluigi char uidstr[20]; 9298514Sluigi char gidstr[20]; 9398514Sluigi char chgstr[20]; 9498514Sluigi char expstr[20]; 9598514Sluigi 9698514Sluigi snprintf(uidstr, sizeof(uidstr), "%lu", (unsigned long)pw->pw_uid); 9798514Sluigi snprintf(gidstr, sizeof(gidstr), "%lu", (unsigned long)pw->pw_gid); 9898514Sluigi snprintf(chgstr, sizeof(chgstr), "%ld", (long)pw->pw_change); 9998514Sluigi snprintf(expstr, sizeof(expstr), "%ld", (long)pw->pw_expire); 10098514Sluigi 10198514Sluigi if (!(from = fdopen(ffd, "r"))) 10298514Sluigi pw_error(_PATH_MASTERPASSWD, 1, 1); 10398514Sluigi if (!(to = fdopen(tfd, "w"))) 10498514Sluigi pw_error(tempname, 1, 1); 10598514Sluigi 10698514Sluigi for (done = 0; fgets(buf, sizeof(buf), from);) { 10798514Sluigi if (!strchr(buf, '\n')) { 10898514Sluigi warnx("%s: line too long", _PATH_MASTERPASSWD); 10998514Sluigi pw_error(NULL, 0, 1); 11098514Sluigi } 11198514Sluigi if (done) { 11298514Sluigi (void)fprintf(to, "%s", buf); 11398514Sluigi if (ferror(to)) 11498514Sluigi goto err; 11598514Sluigi continue; 11698514Sluigi } 11798514Sluigi for (p = buf; *p != '\n'; p++) 11898514Sluigi if (*p != ' ' && *p != '\t') 11998514Sluigi break; 12098514Sluigi if (*p == '#' || *p == '\n') { 12198514Sluigi (void)fprintf(to, "%s", buf); 12298514Sluigi if (ferror(to)) 12398514Sluigi goto err; 12498514Sluigi continue; 12598514Sluigi } 12698514Sluigi if (!(p = strchr(buf, ':'))) { 12798514Sluigi warnx("%s: corrupted entry", _PATH_MASTERPASSWD); 12898514Sluigi pw_error(NULL, 0, 1); 12998514Sluigi } 13098514Sluigi *p = '\0'; 13198514Sluigi if (strcmp(buf, pw->pw_name)) { 13298514Sluigi *p = ':'; 13398514Sluigi (void)fprintf(to, "%s", buf); 13498514Sluigi if (ferror(to)) 13598514Sluigi goto err; 13698514Sluigi continue; 13798514Sluigi } 13898514Sluigi *p = ':'; 13998514Sluigi if (old_pw && !pw_equal(buf, old_pw)) { 14098514Sluigi warnx("%s: entry for %s has changed", 14198514Sluigi _PATH_MASTERPASSWD, pw->pw_name); 14298514Sluigi pw_error(NULL, 0, 1); 14398514Sluigi } 14498514Sluigi (void)fprintf(to, "%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n", 14598514Sluigi pw->pw_name, pw->pw_passwd, 14698514Sluigi pw->pw_fields & _PWF_UID ? uidstr : "", 14798514Sluigi pw->pw_fields & _PWF_GID ? gidstr : "", 14898514Sluigi pw->pw_class, 14998514Sluigi pw->pw_fields & _PWF_CHANGE ? chgstr : "", 15098514Sluigi pw->pw_fields & _PWF_EXPIRE ? expstr : "", 15198514Sluigi pw->pw_gecos, pw->pw_dir, pw->pw_shell); 15298514Sluigi done = 1; 15398514Sluigi if (ferror(to)) 15498514Sluigi goto err; 15598514Sluigi } 15698514Sluigi if (!done) { 15798514Sluigi#ifdef YP 15898514Sluigi /* Ultra paranoid: shouldn't happen. */ 15998514Sluigi if (getuid()) { 16098514Sluigi warnx("%s: not found in %s -- permission denied", 16198514Sluigi pw->pw_name, _PATH_MASTERPASSWD); 16298514Sluigi pw_error(NULL, 0, 1); 16398514Sluigi } else 16498514Sluigi#endif /* YP */ 16598514Sluigi (void)fprintf(to, "%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n", 16698514Sluigi pw->pw_name, pw->pw_passwd, 16798514Sluigi pw->pw_fields & _PWF_UID ? uidstr : "", 16898514Sluigi pw->pw_fields & _PWF_GID ? gidstr : "", 16998514Sluigi pw->pw_class, 17098514Sluigi pw->pw_fields & _PWF_CHANGE ? chgstr : "", 17198514Sluigi pw->pw_fields & _PWF_EXPIRE ? expstr : "", 17298514Sluigi pw->pw_gecos, pw->pw_dir, pw->pw_shell); 17398514Sluigi } 17498514Sluigi 17598514Sluigi if (ferror(to)) 17698514Sluigierr: pw_error(NULL, 1, 1); 17798514Sluigi (void)fclose(to); 17898514Sluigi} 17998514Sluigi 18098514Sluigi#include <sys/param.h> 18198514Sluigi 18298514Sluigi#include <err.h> 18398514Sluigi#include <errno.h> 18498514Sluigi#include <fcntl.h> 18598514Sluigi#include <pwd.h> 18698514Sluigi#include <stdio.h> 18798514Sluigi#include <string.h> 18898514Sluigi#include <stdlib.h> 18998514Sluigi#include <unistd.h> 19098514Sluigi 19198514Sluigi 19298514Sluigi/* 19398514Sluigi * Some software assumes that IDs are short. We should emit warnings 19498514Sluigi * for id's which can not be stored in a short, but we are more liberal 19598514Sluigi * by default, warning for IDs greater than USHRT_MAX. 19698514Sluigi * 19798514Sluigi * If pw_big_ids_warning is anything other than -1 on entry to pw_scan() 19898514Sluigi * it will be set based on the existance of PW_SCAN_BIG_IDS in the 19998514Sluigi * environment. 20098514Sluigi */ 20198514Sluigiint pw_big_ids_warning = -1; 20298514Sluigi 20398514Sluigiint 20498514Sluigipw_scan(bp, pw) 20598514Sluigi char *bp; 20698514Sluigi struct passwd *pw; 20798514Sluigi{ 20898514Sluigi uid_t id; 20998514Sluigi int root; 21098514Sluigi char *p, *sh; 21198514Sluigi 21298514Sluigi if (pw_big_ids_warning == -1) 21398514Sluigi pw_big_ids_warning = getenv("PW_SCAN_BIG_IDS") == NULL ? 1 : 0; 21498514Sluigi 21598514Sluigi pw->pw_fields = 0; 21698514Sluigi if (!(pw->pw_name = strsep(&bp, ":"))) /* login */ 21798514Sluigi goto fmt; 21898514Sluigi root = !strcmp(pw->pw_name, "root"); 21998514Sluigi if(pw->pw_name[0] && (pw->pw_name[0] != '+' || pw->pw_name[1] == '\0')) 22098514Sluigi pw->pw_fields |= _PWF_NAME; 22198514Sluigi 22298514Sluigi if (!(pw->pw_passwd = strsep(&bp, ":"))) /* passwd */ 22398514Sluigi goto fmt; 22498514Sluigi if(pw->pw_passwd[0]) pw->pw_fields |= _PWF_PASSWD; 22598514Sluigi 22698514Sluigi if (!(p = strsep(&bp, ":"))) /* uid */ 22798514Sluigi goto fmt; 22898514Sluigi if (p[0]) 22998514Sluigi pw->pw_fields |= _PWF_UID; 23098514Sluigi else { 23198514Sluigi if (pw->pw_name[0] != '+' && pw->pw_name[0] != '-') { 23298514Sluigi warnx("no uid for user %s", pw->pw_name); 23398514Sluigi return (0); 23498514Sluigi } 23598514Sluigi } 23698514Sluigi id = strtoul(p, (char **)NULL, 10); 23798514Sluigi if (errno == ERANGE) { 23898514Sluigi warnx("%s > max uid value (%lu)", p, ULONG_MAX); 23998514Sluigi return (0); 24098514Sluigi } 24198514Sluigi if (root && id) { 24298514Sluigi warnx("root uid should be 0"); 24398514Sluigi return (0); 24498514Sluigi } 24598514Sluigi if (pw_big_ids_warning && id > USHRT_MAX) { 24698514Sluigi warnx("%s > recommended max uid value (%u)", p, USHRT_MAX); 24798514Sluigi /*return (0);*/ /* THIS SHOULD NOT BE FATAL! */ 24898514Sluigi } 24998514Sluigi pw->pw_uid = id; 25098514Sluigi 25198514Sluigi if (!(p = strsep(&bp, ":"))) /* gid */ 25298514Sluigi goto fmt; 25398514Sluigi if(p[0]) pw->pw_fields |= _PWF_GID; 25498514Sluigi id = strtoul(p, (char **)NULL, 10); 25598514Sluigi if (errno == ERANGE) { 25698514Sluigi warnx("%s > max gid value (%u)", p, ULONG_MAX); 25798514Sluigi return (0); 25898514Sluigi } 25998514Sluigi if (pw_big_ids_warning && id > USHRT_MAX) { 26098514Sluigi warnx("%s > recommended max gid value (%u)", p, USHRT_MAX); 26198514Sluigi /* return (0); This should not be fatal! */ 26298514Sluigi } 26398514Sluigi pw->pw_gid = id; 26498514Sluigi 26598514Sluigi pw->pw_class = strsep(&bp, ":"); /* class */ 26698514Sluigi if(pw->pw_class[0]) pw->pw_fields |= _PWF_CLASS; 26798514Sluigi 26898514Sluigi if (!(p = strsep(&bp, ":"))) /* change */ 26998514Sluigi goto fmt; 27098514Sluigi if(p[0]) pw->pw_fields |= _PWF_CHANGE; 27198514Sluigi pw->pw_change = atol(p); 27298514Sluigi 27398514Sluigi if (!(p = strsep(&bp, ":"))) /* expire */ 27498514Sluigi goto fmt; 27598514Sluigi if(p[0]) pw->pw_fields |= _PWF_EXPIRE; 27698514Sluigi pw->pw_expire = atol(p); 27798514Sluigi 27898514Sluigi if (!(pw->pw_gecos = strsep(&bp, ":"))) /* gecos */ 27998514Sluigi goto fmt; 28098514Sluigi if(pw->pw_gecos[0]) pw->pw_fields |= _PWF_GECOS; 28198514Sluigi 28298514Sluigi if (!(pw->pw_dir = strsep(&bp, ":"))) /* directory */ 28398514Sluigi goto fmt; 28498514Sluigi if(pw->pw_dir[0]) pw->pw_fields |= _PWF_DIR; 28598514Sluigi 28698514Sluigi if (!(pw->pw_shell = strsep(&bp, ":"))) /* shell */ 28798514Sluigi goto fmt; 28898514Sluigi 28998514Sluigi p = pw->pw_shell; 29098514Sluigi if (root && *p) /* empty == /bin/sh */ 29198514Sluigi for (setusershell();;) { 29298514Sluigi if (!(sh = getusershell())) { 29398514Sluigi warnx("warning, unknown root shell"); 29498514Sluigi break; 29598514Sluigi } 29698514Sluigi if (!strcmp(p, sh)) 29798514Sluigi break; 29898514Sluigi } 29998514Sluigi if(p[0]) pw->pw_fields |= _PWF_SHELL; 30098514Sluigi 30198514Sluigi if ((p = strsep(&bp, ":"))) { /* too many */ 30298514Sluigifmt: warnx("corrupted entry"); 30398514Sluigi return (0); 30498514Sluigi } 30598514Sluigi return (1); 30698514Sluigi} 307