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 3498514Sluigi#ifndef lint 3598514Sluigistatic const char sccsid[] = "@(#)pw_copy.c 8.4 (Berkeley) 4/2/94"; 3698514Sluigi#endif /* not lint */ 3798514Sluigi 3898514Sluigi#include <sys/cdefs.h> 3998514Sluigi__FBSDID("$FreeBSD$"); 4098514Sluigi 4198514Sluigi/* 4298514Sluigi * This module is used to copy the master password file, replacing a single 4398514Sluigi * record, by chpass(1) and passwd(1). 4498514Sluigi */ 4598514Sluigi 4698514Sluigi#include <err.h> 4798514Sluigi#include <pwd.h> 4898514Sluigi#include <stdio.h> 4998514Sluigi#include <string.h> 5098514Sluigi#include <unistd.h> 5198514Sluigi 5298514Sluigi#if 0 5398514Sluigi#include <pw_scan.h> 5498514Sluigi#endif 5598514Sluigiextern int pw_big_ids_warning; 56104744Salfredextern int pw_scan(char *, struct passwd *); 5798514Sluigi 5898514Sluigi#include <pw_util.h> 5998514Sluigi 6098514Sluigiextern char *tempname; 6198514Sluigi 6298514Sluigi/* for use in pw_copy(). Compare a pw entry to a pw struct. */ 6398514Sluigistatic int 6498514Sluigipw_equal(char *buf, struct passwd *pw) 6598514Sluigi{ 6698514Sluigi struct passwd buf_pw; 6798514Sluigi int len; 6898514Sluigi 6998514Sluigi len = strlen (buf); 7098514Sluigi if (buf[len-1] == '\n') 7198514Sluigi buf[len-1] = '\0'; 7298514Sluigi return (strcmp(pw->pw_name, buf_pw.pw_name) == 0 7398514Sluigi && pw->pw_uid == buf_pw.pw_uid 7498514Sluigi && pw->pw_gid == buf_pw.pw_gid 7598514Sluigi && strcmp(pw->pw_class, buf_pw.pw_class) == 0 7698514Sluigi && (long)pw->pw_change == (long)buf_pw.pw_change 7798514Sluigi && (long)pw->pw_expire == (long)buf_pw.pw_expire 7898514Sluigi && strcmp(pw->pw_gecos, buf_pw.pw_gecos) == 0 7998514Sluigi && strcmp(pw->pw_dir, buf_pw.pw_dir) == 0 8098514Sluigi && strcmp(pw->pw_shell, buf_pw.pw_shell) == 0); 8198514Sluigi} 8298514Sluigi 8398514Sluigivoid 8498514Sluigipw_copy(int ffd, int tfd, struct passwd *pw, struct passwd *old_pw) 8598514Sluigi{ 8698514Sluigi FILE *from, *to; 8798514Sluigi int done; 8898514Sluigi char *p, buf[8192]; 8998514Sluigi char uidstr[20]; 9098514Sluigi char gidstr[20]; 9198514Sluigi char chgstr[20]; 9298514Sluigi char expstr[20]; 9398514Sluigi 9498514Sluigi snprintf(uidstr, sizeof(uidstr), "%lu", (unsigned long)pw->pw_uid); 9598514Sluigi snprintf(gidstr, sizeof(gidstr), "%lu", (unsigned long)pw->pw_gid); 9698514Sluigi snprintf(chgstr, sizeof(chgstr), "%ld", (long)pw->pw_change); 9798514Sluigi snprintf(expstr, sizeof(expstr), "%ld", (long)pw->pw_expire); 9898514Sluigi 9998514Sluigi if (!(from = fdopen(ffd, "r"))) 10098514Sluigi pw_error(_PATH_MASTERPASSWD, 1, 1); 10198514Sluigi if (!(to = fdopen(tfd, "w"))) 10298514Sluigi pw_error(tempname, 1, 1); 10398514Sluigi 10498514Sluigi for (done = 0; fgets(buf, sizeof(buf), from);) { 10598514Sluigi if (!strchr(buf, '\n')) { 10698514Sluigi warnx("%s: line too long", _PATH_MASTERPASSWD); 10798514Sluigi pw_error(NULL, 0, 1); 10898514Sluigi } 10998514Sluigi if (done) { 11098514Sluigi (void)fprintf(to, "%s", buf); 11198514Sluigi if (ferror(to)) 11298514Sluigi goto err; 11398514Sluigi continue; 11498514Sluigi } 11598514Sluigi for (p = buf; *p != '\n'; p++) 11698514Sluigi if (*p != ' ' && *p != '\t') 11798514Sluigi break; 11898514Sluigi if (*p == '#' || *p == '\n') { 11998514Sluigi (void)fprintf(to, "%s", buf); 12098514Sluigi if (ferror(to)) 12198514Sluigi goto err; 12298514Sluigi continue; 12398514Sluigi } 12498514Sluigi if (!(p = strchr(buf, ':'))) { 12598514Sluigi warnx("%s: corrupted entry", _PATH_MASTERPASSWD); 12698514Sluigi pw_error(NULL, 0, 1); 12798514Sluigi } 12898514Sluigi *p = '\0'; 12998514Sluigi if (strcmp(buf, pw->pw_name)) { 13098514Sluigi *p = ':'; 13198514Sluigi (void)fprintf(to, "%s", buf); 13298514Sluigi if (ferror(to)) 13398514Sluigi goto err; 13498514Sluigi continue; 13598514Sluigi } 13698514Sluigi *p = ':'; 13798514Sluigi if (old_pw && !pw_equal(buf, old_pw)) { 13898514Sluigi warnx("%s: entry for %s has changed", 13998514Sluigi _PATH_MASTERPASSWD, pw->pw_name); 14098514Sluigi pw_error(NULL, 0, 1); 14198514Sluigi } 14298514Sluigi (void)fprintf(to, "%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n", 14398514Sluigi pw->pw_name, pw->pw_passwd, 14498514Sluigi pw->pw_fields & _PWF_UID ? uidstr : "", 14598514Sluigi pw->pw_fields & _PWF_GID ? gidstr : "", 14698514Sluigi pw->pw_class, 14798514Sluigi pw->pw_fields & _PWF_CHANGE ? chgstr : "", 14898514Sluigi pw->pw_fields & _PWF_EXPIRE ? expstr : "", 14998514Sluigi pw->pw_gecos, pw->pw_dir, pw->pw_shell); 15098514Sluigi done = 1; 15198514Sluigi if (ferror(to)) 15298514Sluigi goto err; 15398514Sluigi } 15498514Sluigi if (!done) { 15598514Sluigi#ifdef YP 15698514Sluigi /* Ultra paranoid: shouldn't happen. */ 15798514Sluigi if (getuid()) { 15898514Sluigi warnx("%s: not found in %s -- permission denied", 15998514Sluigi pw->pw_name, _PATH_MASTERPASSWD); 16098514Sluigi pw_error(NULL, 0, 1); 16198514Sluigi } else 16298514Sluigi#endif /* YP */ 16398514Sluigi (void)fprintf(to, "%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n", 16498514Sluigi pw->pw_name, pw->pw_passwd, 16598514Sluigi pw->pw_fields & _PWF_UID ? uidstr : "", 16698514Sluigi pw->pw_fields & _PWF_GID ? gidstr : "", 16798514Sluigi pw->pw_class, 16898514Sluigi pw->pw_fields & _PWF_CHANGE ? chgstr : "", 16998514Sluigi pw->pw_fields & _PWF_EXPIRE ? expstr : "", 17098514Sluigi pw->pw_gecos, pw->pw_dir, pw->pw_shell); 17198514Sluigi } 17298514Sluigi 17398514Sluigi if (ferror(to)) 17498514Sluigierr: pw_error(NULL, 1, 1); 17598514Sluigi (void)fclose(to); 17698514Sluigi} 17798514Sluigi 17898514Sluigi#include <sys/param.h> 17998514Sluigi 18098514Sluigi#include <err.h> 18198514Sluigi#include <errno.h> 18298514Sluigi#include <fcntl.h> 18398514Sluigi#include <pwd.h> 18498514Sluigi#include <stdio.h> 18598514Sluigi#include <string.h> 18698514Sluigi#include <stdlib.h> 18798514Sluigi#include <unistd.h> 18898514Sluigi 18998514Sluigi 19098514Sluigi/* 19198514Sluigi * Some software assumes that IDs are short. We should emit warnings 19298514Sluigi * for id's which can not be stored in a short, but we are more liberal 19398514Sluigi * by default, warning for IDs greater than USHRT_MAX. 19498514Sluigi * 19598514Sluigi * If pw_big_ids_warning is anything other than -1 on entry to pw_scan() 196229779Suqs * it will be set based on the existence of PW_SCAN_BIG_IDS in the 19798514Sluigi * environment. 19898514Sluigi */ 19998514Sluigiint pw_big_ids_warning = -1; 20098514Sluigi 20198514Sluigiint 20298514Sluigipw_scan(bp, pw) 20398514Sluigi char *bp; 20498514Sluigi struct passwd *pw; 20598514Sluigi{ 20698514Sluigi uid_t id; 20798514Sluigi int root; 20898514Sluigi char *p, *sh; 20998514Sluigi 21098514Sluigi if (pw_big_ids_warning == -1) 21198514Sluigi pw_big_ids_warning = getenv("PW_SCAN_BIG_IDS") == NULL ? 1 : 0; 21298514Sluigi 21398514Sluigi pw->pw_fields = 0; 21498514Sluigi if (!(pw->pw_name = strsep(&bp, ":"))) /* login */ 21598514Sluigi goto fmt; 21698514Sluigi root = !strcmp(pw->pw_name, "root"); 21798514Sluigi if(pw->pw_name[0] && (pw->pw_name[0] != '+' || pw->pw_name[1] == '\0')) 21898514Sluigi pw->pw_fields |= _PWF_NAME; 21998514Sluigi 22098514Sluigi if (!(pw->pw_passwd = strsep(&bp, ":"))) /* passwd */ 22198514Sluigi goto fmt; 22298514Sluigi if(pw->pw_passwd[0]) pw->pw_fields |= _PWF_PASSWD; 22398514Sluigi 22498514Sluigi if (!(p = strsep(&bp, ":"))) /* uid */ 22598514Sluigi goto fmt; 22698514Sluigi if (p[0]) 22798514Sluigi pw->pw_fields |= _PWF_UID; 22898514Sluigi else { 22998514Sluigi if (pw->pw_name[0] != '+' && pw->pw_name[0] != '-') { 23098514Sluigi warnx("no uid for user %s", pw->pw_name); 23198514Sluigi return (0); 23298514Sluigi } 23398514Sluigi } 23498514Sluigi id = strtoul(p, (char **)NULL, 10); 23598514Sluigi if (errno == ERANGE) { 23698514Sluigi warnx("%s > max uid value (%lu)", p, ULONG_MAX); 23798514Sluigi return (0); 23898514Sluigi } 23998514Sluigi if (root && id) { 24098514Sluigi warnx("root uid should be 0"); 24198514Sluigi return (0); 24298514Sluigi } 24398514Sluigi if (pw_big_ids_warning && id > USHRT_MAX) { 24498514Sluigi warnx("%s > recommended max uid value (%u)", p, USHRT_MAX); 24598514Sluigi /*return (0);*/ /* THIS SHOULD NOT BE FATAL! */ 24698514Sluigi } 24798514Sluigi pw->pw_uid = id; 24898514Sluigi 24998514Sluigi if (!(p = strsep(&bp, ":"))) /* gid */ 25098514Sluigi goto fmt; 25198514Sluigi if(p[0]) pw->pw_fields |= _PWF_GID; 25298514Sluigi id = strtoul(p, (char **)NULL, 10); 25398514Sluigi if (errno == ERANGE) { 25498514Sluigi warnx("%s > max gid value (%u)", p, ULONG_MAX); 25598514Sluigi return (0); 25698514Sluigi } 25798514Sluigi if (pw_big_ids_warning && id > USHRT_MAX) { 25898514Sluigi warnx("%s > recommended max gid value (%u)", p, USHRT_MAX); 25998514Sluigi /* return (0); This should not be fatal! */ 26098514Sluigi } 26198514Sluigi pw->pw_gid = id; 26298514Sluigi 26398514Sluigi pw->pw_class = strsep(&bp, ":"); /* class */ 26498514Sluigi if(pw->pw_class[0]) pw->pw_fields |= _PWF_CLASS; 26598514Sluigi 26698514Sluigi if (!(p = strsep(&bp, ":"))) /* change */ 26798514Sluigi goto fmt; 26898514Sluigi if(p[0]) pw->pw_fields |= _PWF_CHANGE; 26998514Sluigi pw->pw_change = atol(p); 27098514Sluigi 27198514Sluigi if (!(p = strsep(&bp, ":"))) /* expire */ 27298514Sluigi goto fmt; 27398514Sluigi if(p[0]) pw->pw_fields |= _PWF_EXPIRE; 27498514Sluigi pw->pw_expire = atol(p); 27598514Sluigi 27698514Sluigi if (!(pw->pw_gecos = strsep(&bp, ":"))) /* gecos */ 27798514Sluigi goto fmt; 27898514Sluigi if(pw->pw_gecos[0]) pw->pw_fields |= _PWF_GECOS; 27998514Sluigi 28098514Sluigi if (!(pw->pw_dir = strsep(&bp, ":"))) /* directory */ 28198514Sluigi goto fmt; 28298514Sluigi if(pw->pw_dir[0]) pw->pw_fields |= _PWF_DIR; 28398514Sluigi 28498514Sluigi if (!(pw->pw_shell = strsep(&bp, ":"))) /* shell */ 28598514Sluigi goto fmt; 28698514Sluigi 28798514Sluigi p = pw->pw_shell; 28898514Sluigi if (root && *p) /* empty == /bin/sh */ 28998514Sluigi for (setusershell();;) { 29098514Sluigi if (!(sh = getusershell())) { 29198514Sluigi warnx("warning, unknown root shell"); 29298514Sluigi break; 29398514Sluigi } 29498514Sluigi if (!strcmp(p, sh)) 29598514Sluigi break; 29698514Sluigi } 29798514Sluigi if(p[0]) pw->pw_fields |= _PWF_SHELL; 29898514Sluigi 29998514Sluigi if ((p = strsep(&bp, ":"))) { /* too many */ 30098514Sluigifmt: warnx("corrupted entry"); 30198514Sluigi return (0); 30298514Sluigi } 30398514Sluigi return (1); 30498514Sluigi} 305