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