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