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#include <TargetConditionals.h> 24 25#define _PASSWD_FILE "/etc/master.passwd" 26 27#include <stdio.h> 28#include <errno.h> 29#include <pwd.h> 30#include <libc.h> 31#include <ctype.h> 32#include <string.h> 33#include "passwd.h" 34 35#ifdef __SLICK__ 36#define _PASSWORD_LEN 8 37#endif 38 39char* progname = "passwd"; 40 41static char *saltchars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"; 42 43void 44getpasswd(char *name, int isroot, int minlen, int mixcase, int nonalpha, 45 char *old_pw, char **new_pw, char **old_clear, char **new_clear) 46{ 47 int i, tries, pw_ok, upper, lower, alpha, notalpha; 48 size_t len; 49 int isNull; 50 char *p; 51 static char obuf[_PASSWORD_LEN+1]; 52 static char nbuf[_PASSWORD_LEN+1]; 53 char salt[9]; 54 55 printf("Changing password for %s.\n", name); 56 57 p = ""; 58 isNull = 0; 59 if (old_pw == NULL) isNull = 1; 60 if ((isNull == 0) && (old_pw[0] == '\0')) isNull = 1; 61 if ((isroot == 0) && (isNull == 0)) 62 { 63 p = getpass("Old password:"); 64 if (strcmp(crypt(p, old_pw), old_pw)) 65 { 66 errno = EACCES; 67 fprintf(stderr, "Sorry\n"); 68 exit(1); 69 } 70 } 71 //strcpy(obuf, p); 72 snprintf( obuf, sizeof(obuf), "%s", p ); 73 74 tries = 0; 75 nbuf[0] = '\0'; 76 for (;;) 77 { 78 p = getpass("New password:"); 79 if (!*p) 80 { 81 printf("Password unchanged.\n"); 82 exit(0); 83 } 84 85 tries++; 86 len = strlen(p); 87 upper = 0; 88 lower = 0; 89 alpha = 0; 90 notalpha = 0; 91 for (i = 0; i < len; i++) 92 { 93 if (isupper(p[i])) upper++; 94 if (islower(p[i])) lower++; 95 if (isalpha(p[i])) alpha++; 96 else notalpha++; 97 } 98 99 100 pw_ok = 1; 101 if (len < minlen) pw_ok = 0; 102 if ((mixcase == 1) && ((upper == 0) || (lower == 0))) pw_ok = 0; 103 if ((nonalpha == 1) && (notalpha == 0)) pw_ok = 0; 104 105 /* 106 * An insistent root may override security options. 107 */ 108 if ((isroot == 1) && (tries > 2)) pw_ok = 1; 109 110 /* 111 * A very insistent user may override security options. 112 */ 113 if (tries > 4) pw_ok = 1; 114 115 if (pw_ok == 0) 116 { 117 if (len < minlen) 118 printf("Password must be at least %d characters long.\n", minlen); 119 if ((mixcase == 1) && ((upper == 0) || (lower == 0))) 120 printf("Password must contain both upper and lower case characters.\n"); 121 if ((nonalpha == 1) && (notalpha == 0)) 122 printf("Password must contain non-alphabetic characters.\n"); 123 continue; 124 } 125 126 //strcpy(nbuf, p); 127 snprintf( nbuf, sizeof(nbuf), "%s", p ); 128 129 if (!strcmp(nbuf, getpass("Retype new password:"))) break; 130 131 printf("Mismatch; try again, EOF to quit.\n"); 132 } 133 134 /* 135 * Create a random salt 136 */ 137 srandom((int)time((time_t *)NULL)); 138 salt[0] = saltchars[random() % strlen(saltchars)]; 139 salt[1] = saltchars[random() % strlen(saltchars)]; 140 salt[2] = '\0'; 141 *new_pw = crypt(nbuf, salt); 142 143 *old_clear = obuf; 144 *new_clear = nbuf; 145 return; 146} 147 148static void 149usage(void) 150{ 151 fprintf(stderr, "usage: %s [-i infosystem] -l location]] [-u authname] [name]\n", progname); 152 fprintf(stderr, " infosystem:\n"); 153 fprintf(stderr, " file\n"); 154 fprintf(stderr, " NIS\n"); 155 fprintf(stderr, " OpenDirectory\n"); 156 fprintf(stderr, " PAM\n"); 157 fprintf(stderr, " location (for infosystem):\n"); 158 fprintf(stderr, " file location is path to file (default is %s)\n", _PASSWD_FILE); 159 fprintf(stderr, " NIS location is NIS domain name\n"); 160 fprintf(stderr, " OpenDirectory location is directory node name\n"); 161 fprintf(stderr, " PAM location is not used\n"); 162 exit(1); 163} 164 165int 166main(int argc, char *argv[]) 167{ 168 char* user = NULL; 169 char* locn = NULL; 170 char* auth = NULL; 171 int infosystem, ch; 172 int free_user = 0; 173 174#ifdef INFO_PAM 175 infosystem = INFO_PAM; 176#else 177#ifdef INFO_OPEN_DIRECTORY 178 infosystem = INFO_OPEN_DIRECTORY; 179#else 180 infosystem = INFO_FILE; 181#endif 182#endif 183 184#ifdef INFO_OPEN_DIRECTORY 185 /* PAM is the default infosystem, but we still want to use OpenDirectory directly when run by root */ 186 if (0 == getuid()) 187 infosystem = INFO_OPEN_DIRECTORY; 188#endif 189 190 while ((ch = getopt(argc, argv, "i:l:u:")) != -1) 191 switch(ch) { 192 case 'i': 193 if (!strcasecmp(optarg, "file")) { 194 infosystem = INFO_FILE; 195#ifdef INFO_NIS 196 } else if (!strcasecmp(optarg, "NIS")) { 197 infosystem = INFO_NIS; 198 } else if (!strcasecmp(optarg, "YP")) { 199 infosystem = INFO_NIS; 200#endif 201#ifdef INFO_OPEN_DIRECTORY 202 } else if (!strcasecmp(optarg, "opendirectory")) { 203 infosystem = INFO_OPEN_DIRECTORY; 204#endif 205#ifdef INFO_PAM 206 } else if (!strcasecmp(optarg, "PAM")) { 207 infosystem = INFO_PAM; 208#endif 209 } else { 210 fprintf(stderr, "%s: Unknown info system \'%s\'.\n", 211 progname, optarg); 212 usage(); 213 } 214 break; 215 case 'l': 216 locn = optarg; 217 break; 218 case 'u': 219 auth = optarg; 220 break; 221 case '?': 222 default: 223 usage(); 224 break; 225 } 226 argc -= optind; 227 argv += optind; 228 229 if (argc > 1) { 230 usage(); 231 } else if (argc == 1) { 232 user = argv[0]; 233 } 234 235#ifdef INFO_PAM 236 if (INFO_PAM == infosystem && NULL != locn) 237 usage(); 238#endif 239 240 if (user == NULL) 241 { 242 /* 243 * Verify that the login name exists. 244 * lukeh 24 Dec 1997 245 */ 246 247 /* getlogin() is the wrong thing to use here because it returns the wrong user after su */ 248 /* sns 5 Jan 2005 */ 249 250 struct passwd * userRec = getpwuid(getuid()); 251 if (userRec != NULL && userRec->pw_name != NULL) { 252 /* global static mem is volatile; must strdup */ 253 user = strdup(userRec->pw_name); 254 free_user = 1; 255 } 256 257 if (user == NULL) 258 { 259 fprintf(stderr, "you don't have a login name\n"); 260 exit(1); 261 } 262 } 263 264 switch (infosystem) 265 { 266 case INFO_FILE: 267 file_passwd(user, locn); 268 break; 269#ifdef INFO_NIS 270 case INFO_NIS: 271 nis_passwd(user, locn); 272 break; 273#endif 274#ifdef INFO_OPEN_DIRECTORY 275 case INFO_OPEN_DIRECTORY: 276 od_passwd(user, locn, auth); 277 break; 278#endif 279#ifdef INFO_PAM 280 case INFO_PAM: 281 pam_passwd(user); 282 break; 283#endif 284 } 285 286 if (free_user == 1) 287 free(user); 288 289 exit(0); 290} 291 292