1/*
2 * Copyright (c) 1999-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*-
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.
28 *
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.
33 *
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
36 * are met:
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.
49 *
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
60 * SUCH DAMAGE.
61 */
62
63#if 0
64#ifndef lint
65#if 0
66static char sccsid[] = "@(#)util.c	8.4 (Berkeley) 4/2/94";
67#endif
68#endif /* not lint */
69#include <sys/cdefs.h>
70__FBSDID("$FreeBSD: src/usr.bin/chpass/util.c,v 1.13 2004/01/18 21:46:39 charnier Exp $");
71#endif
72
73#include <sys/types.h>
74
75#include <ctype.h>
76#include <stdio.h>
77#include <stdlib.h>
78#include <string.h>
79#include <time.h>
80#include <tzfile.h>
81#include <unistd.h>
82
83#include "chpass.h"
84
85#if OPEN_DIRECTORY
86#include <err.h>
87#include <paths.h>
88#include <sys/stat.h>
89#include "open_directory.h"
90
91char* tempname;
92#endif /* OPEN_DIRECTORY */
93
94static const char *months[] =
95	{ "January", "February", "March", "April", "May", "June",
96	  "July", "August", "September", "October", "November",
97	  "December", NULL };
98
99char *
100ttoa(time_t tval)
101{
102	struct tm *tp;
103	static char tbuf[50];
104
105	if (tval) {
106		tp = localtime(&tval);
107		(void)sprintf(tbuf, "%s %d, %d", months[tp->tm_mon],
108		    tp->tm_mday, tp->tm_year + TM_YEAR_BASE);
109	}
110	else
111		*tbuf = '\0';
112	return (tbuf);
113}
114
115int
116atot(char *p, time_t *store)
117{
118	static struct tm *lt;
119	char *t;
120	const char **mp;
121	time_t tval;
122	int day, month, year;
123
124	if (!*p) {
125		*store = 0;
126		return (0);
127	}
128	if (!lt) {
129		unsetenv("TZ");
130		(void)time(&tval);
131		lt = localtime(&tval);
132	}
133	if (!(t = strtok(p, " \t")))
134		goto bad;
135	if (isdigit(*t)) {
136		month = atoi(t);
137	} else {
138		for (mp = months;; ++mp) {
139			if (!*mp)
140				goto bad;
141			if (!strncasecmp(*mp, t, 3)) {
142				month = mp - months + 1;
143				break;
144			}
145		}
146	}
147	if (!(t = strtok((char *)NULL, " \t,")) || !isdigit(*t))
148		goto bad;
149	day = atoi(t);
150	if (!(t = strtok((char *)NULL, " \t,")) || !isdigit(*t))
151		goto bad;
152	year = atoi(t);
153	if (day < 1 || day > 31 || month < 1 || month > 12)
154		goto bad;
155	/* Allow two digit years 1969-2068 */
156	if (year < 69)
157		year += 2000;
158	else if (year < 100)
159		year += TM_YEAR_BASE;
160	if (year < EPOCH_YEAR)
161bad:		return (1);
162	lt->tm_year = year - TM_YEAR_BASE;
163	lt->tm_mon = month - 1;
164	lt->tm_mday = day;
165	lt->tm_hour = 0;
166	lt->tm_min = 0;
167	lt->tm_sec = 0;
168	lt->tm_isdst = -1;
169	if ((tval = mktime(lt)) < 0)
170		return (1);
171	*store = tval;
172	return (0);
173}
174
175int
176ok_shell(char *name)
177{
178#ifdef __APPLE__
179	char *sh;
180#else
181	char *p, *sh;
182#endif
183
184	setusershell();
185	while ((sh = getusershell())) {
186		if (!strcmp(name, sh)) {
187			endusershell();
188			return (1);
189		}
190#ifndef __APPLE__
191		/* allow just shell name, but use "real" path */
192		if ((p = strrchr(sh, '/')) && strcmp(name, p + 1) == 0) {
193			endusershell();
194			return (1);
195		}
196#endif
197	}
198	endusershell();
199	return (0);
200}
201
202char *
203dup_shell(char *name)
204{
205	char *p, *sh, *ret;
206
207	setusershell();
208	while ((sh = getusershell())) {
209		if (!strcmp(name, sh)) {
210			endusershell();
211			return (strdup(name));
212		}
213		/* allow just shell name, but use "real" path */
214		if ((p = strrchr(sh, '/')) && strcmp(name, p + 1) == 0) {
215			ret = strdup(sh);
216			endusershell();
217			return (ret);
218		}
219	}
220	endusershell();
221	return (NULL);
222}
223
224#if OPEN_DIRECTORY
225int
226cfprintf(FILE* file, const char* format, ...) {
227		char* cstr;
228		int result = 0;
229        va_list args;
230        va_start(args, format);
231        CFStringRef formatStr = CFStringCreateWithCStringNoCopy(NULL, format, kCFStringEncodingUTF8, kCFAllocatorNull);
232		if (formatStr) {
233			CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, formatStr, args);
234			if (str) {
235				size_t size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8) + 1;
236				va_end(args);
237				cstr = malloc(size);
238				if (cstr && CFStringGetCString(str, cstr, size, kCFStringEncodingUTF8)) {
239					result = fprintf(file, "%s", cstr);
240					free(cstr);
241				}
242				CFRelease(str);
243			}
244			CFRelease(formatStr);
245		}
246		return result;
247}
248
249/*
250 * Edit the temp file.  Return -1 on error, >0 if the file was modified, 0
251 * if it was not.
252 */
253int
254editfile(const char* tfn)
255{
256	struct sigaction sa, sa_int, sa_quit;
257	sigset_t oldsigset, sigset;
258	struct stat st1, st2;
259	const char *p, *editor;
260	int pstat;
261	pid_t editpid;
262
263	if ((editor = getenv("EDITOR")) == NULL)
264		editor = _PATH_VI;
265	if (p = strrchr(editor, '/'))
266		++p;
267	else
268		p = editor;
269
270	if (stat(tfn, &st1) == -1)
271		return (-1);
272	sa.sa_handler = SIG_IGN;
273	sigemptyset(&sa.sa_mask);
274	sa.sa_flags = 0;
275	sigaction(SIGINT, &sa, &sa_int);
276	sigaction(SIGQUIT, &sa, &sa_quit);
277	sigemptyset(&sigset);
278	sigaddset(&sigset, SIGCHLD);
279	sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
280	switch ((editpid = fork())) {
281	case -1:
282		return (-1);
283	case 0:
284		sigaction(SIGINT, &sa_int, NULL);
285		sigaction(SIGQUIT, &sa_quit, NULL);
286		sigprocmask(SIG_SETMASK, &oldsigset, NULL);
287		errno = 0;
288		if (!master_mode) {
289			(void)setgid(getgid());
290			(void)setuid(getuid());
291		}
292		execlp(editor, p, tfn, (char *)NULL);
293		_exit(errno);
294	default:
295		/* parent */
296		break;
297	}
298	for (;;) {
299		if (waitpid(editpid, &pstat, WUNTRACED) == -1) {
300			if (errno == EINTR)
301				continue;
302			unlink(tfn);
303			editpid = -1;
304			break;
305		} else if (WIFSTOPPED(pstat)) {
306			raise(WSTOPSIG(pstat));
307		} else if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0) {
308			editpid = -1;
309			break;
310		} else {
311			unlink(tfn);
312			editpid = -1;
313			break;
314		}
315	}
316	sigaction(SIGINT, &sa_int, NULL);
317	sigaction(SIGQUIT, &sa_quit, NULL);
318	sigprocmask(SIG_SETMASK, &oldsigset, NULL);
319	if (stat(tfn, &st2) == -1)
320		return (-1);
321	return (st1.st_mtime != st2.st_mtime);
322}
323
324void
325pw_error(char *name, int err, int eval)
326{
327	if (err)
328		warn("%s", name);
329	exit(eval);
330}
331
332#endif /* OPEN_DIRECTORY */
333