From 5fd83771641d15c418f747bd343ba6738d3875f7 Mon Sep 17 00:00:00 2001 From: Cameron Katri Date: Sun, 9 May 2021 14:20:58 -0400 Subject: Import macOS userland adv_cmds-176 basic_cmds-55 bootstrap_cmds-116.100.1 developer_cmds-66 diskdev_cmds-667.40.1 doc_cmds-53.60.1 file_cmds-321.40.3 mail_cmds-35 misc_cmds-34 network_cmds-606.40.1 patch_cmds-17 remote_cmds-63 shell_cmds-216.60.1 system_cmds-880.60.2 text_cmds-106 --- system_cmds/chpass.tproj/IMPORT_NOTES | 1 + system_cmds/chpass.tproj/chpass.1 | 315 ++++++++++++++++++++ system_cmds/chpass.tproj/chpass.c | 457 ++++++++++++++++++++++++++++++ system_cmds/chpass.tproj/chpass.h | 132 +++++++++ system_cmds/chpass.tproj/edit.c | 415 +++++++++++++++++++++++++++ system_cmds/chpass.tproj/field.c | 345 ++++++++++++++++++++++ system_cmds/chpass.tproj/open_directory.c | 205 ++++++++++++++ system_cmds/chpass.tproj/open_directory.h | 13 + system_cmds/chpass.tproj/pw_copy.c | 127 +++++++++ system_cmds/chpass.tproj/pw_copy.h | 56 ++++ system_cmds/chpass.tproj/table.c | 117 ++++++++ system_cmds/chpass.tproj/util.c | 335 ++++++++++++++++++++++ 12 files changed, 2518 insertions(+) create mode 100644 system_cmds/chpass.tproj/IMPORT_NOTES create mode 100644 system_cmds/chpass.tproj/chpass.1 create mode 100644 system_cmds/chpass.tproj/chpass.c create mode 100644 system_cmds/chpass.tproj/chpass.h create mode 100644 system_cmds/chpass.tproj/edit.c create mode 100644 system_cmds/chpass.tproj/field.c create mode 100644 system_cmds/chpass.tproj/open_directory.c create mode 100644 system_cmds/chpass.tproj/open_directory.h create mode 100644 system_cmds/chpass.tproj/pw_copy.c create mode 100644 system_cmds/chpass.tproj/pw_copy.h create mode 100644 system_cmds/chpass.tproj/table.c create mode 100644 system_cmds/chpass.tproj/util.c (limited to 'system_cmds/chpass.tproj') diff --git a/system_cmds/chpass.tproj/IMPORT_NOTES b/system_cmds/chpass.tproj/IMPORT_NOTES new file mode 100644 index 0000000..457907b --- /dev/null +++ b/system_cmds/chpass.tproj/IMPORT_NOTES @@ -0,0 +1 @@ +chpass.1 - FreeBSD file with references to yp items deleted diff --git a/system_cmds/chpass.tproj/chpass.1 b/system_cmds/chpass.tproj/chpass.1 new file mode 100644 index 0000000..7ee45ae --- /dev/null +++ b/system_cmds/chpass.tproj/chpass.1 @@ -0,0 +1,315 @@ +.\" Copyright (c) 1988, 1990, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)chpass.1 8.2 (Berkeley) 12/30/93 +.\" $FreeBSD: src/usr.bin/chpass/chpass.1,v 1.38.2.1 2005/09/24 01:59:39 keramida Exp $ +.\" +.Dd December 30, 1993 +.Dt CHPASS 1 +.Os +.Sh NAME +.Nm chpass , +.Nm chfn , +.Nm chsh +.\".Nm ypchpass , +.\".Nm ypchfn , +.\".Nm ypchsh +.Nd add or change user database information +.Sh SYNOPSIS +.Nm +.\".Op Fl a Ar list +.\".Op Fl p Ar encpass +.\".Op Fl e Ar expiretime +.Op Fl l Ar location +.Op Fl u Ar authname +.Op Fl s Ar newshell +.Op user +.Sh DESCRIPTION +The +.Nm +utility +allows editing of the user database information associated +with +.Ar user +or, by default, the current user. +.Pp +The +.Nm +utility +.Em cannot +change the user's password on Open Directory +systems. Use the +.Xr passwd 1 +utility instead. +.Pp +The +.Nm chfn , +and +.Nm chsh +.\".Nm ypchpass , +.\".Nm ypchfn +.\"and +.\".Nm ypchsh +utilities behave identically to +.Nm . +(There is only one program.) +.Pp +The information is formatted and supplied to an editor for changes. +.Pp +Only the information that the user is allowed to change is displayed. +.Pp +The options are as follows: +.Bl -tag -width indent +.\".It Fl a +.\"The super-user is allowed to directly supply a user database +.\"entry, in the format specified by +.\".Xr passwd 5 , +.\"as an argument. +.\"This argument must be a colon +.\".Pq Dq \&: +.\"separated list of all the +.\"user database fields, although they may be empty. +.\".It Fl p +.\"The super-user is allowed to directly supply an encrypted password field, +.\"in the format used by +.\".Xr crypt 3 , +.\"as an argument. +.\".It Fl e Ar expiretime +.\"Change the account expire time. +.\"This option is used to set the expire time +.\"from a script as if it were done in the interactive editor. +.It Fl l Ar location +If not specified, +.Nm +will perform a search for the user record on all available +Open Directory nodes. +When specified, +.Nm +will edit the user record on the directory node at the given +.Ar location . +.It Fl u Ar authname +The user name to use when authenticating to the directory node containing the +user. +.It Fl s Ar newshell +Attempt to change the user's shell to +.Ar newshell . +.El +.Pp +Possible display items are as follows: +.Pp +.Bl -tag -width "Other Information:" -compact -offset indent +.It Login: +user's login name +.\".It Password: +.\"user's encrypted password +.It Uid: +user's login +.It Gid: +user's login group +.It Generated uid: +user's UUID +.\".It Class: +.\"user's general classification +.\".It Change: +.\"password change time +.\".It Expire: +.\"account expiration time +.It Full Name: +user's real name +.It Office Location: +user's office location +.It Office Phone: +user's office phone +.It Home Phone: +user's home phone +.\".It Other Information: +.\"any locally defined parameters for user +.It Home Directory: +user's home directory +.It Shell: +user's login shell +.Pp +.\".It NOTE(1) - +.\"In the actual master.passwd file, these fields are comma-delimited +.\"fields embedded in the FullName field. +.El +.Pp +The +.Ar login +field is the user name used to access the computer account. +.\".Pp +.\"The +.\".Ar password +.\"field contains the encrypted form of the user's password. +.Pp +The +.Ar uid +field is the number associated with the +.Ar login +field. +Both of these fields should be unique across the system (and often +across a group of systems) as they control file access. +.Pp +While it is possible to have multiple entries with identical login names +and/or identical user id's, it is usually a mistake to do so. +Routines +that manipulate these files will often return only one of the multiple +entries, and that one by random selection. +.Pp +The +.Ar group +field is the group that the user will be placed in at login. +Since +.Bx +supports multiple groups (see +.Xr groups 1 ) +this field currently has little special meaning. +This field may be filled in with either a number or a group name (see +.Xr group 5 ) . +.Pp +The +.Ar generated uid +field is the globally unique identifier (UUID) for the user. +.\".Pp +.\"The +.\".Ar class +.\"field references class descriptions in +.\".Pa /etc/login.conf +.\"and is typically used to initialize the user's system resource limits +.\"when they login. +.\".Pp +.\"The +.\".Ar change +.\"field is the date by which the password must be changed. +.\".Pp +.\"The +.\".Ar expire +.\"field is the date on which the account expires. +.\".Pp +.\"Both the +.\".Ar change +.\"and +.\".Ar expire +.\"fields should be entered in the form +.\".Dq month day year +.\"where +.\".Ar month +.\"is the month name (the first three characters are sufficient), +.\".Ar day +.\"is the day of the month, and +.\".Ar year +.\"is the year. +.\".Pp +.\"Five fields are available for storing the user's +.\".Ar full name , office location , +.\".Ar work +.\"and +.\".Ar home telephone +.\"numbers and finally +.\".Ar other information +.\"which is a single comma delimited string to represent any additional +.\"gcos fields (typically used for site specific user information). +.\"Note that +.\".Xr finger 1 +.\"will display the office location and office phone together under the +.\"heading +.\".Ar Office: . +The +.Ar full name +field contains the full name of the user. +.Pp +The user's +.Ar home directory +is the full +.Ux +path name where the user +will be placed at login. +.Pp +The +.Ar shell +field is the command interpreter the user prefers. +If the +.Ar shell +field is empty, the Bourne shell, +.Pa /bin/sh , +is assumed. +When altering a login shell, and not the super-user, the user +may not change from a non-standard shell or to a non-standard +shell. +Non-standard is defined as a shell not found in +.Pa /etc/shells . +.Pp +The +.Ar picture +field is the path to a picture to be displayed for the user. +.Sh OPEN DIRECTORY +User database entries are under the control of +.Xr DirectoryService 8 +and may be physically located in many different places, +including the local Directory Service node, +and remote LDAP servers. +This version of +.Nm +uses Open Directory to change user database information. +It does not interact with the historic flat file +database +.Pa /etc/master.passwd +. +.Sh ENVIRONMENT +The +.Xr vi 1 +editor will be used unless the environment variable +.Ev EDITOR +is set to +an alternate editor. +When the editor terminates, the information is re-read and used to +update the user database itself. +Only the user, or the super-user, may edit the information associated +with the user. +.Sh FILES +.Bl -tag -width /etc/chpass.XXXXXX -compact +.It Pa /etc/chpass.XXXXXX +temporary copy of the data to edit +.It Pa /etc/shells +the list of approved shells +.El +.Sh SEE ALSO +.\".Xr finger 1 , +.Xr login 1 , +.Xr passwd 1 , +.Xr getusershell 3 , +.Xr passwd 5 +.Rs +.%A Robert Morris +.%A Ken Thompson +.%T "UNIX Password security" +.Re +.Sh HISTORY +The +.Nm +utility appeared in +.Bx 4.3 Reno . diff --git a/system_cmds/chpass.tproj/chpass.c b/system_cmds/chpass.tproj/chpass.c new file mode 100644 index 0000000..6b265c0 --- /dev/null +++ b/system_cmds/chpass.tproj/chpass.c @@ -0,0 +1,457 @@ +/* + * Copyright (c) 1999-2016 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/*- + * Copyright (c) 1988, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 2002 Networks Associates Technology, Inc. + * All rights reserved. + * + * Portions of this software were developed for the FreeBSD Project by + * ThinkSec AS and NAI Labs, the Security Research Division of Network + * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 + * ("CBOSS"), as part of the DARPA CHATS research program. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#if 0 +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1988, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)chpass.c 8.4 (Berkeley) 4/2/94"; +#endif /* not lint */ +#endif +#include +__FBSDID("$FreeBSD: src/usr.bin/chpass/chpass.c,v 1.27.8.1 2006/09/29 06:13:20 marck Exp $"); +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#ifdef YP +#include +#endif + +#ifndef OPEN_DIRECTORY +#include +#include +#endif + +#include "chpass.h" + +int master_mode; + +#ifdef OPEN_DIRECTORY +#include "open_directory.h" +char *progname = NULL; +CFStringRef DSPath = NULL; +#endif /* OPEN_DIRECTORY */ + +static void baduser(void); +static void usage(void); + +int +main(int argc, char *argv[]) +{ + enum { NEWSH, LOADENTRY, EDITENTRY, NEWPW, NEWEXP } op; +#ifndef OPEN_DIRECTORY + struct passwd lpw, *old_pw, *pw; + int ch, pfd, tfd; + const char *password; +#else + struct passwd *old_pw, *pw; + int ch, tfd; + char tfn[MAXPATHLEN]; + char *tmpdir; +#endif + char *arg = NULL; + uid_t uid; +#ifdef YP + struct ypclnt *ypclnt; + const char *yp_domain = NULL, *yp_host = NULL; +#endif +#ifdef OPEN_DIRECTORY + CFStringRef username = NULL; + CFStringRef authname = NULL; + CFStringRef location = NULL; + + progname = strrchr(argv[0], '/'); + if (progname) progname++; + else progname = argv[0]; +#endif /* OPEN_DIRECTORY */ + + pw = old_pw = NULL; + op = EDITENTRY; +#ifdef OPEN_DIRECTORY + while ((ch = getopt(argc, argv, "a:s:l:u:")) != -1) +#else /* OPEN_DIRECTORY */ +#ifdef YP + while ((ch = getopt(argc, argv, "a:p:s:e:d:h:loy")) != -1) +#else + while ((ch = getopt(argc, argv, "a:p:s:e:")) != -1) +#endif +#endif /* OPEN_DIRECTORY */ + switch (ch) { + case 'a': + op = LOADENTRY; + arg = optarg; + break; + case 's': + op = NEWSH; + arg = optarg; + break; +#ifndef OPEN_DIRECTORY + case 'p': + op = NEWPW; + arg = optarg; + break; + case 'e': + op = NEWEXP; + arg = optarg; + break; +#ifdef YP + case 'd': + yp_domain = optarg; + break; + case 'h': + yp_host = optarg; + break; + case 'l': + case 'o': + case 'y': + /* compatibility */ + break; +#endif +#else /* OPEN_DIRECTORY */ + case 'l': + location = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8); + break; + case 'u': + authname = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8); + break; +#endif + case '?': + default: + usage(); + } + + argc -= optind; + argv += optind; + + if (argc > 1) + usage(); + + uid = getuid(); + + if (op == EDITENTRY || op == NEWSH || op == NEWPW || op == NEWEXP) { + if (argc == 0) { + if ((pw = getpwuid(uid)) == NULL) + errx(1, "unknown user: uid %lu", + (unsigned long)uid); + } else { + if ((pw = getpwnam(*argv)) == NULL) + errx(1, "unknown user: %s", *argv); +#ifndef OPEN_DIRECTORY + if (uid != 0 && uid != pw->pw_uid) + baduser(); +#endif + } + +#ifndef OPEN_DIRECTORY + /* Make a copy for later verification */ + if ((pw = pw_dup(pw)) == NULL || + (old_pw = pw_dup(pw)) == NULL) + err(1, "pw_dup"); +#endif + } + +#if OPEN_DIRECTORY + master_mode = (uid == 0); + + /* + * Find the user record and copy its details. + */ + username = CFStringCreateWithCString(NULL, pw->pw_name, kCFStringEncodingUTF8); + + if (strcmp(progname, "chsh") == 0 || op == NEWSH) { + cfprintf(stderr, "Changing shell for %@.\n", username); + } else if (strcmp(progname, "chfn") == 0) { + cfprintf(stderr, "Changing finger information for %@.\n", username); + } else if (strcmp(progname, "chpass") == 0) { + cfprintf(stderr, "Changing account information for %@.\n", username); + } + + /* + * odGetUser updates DSPath global variable, performs authentication + * if necessary, and extracts the attributes. + */ + CFDictionaryRef attrs_orig = NULL; + CFDictionaryRef attrs = NULL; + ODRecordRef rec = odGetUser(location, authname, username, &attrs_orig); + + if (!rec || !attrs_orig) exit(1); +#endif /* OPEN_DIRECTORY */ + +#ifdef YP + if (pw != NULL && (pw->pw_fields & _PWF_SOURCE) == _PWF_NIS) { + ypclnt = ypclnt_new(yp_domain, "passwd.byname", yp_host); + master_mode = (ypclnt != NULL && + ypclnt_connect(ypclnt) != -1 && + ypclnt_havepasswdd(ypclnt) == 1); + ypclnt_free(ypclnt); + } else +#endif + master_mode = (uid == 0); + + if (op == NEWSH) { + /* protect p_shell -- it thinks NULL is /bin/sh */ + if (!arg[0]) + usage(); + if (p_shell(arg, pw, (ENTRY *)NULL) == -1) + exit(1); +#ifdef OPEN_DIRECTORY + else { + ENTRY* ep; + + setrestricted(attrs_orig); + + for (ep = list; ep->prompt; ep++) { + if (strncasecmp(ep->prompt, "shell", ep->len) == 0) { + if (!ep->restricted) { + CFStringRef shell = CFStringCreateWithCString(NULL, arg, kCFStringEncodingUTF8); + if (shell) { + attrs = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (attrs) CFDictionarySetValue((CFMutableDictionaryRef)attrs, kODAttributeTypeUserShell, shell); + CFRelease(shell); + } + } else { + warnx("shell is restricted"); + exit(1); + } + } + } + } +#endif + } + +#ifndef OPEN_DIRECTORY + if (op == NEWEXP) { + if (uid) /* only root can change expire */ + baduser(); + if (p_expire(arg, pw, (ENTRY *)NULL) == -1) + exit(1); + } +#endif + + if (op == LOADENTRY) { + if (uid) + baduser(); +#ifdef OPEN_DIRECTORY + warnx("-a is not supported for Open Directory."); + exit(1); +#else + pw = &lpw; + old_pw = NULL; + if (!__pw_scan(arg, pw, _PWSCAN_WARN|_PWSCAN_MASTER)) + exit(1); +#endif /* OPEN_DIRECTORY */ + } + +#ifndef OPEN_DIRECTORY + if (op == NEWPW) { + if (uid) + baduser(); + + if (strchr(arg, ':')) + errx(1, "invalid format for password"); + pw->pw_passwd = arg; + } +#endif /* OPEN_DIRECTORY */ + + if (op == EDITENTRY) { +#ifdef OPEN_DIRECTORY + setrestricted(attrs_orig); + tmpdir = getenv("TMPDIR"); + if (!tmpdir) + tmpdir = P_tmpdir; // defined in the system headers, defaults to /tmp + snprintf(tfn, sizeof(tfn), "%s/%s.XXXXXX", tmpdir, progname); + if ((tfd = mkstemp(tfn)) == -1) + err(1, "%s", tfn); + attrs = (CFMutableDictionaryRef)edit(tfn, attrs_orig); + (void)unlink(tfn); +#else + /* + * We don't really need pw_*() here, but pw_edit() (used + * by edit()) is just too useful... + */ + if (pw_init(NULL, NULL)) + err(1, "pw_init()"); + if ((tfd = pw_tmp(-1)) == -1) { + pw_fini(); + err(1, "pw_tmp()"); + } + free(pw); + pw = edit(pw_tempname(), old_pw); + pw_fini(); + if (pw == NULL) + err(1, "edit()"); + /* + * pw_equal does not check for crypted passwords, so we + * should do it explicitly + */ + if (pw_equal(old_pw, pw) && + strcmp(old_pw->pw_passwd, pw->pw_passwd) == 0) + errx(0, "user information unchanged"); +#endif /* OPEN_DIRECTORY */ + } + +#ifndef OPEN_DIRECTORY + if (old_pw && !master_mode) { + password = getpass("Password: "); + if (strcmp(crypt(password, old_pw->pw_passwd), + old_pw->pw_passwd) != 0) + baduser(); + } else { + password = ""; + } +#endif + +#ifdef OPEN_DIRECTORY + odUpdateUser(rec, attrs_orig, attrs); + + if (rec) CFRelease(rec); + + exit(0); + return 0; +#else /* OPEN_DIRECTORY */ + exit(0); + if (old_pw != NULL) + pw->pw_fields |= (old_pw->pw_fields & _PWF_SOURCE); + switch (pw->pw_fields & _PWF_SOURCE) { +#ifdef YP + case _PWF_NIS: + ypclnt = ypclnt_new(yp_domain, "passwd.byname", yp_host); + if (ypclnt == NULL || + ypclnt_connect(ypclnt) == -1 || + ypclnt_passwd(ypclnt, pw, password) == -1) { + warnx("%s", ypclnt->error); + ypclnt_free(ypclnt); + exit(1); + } + ypclnt_free(ypclnt); + errx(0, "NIS user information updated"); +#endif /* YP */ + case 0: + case _PWF_FILES: + if (pw_init(NULL, NULL)) + err(1, "pw_init()"); + if ((pfd = pw_lock()) == -1) { + pw_fini(); + err(1, "pw_lock()"); + } + if ((tfd = pw_tmp(-1)) == -1) { + pw_fini(); + err(1, "pw_tmp()"); + } + if (pw_copy(pfd, tfd, pw, old_pw) == -1) { + pw_fini(); + err(1, "pw_copy"); + } + if (pw_mkdb(pw->pw_name) == -1) { + pw_fini(); + err(1, "pw_mkdb()"); + } + pw_fini(); + errx(0, "user information updated"); + break; + default: + errx(1, "unsupported passwd source"); + } +#endif /* OPEN_DIRECTORY */ +} + +static void +baduser(void) +{ + errx(1, "%s", strerror(EACCES)); +} + +static void +usage(void) +{ + (void)fprintf(stderr, + "usage: chpass%s %s [user]\n", +#ifdef OPEN_DIRECTORY + "", + "[-l location] [-u authname] [-s shell]"); +#else /* OPEN_DIRECTORY */ +#ifdef YP + " [-d domain] [-h host]", +#else + "", +#endif + "[-a list] [-p encpass] [-s shell] [-e mmm dd yy]"); +#endif /* OPEN_DIRECTORY */ + exit(1); +} diff --git a/system_cmds/chpass.tproj/chpass.h b/system_cmds/chpass.tproj/chpass.h new file mode 100644 index 0000000..739601f --- /dev/null +++ b/system_cmds/chpass.tproj/chpass.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 1999-2016 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Copyright (c) 1988, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 2002 Networks Associates Technology, Inc. + * All rights reserved. + * + * Portions of this software were developed for the FreeBSD Project by + * ThinkSec AS and NAI Labs, the Security Research Division of Network + * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 + * ("CBOSS"), as part of the DARPA CHATS research program. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)chpass.h 8.4 (Berkeley) 4/2/94 + * $FreeBSD: src/usr.bin/chpass/chpass.h,v 1.7 2004/01/18 21:46:39 charnier Exp $ + */ + +#ifdef OPEN_DIRECTORY +#include "open_directory.h" + +extern char* progname; +extern CFStringRef DSPath; +#endif /* OPEN_DIRECTORY */ + +struct passwd; + +typedef struct _entry { + const char *prompt; +#ifdef OPEN_DIRECTORY + void (*display)(); +#endif + int (*func)(char *, struct passwd *, struct _entry *); + int restricted; + size_t len; +#if OPEN_DIRECTORY + char *except; + const CFStringRef *attrName; +#else /* OPEN_DIRECTORY */ + char *except, *save; +#endif /* OPEN_DIRECTORY */ +} ENTRY; + +/* Field numbers. */ +#define E_BPHONE 8 +#define E_HPHONE 9 +#define E_LOCATE 10 +#define E_NAME 7 +#define E_OTHER 11 +#define E_SHELL 13 + +extern ENTRY list[]; +extern int master_mode; + +#ifdef OPEN_DIRECTORY +/* edit.c */ +void display_time(CFDictionaryRef, CFStringRef, const char*, FILE *); +void display_string(CFDictionaryRef, CFStringRef, const char*, FILE *); +CFDictionaryRef edit(const char *tfn, CFDictionaryRef pw); + +/* util.c */ +int cfprintf(FILE* file, const char* format, ...); +int editfile(const char* tfn); +#endif /* OPEN_DIRECTORY */ + +int atot(char *, time_t *); +#ifndef OPEN_DIRECTORY +struct passwd *edit(const char *, struct passwd *); +#endif /* OPEN_DIRECTORY */ +int ok_shell(char *); +char *dup_shell(char *); +int p_change(char *, struct passwd *, ENTRY *); +int p_class(char *, struct passwd *, ENTRY *); +int p_expire(char *, struct passwd *, ENTRY *); +int p_gecos(char *, struct passwd *, ENTRY *); +int p_gid(char *, struct passwd *, ENTRY *); +int p_hdir(char *, struct passwd *, ENTRY *); +int p_login(char *, struct passwd *, ENTRY *); +int p_passwd(char *, struct passwd *, ENTRY *); +int p_shell(char *, struct passwd *, ENTRY *); +int p_uid(char *, struct passwd *, ENTRY *); +#ifdef OPEN_DIRECTORY +int p_uuid(char *, struct passwd *, ENTRY *); +#endif /* OPEN_DIRECTORY */ +char *ttoa(time_t); diff --git a/system_cmds/chpass.tproj/edit.c b/system_cmds/chpass.tproj/edit.c new file mode 100644 index 0000000..7c87050 --- /dev/null +++ b/system_cmds/chpass.tproj/edit.c @@ -0,0 +1,415 @@ +/* + * Copyright (c) 1999-2016 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 2002 Networks Associates Technology, Inc. + * All rights reserved. + * + * Portions of this software were developed for the FreeBSD Project by + * ThinkSec AS and NAI Labs, the Security Research Division of Network + * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 + * ("CBOSS"), as part of the DARPA CHATS research program. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#if 0 +#ifndef lint +static char sccsid[] = "@(#)edit.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ +#endif + +#include +__FBSDID("$FreeBSD: src/usr.bin/chpass/edit.c,v 1.23 2003/04/09 18:18:42 des Exp $"); +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef OPEN_DIRECTORY +#include +#include +#endif + +#include "chpass.h" + +#ifdef OPEN_DIRECTORY +static int display(const char *tfn, CFDictionaryRef attrs); +static CFDictionaryRef verify(const char *tfn, CFDictionaryRef attrs); +#else +static int display(const char *tfn, struct passwd *pw); +static struct passwd *verify(const char *tfn, struct passwd *pw); +#endif + +#ifdef OPEN_DIRECTORY +CFDictionaryRef +edit(const char *tfn, CFDictionaryRef pw) +#else +struct passwd * +edit(const char *tfn, struct passwd *pw) +#endif +{ +#ifdef OPEN_DIRECTORY + CFDictionaryRef npw; +#else + struct passwd *npw; +#endif + char *line; + size_t len; + + if (display(tfn, pw) == -1) + return (NULL); + for (;;) { +#ifdef OPEN_DIRECTORY + switch (editfile(tfn)) { +#else + switch (pw_edit(1)) { +#endif + case -1: + return (NULL); + case 0: +#ifdef OPEN_DIRECTORY + return (NULL); +#else + return (pw_dup(pw)); +#endif + default: + break; + } + if ((npw = verify(tfn, pw)) != NULL) + return (npw); +#ifndef OPEN_DIRECTORY + free(npw); +#endif + printf("re-edit the password file? "); + fflush(stdout); + if ((line = fgetln(stdin, &len)) == NULL) { + warn("fgetln()"); + return (NULL); + } + if (len > 0 && (*line == 'N' || *line == 'n')) + return (NULL); + } +} + +/* + * display -- + * print out the file for the user to edit; strange side-effect: + * set conditional flag if the user gets to edit the shell. + */ +#if OPEN_DIRECTORY +static int +display(const char *tfn, CFDictionaryRef attrs) +#else +static int +display(const char *tfn, struct passwd *pw) +#endif +{ + FILE *fp; +#ifndef OPEN_DIRECTORY + char *bp, *gecos, *p; +#endif + + if ((fp = fopen(tfn, "w")) == NULL) { + warn("%s", tfn); + return (-1); + } + +#ifdef OPEN_DIRECTORY + CFArrayRef values = CFDictionaryGetValue(attrs, kODAttributeTypeRecordName); + CFStringRef username = (values && CFArrayGetCount(values)) > 0 ? CFArrayGetValueAtIndex(values, 0) : NULL; + + (void)cfprintf(fp, + "# Changing user information for %@.\n" + "# Use \"passwd\" to change the password.\n" + "##\n" + "# Open Directory%s%@\n" + "##\n", + username, + DSPath ? ": " : "", + DSPath ? DSPath : CFSTR("")); + + int ndisplayed = 0; + ENTRY* ep; + for (ep = list; ep->prompt; ep++) + if (!ep->restricted) { + ep->display(attrs, *ep->attrName, ep->prompt, fp); + ndisplayed++; + } + if(!ndisplayed) { + (void)fprintf(fp, "###################################\n"); + (void)fprintf(fp, "# No fields are available to change\n"); + (void)fprintf(fp, "###################################\n"); + } +#else /* OPEN_DIRECTORY */ + (void)fprintf(fp, + "#Changing user information for %s.\n", pw->pw_name); + if (master_mode) { + (void)fprintf(fp, "Login: %s\n", pw->pw_name); + (void)fprintf(fp, "Password: %s\n", pw->pw_passwd); + (void)fprintf(fp, "Uid [#]: %lu\n", (unsigned long)pw->pw_uid); + (void)fprintf(fp, "Gid [# or name]: %lu\n", + (unsigned long)pw->pw_gid); + (void)fprintf(fp, "Change [month day year]: %s\n", + ttoa(pw->pw_change)); + (void)fprintf(fp, "Expire [month day year]: %s\n", + ttoa(pw->pw_expire)); + (void)fprintf(fp, "Class: %s\n", pw->pw_class); + (void)fprintf(fp, "Home directory: %s\n", pw->pw_dir); + (void)fprintf(fp, "Shell: %s\n", + *pw->pw_shell ? pw->pw_shell : _PATH_BSHELL); + } + /* Only admin can change "restricted" shells. */ +#if 0 + else if (ok_shell(pw->pw_shell)) + /* + * Make shell a restricted field. Ugly with a + * necklace, but there's not much else to do. + */ +#else + else if ((!list[E_SHELL].restricted && ok_shell(pw->pw_shell)) || + master_mode) + /* + * If change not restrict (table.c) and standard shell + * OR if root, then allow editing of shell. + */ +#endif + (void)fprintf(fp, "Shell: %s\n", + *pw->pw_shell ? pw->pw_shell : _PATH_BSHELL); + else + list[E_SHELL].restricted = 1; + + if ((bp = gecos = strdup(pw->pw_gecos)) == NULL) { + warn(NULL); + fclose(fp); + return (-1); + } + + p = strsep(&bp, ","); + p = strdup(p ? p : ""); + list[E_NAME].save = p; + if (!list[E_NAME].restricted || master_mode) + (void)fprintf(fp, "Full Name: %s\n", p); + + p = strsep(&bp, ","); + p = strdup(p ? p : ""); + list[E_LOCATE].save = p; + if (!list[E_LOCATE].restricted || master_mode) + (void)fprintf(fp, "Office Location: %s\n", p); + + p = strsep(&bp, ","); + p = strdup(p ? p : ""); + list[E_BPHONE].save = p; + if (!list[E_BPHONE].restricted || master_mode) + (void)fprintf(fp, "Office Phone: %s\n", p); + + p = strsep(&bp, ","); + p = strdup(p ? p : ""); + list[E_HPHONE].save = p; + if (!list[E_HPHONE].restricted || master_mode) + (void)fprintf(fp, "Home Phone: %s\n", p); + + bp = strdup(bp ? bp : ""); + list[E_OTHER].save = bp; + if (!list[E_OTHER].restricted || master_mode) + (void)fprintf(fp, "Other information: %s\n", bp); + + free(gecos); +#endif /* OPEN_DIRECTORY */ + + (void)fchown(fileno(fp), getuid(), getgid()); + (void)fclose(fp); + return (0); +} + +#ifdef OPEN_DIRECTORY +static CFDictionaryRef +verify(const char* tfn, CFDictionaryRef pw) +#else +static struct passwd * +verify(const char *tfn, struct passwd *pw) +#endif +{ +#ifdef OPEN_DIRECTORY + CFMutableDictionaryRef npw; +#else + struct passwd *npw; +#endif + ENTRY *ep; + char *buf, *p, *val; + struct stat sb; + FILE *fp; + int line; + size_t len; + +#ifdef OPEN_DIRECTORY + if ((npw = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == NULL) + return (NULL); +#else + if ((pw = pw_dup(pw)) == NULL) + return (NULL); +#endif + if ((fp = fopen(tfn, "r")) == NULL || + fstat(fileno(fp), &sb) == -1) { + warn("%s", tfn); +#ifndef OPEN_DIRECTORY + free(pw); +#endif + return (NULL); + } + if (sb.st_size == 0) { + warnx("corrupted temporary file"); + fclose(fp); +#ifndef OPEN_DIRECTORY + free(pw); +#endif + return (NULL); + } + val = NULL; + for (line = 1; (buf = fgetln(fp, &len)) != NULL; ++line) { + if (*buf == '\0' || *buf == '#') + continue; + while (len > 0 && isspace(buf[len - 1])) + --len; + for (ep = list;; ++ep) { + if (!ep->prompt) { + warnx("%s: unrecognized field on line %d", + tfn, line); + goto bad; + } + if (ep->len > len) + continue; + if (strncasecmp(buf, ep->prompt, ep->len) != 0) + continue; + if (ep->restricted && !master_mode) { + warnx("%s: you may not change the %s field", + tfn, ep->prompt); + goto bad; + } + for (p = buf; p < buf + len && *p != ':'; ++p) + /* nothing */ ; + if (*p != ':') { + warnx("%s: line %d corrupted", tfn, line); + goto bad; + } + while (++p < buf + len && isspace(*p)) + /* nothing */ ; + free(val); + asprintf(&val, "%.*s", (int)(buf + len - p), p); + if (val == NULL) + goto bad; + if (ep->except && strpbrk(val, ep->except)) { + warnx("%s: invalid character in \"%s\" field '%s'", + tfn, ep->prompt, val); + goto bad; + } +#ifdef OPEN_DIRECTORY + if ((ep->func)(val, NULL, NULL)) + goto bad; + { + CFStringRef str = CFStringCreateWithCString(NULL, val, kCFStringEncodingUTF8); + if (str) { + CFDictionarySetValue(npw, *ep->attrName, str); + CFRelease(str); + } + } +#else + if ((ep->func)(val, pw, ep)) + goto bad; +#endif + break; + } + } + free(val); + fclose(fp); + +#ifndef OPEN_DIRECTORY + /* Build the gecos field. */ + len = asprintf(&p, "%s,%s,%s,%s,%s", list[E_NAME].save, + list[E_LOCATE].save, list[E_BPHONE].save, + list[E_HPHONE].save, list[E_OTHER].save); + if (p == NULL) { + warn("asprintf()"); + free(pw); + return (NULL); + } + while (len > 0 && p[len - 1] == ',') + p[--len] = '\0'; + pw->pw_gecos = p; + buf = pw_make(pw); + free(pw); + free(p); + if (buf == NULL) { + warn("pw_make()"); + return (NULL); + } + npw = pw_scan(buf, PWSCAN_WARN|PWSCAN_MASTER); +#endif /* !OPEN_DIRECTORY */ + free(buf); + return (npw); +bad: +#ifndef OPEN_DIRECTORY + free(pw); +#endif + free(val); + fclose(fp); + return (NULL); +} diff --git a/system_cmds/chpass.tproj/field.c b/system_cmds/chpass.tproj/field.c new file mode 100644 index 0000000..5ae326a --- /dev/null +++ b/system_cmds/chpass.tproj/field.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 1999-2016 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Copyright (c) 1988, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 2002 Networks Associates Technology, Inc. + * All rights reserved. + * + * Portions of this software were developed for the FreeBSD Project by + * ThinkSec AS and NAI Labs, the Security Research Division of Network + * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 + * ("CBOSS"), as part of the DARPA CHATS research program. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#if 0 +#ifndef lint +static char sccsid[] = "@(#)field.c 8.4 (Berkeley) 4/2/94"; +#endif /* not lint */ +#endif + +#include +__FBSDID("$FreeBSD: src/usr.bin/chpass/field.c,v 1.9 2004/01/18 21:46:39 charnier Exp $"); +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "chpass.h" + +/* ARGSUSED */ +int +p_login(char *p, struct passwd *pw, ENTRY *ep __unused) +{ + if (!*p) { + warnx("empty login field"); + return (-1); + } + if (*p == '-') { + warnx("login names may not begin with a hyphen"); + return (-1); + } +#ifndef OPEN_DIRECTORY + if (!(pw->pw_name = strdup(p))) { + warnx("can't save entry"); + return (-1); + } +#endif + if (strchr(p, '.')) + warnx("\'.\' is dangerous in a login name"); + for (; *p; ++p) + if (isupper(*p)) { + warnx("upper-case letters are dangerous in a login name"); + break; + } + return (0); +} + +/* ARGSUSED */ +int +p_passwd(char *p, struct passwd *pw, ENTRY *ep __unused) +{ +#ifndef OPEN_DIRECTORY + if (!(pw->pw_passwd = strdup(p))) { + warnx("can't save password entry"); + return (-1); + } +#endif + + return (0); +} + +/* ARGSUSED */ +int +p_uid(char *p, struct passwd *pw, ENTRY *ep __unused) +{ + uid_t id; + char *np; + + if (!*p) { + warnx("empty uid field"); + return (-1); + } + if (!isdigit(*p)) { + warnx("illegal uid"); + return (-1); + } + errno = 0; + id = (uid_t)strtoul(p, &np, 10); + if (*np || (id == (uid_t)ULONG_MAX && errno == ERANGE)) { + warnx("illegal uid"); + return (-1); + } +#ifndef OPEN_DIRECTORY + pw->pw_uid = id; +#endif + return (0); +} + +/* ARGSUSED */ +int +p_gid(char *p, struct passwd *pw, ENTRY *ep __unused) +{ + struct group *gr; + gid_t id; + char *np; + + if (!*p) { + warnx("empty gid field"); + return (-1); + } + if (!isdigit(*p)) { + if (!(gr = getgrnam(p))) { + warnx("unknown group %s", p); + return (-1); + } +#ifndef OPEN_DIRECTORY + pw->pw_gid = gr->gr_gid; +#endif + return (0); + } + errno = 0; + id = (gid_t)strtoul(p, &np, 10); + if (*np || (id == (uid_t)ULONG_MAX && errno == ERANGE)) { + warnx("illegal gid"); + return (-1); + } +#ifndef OPEN_DIRECTORY + pw->pw_gid = id; +#endif + return (0); +} + +/* ARGSUSED */ +int +p_class(char *p, struct passwd *pw, ENTRY *ep __unused) +{ +#ifndef OPEN_DIRECTORY + if (!(pw->pw_class = strdup(p))) { + warnx("can't save entry"); + return (-1); + } +#endif + + return (0); +} + +/* ARGSUSED */ +int +p_change(char *p, struct passwd *pw, ENTRY *ep __unused) +{ +#ifndef OPEN_DIRECTORY + if (!atot(p, &pw->pw_change)) + return (0); + warnx("illegal date for change field"); +#endif + return (-1); +} + +/* ARGSUSED */ +int +p_expire(char *p, struct passwd *pw, ENTRY *ep __unused) +{ +#ifndef OPEN_DIRECTORY + if (!atot(p, &pw->pw_expire)) + return (0); + warnx("illegal date for expire field"); +#endif + return (-1); +} + +/* ARGSUSED */ +int +p_gecos(char *p, struct passwd *pw __unused, ENTRY *ep) +{ +#ifndef OPEN_DIRECTORY + if (!(ep->save = strdup(p))) { + warnx("can't save entry"); + return (-1); + } +#endif + return (0); +} + +/* ARGSUSED */ +int +p_hdir(char *p, struct passwd *pw, ENTRY *ep __unused) +{ + if (!*p) { + warnx("empty home directory field"); + return (-1); + } +#ifndef OPEN_DIRECTORY + if (!(pw->pw_dir = strdup(p))) { + warnx("can't save entry"); + return (-1); + } +#endif + return (0); +} + + +/* ARGSUSED */ +int +p_shell(char *p, struct passwd *pw, ENTRY *ep __unused) +{ + struct stat sbuf; +#ifdef OPEN_DIRECTORY + struct passwd lpw; + pw = &lpw; + memset(pw, 0, sizeof(lpw)); + pw->pw_shell = p; +#endif + +#ifndef OPEN_DIRECTORY + if (!*p) { + pw->pw_shell = strdup(_PATH_BSHELL); + return (0); + } + /* only admin can change from or to "restricted" shells */ + if (!master_mode && pw->pw_shell && !ok_shell(pw->pw_shell)) { + warnx("%s: current shell non-standard", pw->pw_shell); + return (-1); + } +#endif /* !OPEN_DIRECTORY */ + if (!ok_shell(p)) { + if (!master_mode) { + warnx("%s: non-standard shell", p); + return (-1); + } +#ifndef OPEN_DIRECTORY + pw->pw_shell = strdup(p); +#endif + } +#ifndef OPEN_DIRECTORY + else + pw->pw_shell = dup_shell(p); + if (!pw->pw_shell) { + warnx("can't save entry"); + return (-1); + } +#endif + if (stat(pw->pw_shell, &sbuf) < 0) { + if (errno == ENOENT) + warnx("WARNING: shell '%s' does not exist", + pw->pw_shell); + else + warn("WARNING: can't stat shell '%s'", pw->pw_shell); + return (0); + } + if (!S_ISREG(sbuf.st_mode)) { + warnx("WARNING: shell '%s' is not a regular file", + pw->pw_shell); + return (0); + } + if ((sbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) == 0) { + warnx("WARNING: shell '%s' is not executable", pw->pw_shell); + return (0); + } + return (0); +} + +#ifdef OPEN_DIRECTORY +#include +/* ARGSUSED */ +int +p_uuid(char *p, struct passwd *pw __unused, ENTRY *ep) +{ + uuid_t uu; + if (uuid_parse(p, uu) != 0) { + warnx("invalid UUID"); + return (-1); + } + return (0); +} + +void +display_string(CFDictionaryRef attrs, CFStringRef attrName, const char* prompt, FILE *fp) +{ + CFTypeRef value = CFSTR(""); + CFArrayRef values = CFDictionaryGetValue(attrs, attrName); + if (values) { + value = CFArrayGetCount(values) > 0 ? CFArrayGetValueAtIndex(values, 0) : NULL; + if (value && CFGetTypeID(value) != CFStringGetTypeID()) value = NULL; + } + cfprintf(fp, "%s: %@\n", prompt, value); +} +#endif /* OPEN_DIRECTORY */ diff --git a/system_cmds/chpass.tproj/open_directory.c b/system_cmds/chpass.tproj/open_directory.c new file mode 100644 index 0000000..5949eac --- /dev/null +++ b/system_cmds/chpass.tproj/open_directory.c @@ -0,0 +1,205 @@ +#ifdef OPEN_DIRECTORY +#include "open_directory.h" +#include "chpass.h" +#include +#include +#include +#include +#include +#include + +/*--------------------------------------------------------------------------- + * PUBLIC setrestricted - sets the restricted flag + *---------------------------------------------------------------------------*/ +void +setrestricted(CFDictionaryRef attrs) +{ + const char* user_allowed[] = { "shell", "full name", "office location", "office phone", "home phone", "picture", NULL }; + const char* root_restricted[] = { "password", "change", "expire", "class", NULL }; + ENTRY* ep; + const char** pp; + int restrict_by_default = !master_mode; + + // for ordinary users, everything is restricted except for the values + // expressly permitted above + // for root, everything is permitted except for the values expressly + // restricted above + + for (ep = list; ep->prompt; ep++) { + ep->restricted = restrict_by_default; + pp = restrict_by_default ? user_allowed : root_restricted; + for (; *pp; pp++) { + if (strncasecmp(ep->prompt, *pp, ep->len) == 0) { + ep->restricted = !restrict_by_default; + break; + } + } + + // If not root, then it is only permitted to change the shell + // when the original value is one of the approved shells. + // Otherwise, the assumption is that root has given this user + // a restricted shell which they must not change away from. + if (restrict_by_default && strcmp(ep->prompt, "shell") == 0) { + ep->restricted = 1; + CFArrayRef values = CFDictionaryGetValue(attrs, kODAttributeTypeUserShell); + CFTypeRef value = values && CFArrayGetCount(values) > 0 ? CFArrayGetValueAtIndex(values, 0) : NULL; + if (value && CFGetTypeID(value) == CFStringGetTypeID()) { + size_t size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value), kCFStringEncodingUTF8)+1; + char* shell = malloc(size); + if (CFStringGetCString(value, shell, size, kCFStringEncodingUTF8)) { + if (ok_shell(shell)) { + ep->restricted = 0; + } + } + } + } + } +} + +static CFStringRef +prompt_passwd(CFStringRef user) +{ + CFStringRef result = NULL; + CFStringRef prompt = CFStringCreateWithFormat(NULL, NULL, CFSTR("Password for %@: "), user); + size_t prompt_size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(prompt), kCFStringEncodingUTF8); + char* buf = malloc(prompt_size); + CFStringGetCString(prompt, buf, prompt_size, kCFStringEncodingUTF8); + char* pass = getpass(buf); + result = CFStringCreateWithCString(NULL, pass, kCFStringEncodingUTF8); + memset(pass, 0, strlen(pass)); + free(buf); + CFRelease(prompt); + return result; +} + +static void +show_error(CFErrorRef error) { + if (error) { + CFStringRef desc = CFErrorCopyDescription(error); + if (desc) { + cfprintf(stderr, "%s: %@", progname, desc); + CFRelease(desc); + } + desc = CFErrorCopyFailureReason(error); + if (desc) cfprintf(stderr, " %@", desc); + + desc = CFErrorCopyRecoverySuggestion(error); + if (desc) cfprintf(stderr, " %@", desc); + + fprintf(stderr, "\n"); + } +} + +ODRecordRef +odGetUser(CFStringRef location, CFStringRef authname, CFStringRef user, CFDictionaryRef* attrs) +{ + ODNodeRef node = NULL; + ODRecordRef rec = NULL; + CFErrorRef error = NULL; + + assert(attrs); + + /* + * Open the specified node, or perform a search. + * Copy the record and put the record's location into DSPath. + */ + if (location) { + node = ODNodeCreateWithName(NULL, kODSessionDefault, location, &error); + } else { + node = ODNodeCreateWithNodeType(NULL, kODSessionDefault, kODNodeTypeAuthentication, &error); + } + if (node) { + CFTypeRef vals[] = { kODAttributeTypeStandardOnly }; + CFArrayRef desiredAttrs = CFArrayCreate(NULL, vals, 1, &kCFTypeArrayCallBacks); + rec = ODNodeCopyRecord(node, kODRecordTypeUsers, user, desiredAttrs, &error); + if (desiredAttrs) CFRelease(desiredAttrs); + CFRelease(node); + } + if (rec) { + *attrs = ODRecordCopyDetails(rec, NULL, &error); + if (*attrs) { + CFArrayRef values = CFDictionaryGetValue(*attrs, kODAttributeTypeMetaNodeLocation); + DSPath = (values && CFArrayGetCount(values) > 0) ? CFArrayGetValueAtIndex(values, 0) : NULL; + } + + /* + * Prompt for a password if -u was specified, + * or if we are not root, + * or if we are updating something not on the + * local node. + */ + if (authname || !master_mode || + (DSPath && CFStringCompareWithOptions(DSPath, CFSTR("/Local/"), CFRangeMake(0, 7), 0) != kCFCompareEqualTo)) { + + CFStringRef password = NULL; + + if (!authname) authname = user; + + password = prompt_passwd(authname); + if (!ODRecordSetNodeCredentials(rec, authname, password, &error)) { + CFRelease(rec); + rec = NULL; + } + } + } + + if (error) show_error(error); + return rec; +} + +void +odUpdateUser(ODRecordRef rec, CFDictionaryRef attrs_orig, CFDictionaryRef attrs) +{ + CFErrorRef error = NULL; + int updated = 0; + ENTRY* ep; + + for (ep = list; ep->prompt; ep++) { + + // Nothing to update + if (!rec || !attrs_orig || !attrs) break; + + // No need to update if entry is restricted + if (ep->restricted) continue; + + CFArrayRef values_orig = CFDictionaryGetValue(attrs_orig, *ep->attrName); + CFTypeRef value_orig = values_orig && CFArrayGetCount(values_orig) ? CFArrayGetValueAtIndex(values_orig, 0) : NULL; + CFTypeRef value = CFDictionaryGetValue(attrs, *ep->attrName); + + // No need to update if both values are the same + if (value == value_orig) continue; + + // No need to update if strings are equal + if (value && value_orig) { + if (CFGetTypeID(value_orig) == CFStringGetTypeID() && + CFStringCompare(value_orig, value, 0) == kCFCompareEqualTo) continue; + } + + // No need to update if empty string replaces NULL + if (!value_orig && value) { + if (CFStringGetLength(value) == 0) continue; + } + + // Needs update + if (value) { + // if new value is an empty string, send an empty dictionary which will delete the property. + CFIndex count = CFEqual(value, CFSTR("")) ? 0 : 1; + CFTypeRef vals[] = { value }; + CFArrayRef values = CFArrayCreate(NULL, vals, count, &kCFTypeArrayCallBacks); + if (values && ODRecordSetValue(rec, *ep->attrName, values, &error)) { + updated = 1; + } + if (values) CFRelease(values); + if (error) show_error(error); + } + } + + if (updated) { + updated = ODRecordSynchronize(rec, &error); + if (error) show_error(error); + } + if (!updated) { + fprintf(stderr, "%s: no changes made\n", progname); + } +} +#endif /* OPEN_DIRECTORY */ diff --git a/system_cmds/chpass.tproj/open_directory.h b/system_cmds/chpass.tproj/open_directory.h new file mode 100644 index 0000000..e6011b7 --- /dev/null +++ b/system_cmds/chpass.tproj/open_directory.h @@ -0,0 +1,13 @@ +#ifndef _OPEN_DIRECTORY_H_ +#define _OPEN_DIRECTORY_H_ + +#include +#include + +extern void setrestricted(CFDictionaryRef attrs); + +ODRecordRef odGetUser(CFStringRef location, CFStringRef authname, CFStringRef user, CFDictionaryRef* attrs); + +void odUpdateUser(ODRecordRef rec, CFDictionaryRef attrs_orig, CFDictionaryRef attrs); + +#endif /* _OPEN_DIRECTORY_H_ */ diff --git a/system_cmds/chpass.tproj/pw_copy.c b/system_cmds/chpass.tproj/pw_copy.c new file mode 100644 index 0000000..8aa74a6 --- /dev/null +++ b/system_cmds/chpass.tproj/pw_copy.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 1999-2016 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This module is used to copy the master password file, replacing a single + * record, by chpass(1) and passwd(1). + */ + +#include +#include +#include +#include + +#include "pw_util.h" +#include "pw_copy.h" + +extern char *tempname; + +void +pw_copy(int ffd, int tfd, struct passwd *pw) +{ + FILE *from, *to; + int done; + char *p, buf[8192]; + + if (!(from = fdopen(ffd, "r"))) + pw_error(_PATH_MASTERPASSWD, 1, 1); + if (!(to = fdopen(tfd, "w"))) + pw_error(tempname, 1, 1); + + for (done = 0; fgets(buf, sizeof(buf), from);) { + if (!strchr(buf, '\n')) { + warnx("%s: line too long", _PATH_MASTERPASSWD); + pw_error(NULL, 0, 1); + } +#if defined(__APPLE__) + if (done || (buf[0] == '#')) { +#else + if (done) { +#endif + (void)fprintf(to, "%s", buf); + if (ferror(to)) + goto err; + continue; + } + if (!(p = strchr(buf, ':'))) { + warnx("%s: corrupted entry", _PATH_MASTERPASSWD); + pw_error(NULL, 0, 1); + } + *p = '\0'; + if (strcmp(buf, pw->pw_name)) { + *p = ':'; + (void)fprintf(to, "%s", buf); + if (ferror(to)) + goto err; + continue; + } + (void)fprintf(to, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n", + pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid, + pw->pw_class, pw->pw_change, pw->pw_expire, pw->pw_gecos, + pw->pw_dir, pw->pw_shell); + done = 1; + if (ferror(to)) + goto err; + } + if (!done) + (void)fprintf(to, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n", + pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid, + pw->pw_class, pw->pw_change, pw->pw_expire, pw->pw_gecos, + pw->pw_dir, pw->pw_shell); + + if (ferror(to)) +err: pw_error(NULL, 1, 1); + (void)fclose(to); +} diff --git a/system_cmds/chpass.tproj/pw_copy.h b/system_cmds/chpass.tproj/pw_copy.h new file mode 100644 index 0000000..7c7af0a --- /dev/null +++ b/system_cmds/chpass.tproj/pw_copy.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1999-2016 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +void pw_copy __P((int, int, struct passwd *)); diff --git a/system_cmds/chpass.tproj/table.c b/system_cmds/chpass.tproj/table.c new file mode 100644 index 0000000..ba1523d --- /dev/null +++ b/system_cmds/chpass.tproj/table.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 1999-2016 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#if 0 +#ifndef lint +static const char sccsid[] = "@(#)table.c 8.3 (Berkeley) 4/2/94"; +#endif /* not lint */ +#endif +#include +__FBSDID("$FreeBSD: src/usr.bin/chpass/table.c,v 1.10 2003/05/03 19:44:45 obrien Exp $"); +#endif + +#include +#include +#include "chpass.h" + +char e1[] = ": "; +char e2[] = ":,"; + +#ifdef OPEN_DIRECTORY +#include "open_directory.h" + +ENTRY list[] = { + { "Login", display_string, p_login, 1, 5, e1, &kODAttributeTypeRecordName, }, + { "Password", display_string, p_passwd, 1, 8, e1, &kODAttributeTypePassword, }, + { "Uid [#]", display_string, p_uid, 1, 3, e1, &kODAttributeTypeUniqueID, }, + { "Gid [# or name]", display_string, p_gid, 1, 3, e1, &kODAttributeTypePrimaryGroupID, }, + { "Generated uid", display_string, p_uuid, 1, 13, NULL, &kODAttributeTypeGUID, }, +#if 0 + { "Change [month day year]", display_time, p_change, 1, 6, NULL, CFSTR(kDS1AttrChange), }, + { "Expire [month day year]", display_time, p_expire, 1, 6, NULL, kODAttributeTypeExpire, }, + { "Class", display_string, p_class, 0, 5, e1, CFSTR(""), "Class" }, +#endif + { "Home directory", display_string, p_hdir, 1, 14, e1, &kODAttributeTypeNFSHomeDirectory, }, + { "Shell", display_string, p_shell, 1, 5, e1, &kODAttributeTypeUserShell, }, + { "Full Name", display_string, p_gecos, 1, 9, e2, &kODAttributeTypeFullName, }, + { "Office Location", display_string, p_gecos, 1, 8, e2, &kODAttributeTypeBuilding, }, + { "Office Phone", display_string, p_gecos, 1, 12, e2, &kODAttributeTypePhoneNumber, }, + { "Home Phone", display_string, p_gecos, 1, 10, e2, &kODAttributeTypeHomePhoneNumber, }, + { NULL, NULL, NULL, 0, 0, NULL, NULL,}, +}; +#else /* OPEN_DIRECTORY */ +ENTRY list[] = { + { "login", p_login, 1, 5, e1, NULL }, + { "password", p_passwd, 1, 8, e1, NULL }, + { "uid", p_uid, 1, 3, e1, NULL }, + { "gid", p_gid, 1, 3, e1, NULL }, + { "class", p_class, 1, 5, e1, NULL }, + { "change", p_change, 1, 6, NULL, NULL }, + { "expire", p_expire, 1, 6, NULL, NULL }, +#ifdef RESTRICT_FULLNAME_CHANGE /* do not allow fullname changes */ + { "full name", p_gecos, 1, 9, e2, NULL }, +#else + { "full name", p_gecos, 0, 9, e2, NULL }, +#endif + { "office phone", p_gecos, 0, 12, e2, NULL }, + { "home phone", p_gecos, 0, 10, e2, NULL }, + { "office location", p_gecos, 0, 15, e2, NULL }, + { "other information", p_gecos, 0, 11, e1, NULL }, + { "home directory", p_hdir, 1, 14, e1, NULL }, + { "shell", p_shell, 0, 5, e1, NULL }, + { NULL, NULL, 0, 0, NULL, NULL }, +}; +#endif /* OPEN_DIRECTORY */ diff --git a/system_cmds/chpass.tproj/util.c b/system_cmds/chpass.tproj/util.c new file mode 100644 index 0000000..d3ab03f --- /dev/null +++ b/system_cmds/chpass.tproj/util.c @@ -0,0 +1,335 @@ +/* + * Copyright (c) 1999-2016 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 2002 Networks Associates Technology, Inc. + * All rights reserved. + * + * Portions of this software were developed for the FreeBSD Project by + * ThinkSec AS and NAI Labs, the Security Research Division of Network + * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 + * ("CBOSS"), as part of the DARPA CHATS research program. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#ifndef lint +#if 0 +static char sccsid[] = "@(#)util.c 8.4 (Berkeley) 4/2/94"; +#endif +#endif /* not lint */ +#include +__FBSDID("$FreeBSD: src/usr.bin/chpass/util.c,v 1.13 2004/01/18 21:46:39 charnier Exp $"); +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "chpass.h" + +#if OPEN_DIRECTORY +#include +#include +#include +#include "open_directory.h" + +char* tempname; +#endif /* OPEN_DIRECTORY */ + +static const char *months[] = + { "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", + "December", NULL }; + +char * +ttoa(time_t tval) +{ + struct tm *tp; + static char tbuf[50]; + + if (tval) { + tp = localtime(&tval); + (void)sprintf(tbuf, "%s %d, %d", months[tp->tm_mon], + tp->tm_mday, tp->tm_year + TM_YEAR_BASE); + } + else + *tbuf = '\0'; + return (tbuf); +} + +int +atot(char *p, time_t *store) +{ + static struct tm *lt; + char *t; + const char **mp; + time_t tval; + int day, month, year; + + if (!*p) { + *store = 0; + return (0); + } + if (!lt) { + unsetenv("TZ"); + (void)time(&tval); + lt = localtime(&tval); + } + if (!(t = strtok(p, " \t"))) + goto bad; + if (isdigit(*t)) { + month = atoi(t); + } else { + for (mp = months;; ++mp) { + if (!*mp) + goto bad; + if (!strncasecmp(*mp, t, 3)) { + month = (int)(mp - months + 1); + break; + } + } + } + if (!(t = strtok((char *)NULL, " \t,")) || !isdigit(*t)) + goto bad; + day = atoi(t); + if (!(t = strtok((char *)NULL, " \t,")) || !isdigit(*t)) + goto bad; + year = atoi(t); + if (day < 1 || day > 31 || month < 1 || month > 12) + goto bad; + /* Allow two digit years 1969-2068 */ + if (year < 69) + year += 2000; + else if (year < 100) + year += TM_YEAR_BASE; + if (year < EPOCH_YEAR) +bad: return (1); + lt->tm_year = year - TM_YEAR_BASE; + lt->tm_mon = month - 1; + lt->tm_mday = day; + lt->tm_hour = 0; + lt->tm_min = 0; + lt->tm_sec = 0; + lt->tm_isdst = -1; + if ((tval = mktime(lt)) < 0) + return (1); + *store = tval; + return (0); +} + +int +ok_shell(char *name) +{ +#ifdef __APPLE__ + char *sh; +#else + char *p, *sh; +#endif + + setusershell(); + while ((sh = getusershell())) { + if (!strcmp(name, sh)) { + endusershell(); + return (1); + } +#ifndef __APPLE__ + /* allow just shell name, but use "real" path */ + if ((p = strrchr(sh, '/')) && strcmp(name, p + 1) == 0) { + endusershell(); + return (1); + } +#endif + } + endusershell(); + return (0); +} + +char * +dup_shell(char *name) +{ + char *p, *sh, *ret; + + setusershell(); + while ((sh = getusershell())) { + if (!strcmp(name, sh)) { + endusershell(); + return (strdup(name)); + } + /* allow just shell name, but use "real" path */ + if ((p = strrchr(sh, '/')) && strcmp(name, p + 1) == 0) { + ret = strdup(sh); + endusershell(); + return (ret); + } + } + endusershell(); + return (NULL); +} + +#if OPEN_DIRECTORY +int +cfprintf(FILE* file, const char* format, ...) +{ + char* cstr; + int result = 0; + va_list args; + va_start(args, format); + CFStringRef formatStr = CFStringCreateWithCStringNoCopy(NULL, format, kCFStringEncodingUTF8, kCFAllocatorNull); + if (formatStr) { + CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, formatStr, args); + if (str) { + size_t size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8) + 1; + va_end(args); + cstr = malloc(size); + if (cstr && CFStringGetCString(str, cstr, size, kCFStringEncodingUTF8)) { + result = fprintf(file, "%s", cstr); + free(cstr); + } + CFRelease(str); + } + CFRelease(formatStr); + } + return result; +} + +/* + * Edit the temp file. Return -1 on error, >0 if the file was modified, 0 + * if it was not. + */ +int +editfile(const char* tfn) +{ + struct sigaction sa, sa_int, sa_quit; + sigset_t oldsigset, sigset; + struct stat st1, st2; + const char *p, *editor; + int pstat; + pid_t editpid; + + if ((editor = getenv("EDITOR")) == NULL) + editor = _PATH_VI; + if ((p = strrchr(editor, '/'))) + ++p; + else + p = editor; + + if (stat(tfn, &st1) == -1) + return (-1); + sa.sa_handler = SIG_IGN; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(SIGINT, &sa, &sa_int); + sigaction(SIGQUIT, &sa, &sa_quit); + sigemptyset(&sigset); + sigaddset(&sigset, SIGCHLD); + sigprocmask(SIG_BLOCK, &sigset, &oldsigset); + switch ((editpid = fork())) { + case -1: + return (-1); + case 0: + sigaction(SIGINT, &sa_int, NULL); + sigaction(SIGQUIT, &sa_quit, NULL); + sigprocmask(SIG_SETMASK, &oldsigset, NULL); + errno = 0; + if (!master_mode) { + (void)setgid(getgid()); + (void)setuid(getuid()); + } + execlp(editor, p, tfn, (char *)NULL); + _exit(errno); + default: + /* parent */ + break; + } + for (;;) { + if (waitpid(editpid, &pstat, WUNTRACED) == -1) { + if (errno == EINTR) + continue; + unlink(tfn); + editpid = -1; + break; + } else if (WIFSTOPPED(pstat)) { + raise(WSTOPSIG(pstat)); + } else if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0) { + editpid = -1; + break; + } else { + unlink(tfn); + editpid = -1; + break; + } + } + sigaction(SIGINT, &sa_int, NULL); + sigaction(SIGQUIT, &sa_quit, NULL); + sigprocmask(SIG_SETMASK, &oldsigset, NULL); + if (stat(tfn, &st2) == -1) + return (-1); + return (st1.st_mtime != st2.st_mtime); +} + +#if 0 +static void +pw_error(char *name, int err, int eval) +{ + if (err) + warn("%s", name); + exit(eval); +} +#endif + +#endif /* OPEN_DIRECTORY */ -- cgit v1.2.3-56-ge451