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