pwupd.c revision 88280
1290001Sglebius/*-
2290001Sglebius * Copyright (C) 1996
3290001Sglebius *	David L. Nugent.  All rights reserved.
4290001Sglebius *
5290001Sglebius * Redistribution and use in source and binary forms, with or without
6290001Sglebius * modification, are permitted provided that the following conditions
7290001Sglebius * are met:
8290001Sglebius * 1. Redistributions of source code must retain the above copyright
9290001Sglebius *    notice, this list of conditions and the following disclaimer.
10290001Sglebius * 2. Redistributions in binary form must reproduce the above copyright
11290001Sglebius *    notice, this list of conditions and the following disclaimer in the
12290001Sglebius *    documentation and/or other materials provided with the distribution.
13290001Sglebius *
14290001Sglebius * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND
15290001Sglebius * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16290001Sglebius * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17290001Sglebius * ARE DISCLAIMED.  IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE
18290001Sglebius * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19290001Sglebius * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20290001Sglebius * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21290001Sglebius * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22290001Sglebius * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23290001Sglebius * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24290001Sglebius * SUCH DAMAGE.
25290001Sglebius */
26290001Sglebius
27290001Sglebius#ifndef lint
28290001Sglebiusstatic const char rcsid[] =
29290001Sglebius  "$FreeBSD: head/usr.sbin/pw/pwupd.c 88280 2001-12-20 16:03:04Z nectar $";
30290001Sglebius#endif /* not lint */
31290001Sglebius
32290001Sglebius#include <stdio.h>
33290001Sglebius#include <stdlib.h>
34290001Sglebius#include <string.h>
35290001Sglebius#include <unistd.h>
36290001Sglebius#include <stdarg.h>
37290001Sglebius#include <errno.h>
38290001Sglebius#include <sys/types.h>
39290001Sglebius#include <sys/stat.h>
40290001Sglebius#include <sys/param.h>
41290001Sglebius#include <sys/wait.h>
42290001Sglebius
43290001Sglebius#include "pwupd.h"
44290001Sglebius
45290001Sglebius#define HAVE_PWDB_C	1
46290001Sglebius#define	HAVE_PWDB_U	1
47290001Sglebius
48290001Sglebiusstatic char pathpwd[] = _PATH_PWD;
49290001Sglebiusstatic char * pwpath = pathpwd;
50290001Sglebius
51290001Sglebiusint
52290001Sglebiussetpwdir(const char * dir)
53290001Sglebius{
54290001Sglebius	if (dir == NULL)
55290001Sglebius		return -1;
56290001Sglebius	else {
57290001Sglebius		char * d = malloc(strlen(dir)+1);
58290001Sglebius		if (d == NULL)
59290001Sglebius			return -1;
60290001Sglebius		pwpath = strcpy(d, dir);
61290001Sglebius	}
62290001Sglebius	return 0;
63290001Sglebius}
64290001Sglebius
65290001Sglebiuschar *
66290001Sglebiusgetpwpath(char const * file)
67290001Sglebius{
68290001Sglebius	static char pathbuf[MAXPATHLEN];
69290001Sglebius
70290001Sglebius	snprintf(pathbuf, sizeof pathbuf, "%s/%s", pwpath, file);
71290001Sglebius	return pathbuf;
72290001Sglebius}
73290001Sglebius
74290001Sglebiusint
75290001Sglebiuspwdb(char *arg,...)
76290001Sglebius{
77290001Sglebius	int             i = 0;
78290001Sglebius	pid_t           pid;
79290001Sglebius	va_list         ap;
80290001Sglebius	char           *args[10];
81290001Sglebius
82290001Sglebius	args[i++] = _PATH_PWD_MKDB;
83290001Sglebius	va_start(ap, arg);
84290001Sglebius	while (i < 6 && arg != NULL) {
85290001Sglebius		args[i++] = arg;
86290001Sglebius		arg = va_arg(ap, char *);
87290001Sglebius	}
88290001Sglebius	if (pwpath != pathpwd) {
89290001Sglebius		args[i++] = "-d";
90290001Sglebius		args[i++] = pwpath;
91290001Sglebius	}
92290001Sglebius	args[i++] = getpwpath(_MASTERPASSWD);
93290001Sglebius	args[i] = NULL;
94290001Sglebius
95290001Sglebius	if ((pid = fork()) == -1)	/* Error (errno set) */
96290001Sglebius		i = errno;
97290001Sglebius	else if (pid == 0) {	/* Child */
98290001Sglebius		execv(args[0], args);
99290001Sglebius		_exit(1);
100290001Sglebius	} else {		/* Parent */
101290001Sglebius		waitpid(pid, &i, 0);
102290001Sglebius		if (WEXITSTATUS(i))
103290001Sglebius			i = EIO;
104290001Sglebius	}
105290001Sglebius	return i;
106290001Sglebius}
107290001Sglebius
108290001Sglebiusint
109290001Sglebiusfmtpwentry(char *buf, struct passwd * pwd, int type)
110290001Sglebius{
111290001Sglebius	int             l;
112290001Sglebius	char           *pw;
113290001Sglebius
114290001Sglebius	pw = (pwd->pw_passwd == NULL || !*pwd->pw_passwd) ? "" : (type == PWF_MASTER) ? pwd->pw_passwd : "*";
115290001Sglebius
116290001Sglebius	if (type == PWF_PASSWD)
117290001Sglebius		l = sprintf(buf, "%s:*:%ld:%ld:%s:%s:%s\n",
118290001Sglebius		       pwd->pw_name, (long) pwd->pw_uid, (long) pwd->pw_gid,
119290001Sglebius			    pwd->pw_gecos ? pwd->pw_gecos : "User &",
120290001Sglebius			    pwd->pw_dir, pwd->pw_shell);
121290001Sglebius	else
122290001Sglebius		l = sprintf(buf, "%s:%s:%ld:%ld:%s:%lu:%lu:%s:%s:%s\n",
123290001Sglebius		   pwd->pw_name, pw, (long) pwd->pw_uid, (long) pwd->pw_gid,
124290001Sglebius			    pwd->pw_class ? pwd->pw_class : "",
125290001Sglebius			    (unsigned long) pwd->pw_change,
126290001Sglebius			    (unsigned long) pwd->pw_expire,
127290001Sglebius			    pwd->pw_gecos, pwd->pw_dir, pwd->pw_shell);
128290001Sglebius	return l;
129290001Sglebius}
130290001Sglebius
131290001Sglebius
132290001Sglebiusint
133290001Sglebiusfmtpwent(char *buf, struct passwd * pwd)
134290001Sglebius{
135290001Sglebius	return fmtpwentry(buf, pwd, PWF_STANDARD);
136290001Sglebius}
137290001Sglebius
138290001Sglebiusstatic int
139290001Sglebiuspw_update(struct passwd * pwd, char const * user, int mode)
140290001Sglebius{
141290001Sglebius	int             rc = 0;
142290001Sglebius
143290001Sglebius	ENDPWENT();
144290001Sglebius
145290001Sglebius	/*
146290001Sglebius	 * First, let's check the see if the database is alright
147290001Sglebius	 * Note: -C is only available in FreeBSD 2.2 and above
148290001Sglebius	 */
149290001Sglebius#ifdef HAVE_PWDB_C
150290001Sglebius	if (pwdb("-C", NULL) == 0) {	/* Check only */
151290001Sglebius#else
152290001Sglebius	{				/* No -C */
153290001Sglebius#endif
154290001Sglebius		char            pfx[PWBUFSZ];
155290001Sglebius		char            pwbuf[PWBUFSZ];
156290001Sglebius		int             l = snprintf(pfx, PWBUFSZ, "%s:", user);
157290001Sglebius#ifdef HAVE_PWDB_U
158290001Sglebius		int		isrename = pwd!=NULL && strcmp(user, pwd->pw_name);
159290001Sglebius#endif
160290001Sglebius
161290001Sglebius		/*
162290001Sglebius		 * Update the passwd file first
163290001Sglebius		 */
164290001Sglebius		if (pwd == NULL)
165290001Sglebius			*pwbuf = '\0';
166290001Sglebius		else
167290001Sglebius			fmtpwentry(pwbuf, pwd, PWF_PASSWD);
168290001Sglebius
169290001Sglebius		if (l < 0)
170290001Sglebius			l = 0;
171290001Sglebius		rc = fileupdate(getpwpath(_PASSWD), 0644, pwbuf, pfx, l, mode);
172290001Sglebius		if (rc == 0) {
173290001Sglebius
174290001Sglebius			/*
175290001Sglebius			 * Then the master.passwd file
176290001Sglebius			 */
177290001Sglebius			if (pwd != NULL)
178290001Sglebius				fmtpwentry(pwbuf, pwd, PWF_MASTER);
179290001Sglebius			rc = fileupdate(getpwpath(_MASTERPASSWD), 0600, pwbuf, pfx, l, mode);
180290001Sglebius			if (rc == 0) {
181290001Sglebius#ifdef HAVE_PWDB_U
182290001Sglebius				if (mode == UPD_DELETE || isrename)
183290001Sglebius#endif
184290001Sglebius					rc = pwdb(NULL);
185290001Sglebius#ifdef HAVE_PWDB_U
186290001Sglebius				else
187290001Sglebius					rc = pwdb("-u", user, NULL);
188290001Sglebius#endif
189290001Sglebius			}
190290001Sglebius		}
191290001Sglebius	}
192290001Sglebius	return rc;
193290001Sglebius}
194290001Sglebius
195290001Sglebiusint
196290001Sglebiusaddpwent(struct passwd * pwd)
197290001Sglebius{
198290001Sglebius	return pw_update(pwd, pwd->pw_name, UPD_CREATE);
199290001Sglebius}
200290001Sglebius
201290001Sglebiusint
202290001Sglebiuschgpwent(char const * login, struct passwd * pwd)
203290001Sglebius{
204290001Sglebius	return pw_update(pwd, login, UPD_REPLACE);
205290001Sglebius}
206290001Sglebius
207290001Sglebiusint
208290001Sglebiusdelpwent(struct passwd * pwd)
209290001Sglebius{
210290001Sglebius	return pw_update(NULL, pwd->pw_name, UPD_DELETE);
211290001Sglebius}
212290001Sglebius