2 * Copyright (c) 1999-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 * Copyright (c) 1990, 1993, 1994
25 * The Regents of the University of California. All rights reserved.
26 * Copyright (c) 2002 Networks Associates Technology, Inc.
27 * All rights reserved.
29 * Portions of this software were developed for the FreeBSD Project by
30 * ThinkSec AS and NAI Labs, the Security Research Division of Network
31 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
32 * ("CBOSS"), as part of the DARPA CHATS research program.
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
37 * 1. Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
42 * 3. All advertising materials mentioning features or use of this software
43 * must display the following acknowledgement:
44 * This product includes software developed by the University of
45 * California, Berkeley and its contributors.
46 * 4. Neither the name of the University nor the names of its contributors
47 * may be used to endorse or promote products derived from this software
48 * without specific prior written permission.
50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66 static char sccsid
[] = "@(#)edit.c 8.3 (Berkeley) 4/2/94";
70 #include <sys/cdefs.h>
71 __FBSDID("$FreeBSD: src/usr.bin/chpass/edit.c,v 1.23 2003/04/09 18:18:42 des Exp $");
74 #include <sys/param.h>
87 #ifndef OPEN_DIRECTORY
95 static int display(const char *tfn
, CFDictionaryRef attrs
);
96 static CFDictionaryRef
verify(const char *tfn
, CFDictionaryRef attrs
);
98 static int display(const char *tfn
, struct passwd
*pw
);
99 static struct passwd
*verify(const char *tfn
, struct passwd
*pw
);
102 #ifdef OPEN_DIRECTORY
104 edit(const char *tfn
, CFDictionaryRef pw
)
107 edit(const char *tfn
, struct passwd
*pw
)
110 #ifdef OPEN_DIRECTORY
118 if (display(tfn
, pw
) == -1)
121 #ifdef OPEN_DIRECTORY
122 switch (editfile(tfn
)) {
124 switch (pw_edit(1)) {
129 #ifdef OPEN_DIRECTORY
137 if ((npw
= verify(tfn
, pw
)) != NULL
)
139 #ifndef OPEN_DIRECTORY
142 printf("re-edit the password file? ");
144 if ((line
= fgetln(stdin
, &len
)) == NULL
) {
148 if (len
> 0 && (*line
== 'N' || *line
== 'n'))
155 * print out the file for the user to edit; strange side-effect:
156 * set conditional flag if the user gets to edit the shell.
160 display(const char *tfn
, CFDictionaryRef attrs
)
163 display(const char *tfn
, struct passwd
*pw
)
167 #ifndef OPEN_DIRECTORY
168 char *bp
, *gecos
, *p
;
171 if ((fp
= fopen(tfn
, "w")) == NULL
) {
176 #ifdef OPEN_DIRECTORY
177 CFArrayRef values
= CFDictionaryGetValue(attrs
, kODAttributeTypeRecordName
);
178 CFStringRef username
= (values
&& CFArrayGetCount(values
)) > 0 ? CFArrayGetValueAtIndex(values
, 0) : NULL
;
181 "# Changing user information for %@.\n"
182 "# Use \"passwd\" to change the password.\n"
184 "# Open Directory%s%@\n"
188 DSPath
? DSPath
: CFSTR(""));
192 for (ep
= list
; ep
->prompt
; ep
++)
193 if (!ep
->restricted
) {
194 ep
->display(attrs
, *ep
->attrName
, ep
->prompt
, fp
);
198 (void)fprintf(fp
, "###################################\n");
199 (void)fprintf(fp
, "# No fields are available to change\n");
200 (void)fprintf(fp
, "###################################\n");
204 "#Changing user information for %s.\n", pw
->pw_name
);
206 (void)fprintf(fp
, "Login: %s\n", pw
->pw_name
);
207 (void)fprintf(fp
, "Password: %s\n", pw
->pw_passwd
);
208 (void)fprintf(fp
, "Uid [#]: %lu\n", (unsigned long)pw
->pw_uid
);
209 (void)fprintf(fp
, "Gid [# or name]: %lu\n",
210 (unsigned long)pw
->pw_gid
);
211 (void)fprintf(fp
, "Change [month day year]: %s\n",
212 ttoa(pw
->pw_change
));
213 (void)fprintf(fp
, "Expire [month day year]: %s\n",
214 ttoa(pw
->pw_expire
));
215 (void)fprintf(fp
, "Class: %s\n", pw
->pw_class
);
216 (void)fprintf(fp
, "Home directory: %s\n", pw
->pw_dir
);
217 (void)fprintf(fp
, "Shell: %s\n",
218 *pw
->pw_shell
? pw
->pw_shell
: _PATH_BSHELL
);
220 /* Only admin can change "restricted" shells. */
222 else if (ok_shell(pw
->pw_shell
))
224 * Make shell a restricted field. Ugly with a
225 * necklace, but there's not much else to do.
228 else if ((!list
[E_SHELL
].restricted
&& ok_shell(pw
->pw_shell
)) ||
231 * If change not restrict (table.c) and standard shell
232 * OR if root, then allow editing of shell.
235 (void)fprintf(fp
, "Shell: %s\n",
236 *pw
->pw_shell
? pw
->pw_shell
: _PATH_BSHELL
);
238 list
[E_SHELL
].restricted
= 1;
240 if ((bp
= gecos
= strdup(pw
->pw_gecos
)) == NULL
) {
246 p
= strsep(&bp
, ",");
247 p
= strdup(p
? p
: "");
248 list
[E_NAME
].save
= p
;
249 if (!list
[E_NAME
].restricted
|| master_mode
)
250 (void)fprintf(fp
, "Full Name: %s\n", p
);
252 p
= strsep(&bp
, ",");
253 p
= strdup(p
? p
: "");
254 list
[E_LOCATE
].save
= p
;
255 if (!list
[E_LOCATE
].restricted
|| master_mode
)
256 (void)fprintf(fp
, "Office Location: %s\n", p
);
258 p
= strsep(&bp
, ",");
259 p
= strdup(p
? p
: "");
260 list
[E_BPHONE
].save
= p
;
261 if (!list
[E_BPHONE
].restricted
|| master_mode
)
262 (void)fprintf(fp
, "Office Phone: %s\n", p
);
264 p
= strsep(&bp
, ",");
265 p
= strdup(p
? p
: "");
266 list
[E_HPHONE
].save
= p
;
267 if (!list
[E_HPHONE
].restricted
|| master_mode
)
268 (void)fprintf(fp
, "Home Phone: %s\n", p
);
270 bp
= strdup(bp
? bp
: "");
271 list
[E_OTHER
].save
= bp
;
272 if (!list
[E_OTHER
].restricted
|| master_mode
)
273 (void)fprintf(fp
, "Other information: %s\n", bp
);
276 #endif /* OPEN_DIRECTORY */
278 (void)fchown(fileno(fp
), getuid(), getgid());
283 #ifdef OPEN_DIRECTORY
284 static CFDictionaryRef
285 verify(const char* tfn
, CFDictionaryRef pw
)
287 static struct passwd
*
288 verify(const char *tfn
, struct passwd
*pw
)
291 #ifdef OPEN_DIRECTORY
292 CFMutableDictionaryRef npw
;
303 #ifdef OPEN_DIRECTORY
304 if ((npw
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
)) == NULL
)
307 if ((pw
= pw_dup(pw
)) == NULL
)
310 if ((fp
= fopen(tfn
, "r")) == NULL
||
311 fstat(fileno(fp
), &sb
) == -1) {
313 #ifndef OPEN_DIRECTORY
318 if (sb
.st_size
== 0) {
319 warnx("corrupted temporary file");
321 #ifndef OPEN_DIRECTORY
327 for (line
= 1; (buf
= fgetln(fp
, &len
)) != NULL
; ++line
) {
328 if (*buf
== '\0' || *buf
== '#')
330 while (len
> 0 && isspace(buf
[len
- 1]))
332 for (ep
= list
;; ++ep
) {
334 warnx("%s: unrecognized field on line %d",
340 if (strncasecmp(buf
, ep
->prompt
, ep
->len
) != 0)
342 if (ep
->restricted
&& !master_mode
) {
343 warnx("%s: you may not change the %s field",
347 for (p
= buf
; p
< buf
+ len
&& *p
!= ':'; ++p
)
350 warnx("%s: line %d corrupted", tfn
, line
);
353 while (++p
< buf
+ len
&& isspace(*p
))
356 asprintf(&val
, "%.*s", (int)(buf
+ len
- p
), p
);
359 if (ep
->except
&& strpbrk(val
, ep
->except
)) {
360 warnx("%s: invalid character in \"%s\" field '%s'",
361 tfn
, ep
->prompt
, val
);
364 #ifdef OPEN_DIRECTORY
365 if ((ep
->func
)(val
, NULL
, NULL
))
368 CFStringRef str
= CFStringCreateWithCString(NULL
, val
, kCFStringEncodingUTF8
);
370 CFDictionarySetValue(npw
, *ep
->attrName
, str
);
375 if ((ep
->func
)(val
, pw
, ep
))
384 #ifndef OPEN_DIRECTORY
385 /* Build the gecos field. */
386 len
= asprintf(&p
, "%s,%s,%s,%s,%s", list
[E_NAME
].save
,
387 list
[E_LOCATE
].save
, list
[E_BPHONE
].save
,
388 list
[E_HPHONE
].save
, list
[E_OTHER
].save
);
394 while (len
> 0 && p
[len
- 1] == ',')
404 npw
= pw_scan(buf
, PWSCAN_WARN
|PWSCAN_MASTER
);
405 #endif /* !OPEN_DIRECTORY */
409 #ifndef OPEN_DIRECTORY