1 /* 2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 10 * 11 * Openvision retains the copyright to derivative works of 12 * this source code. Do *NOT* create a derivative of this 13 * source code before consulting with your legal department. 14 * Do *NOT* integrate *ANY* of this source code into another 15 * product before consulting with your legal department. 16 * 17 * For further information, read the top-level Openvision 18 * copyright which is contained in the top-level MIT Kerberos 19 * copyright. 20 * 21 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING 22 * 23 */ 24 25 26 /* 27 * Copyright 1993-1994 OpenVision Technologies, Inc., All Rights Reserved. 28 * 29 * $Header: /cvs/krbdev/krb5/src/kadmin/passwd/kpasswd.c,v 1.25 2001/02/26 18:22:08 epeisach Exp $ 30 * 31 * 32 */ 33 34 static char rcsid[] = "$Id: kpasswd.c,v 1.25 2001/02/26 18:22:08 epeisach Exp $"; 35 36 #include <kadm5/admin.h> 37 #include <krb5.h> 38 39 #include "kpasswd_strings.h" 40 #define string_text error_message 41 42 #include "kpasswd.h" 43 44 #include <stdio.h> 45 #include <pwd.h> 46 #include <string.h> 47 #include <libintl.h> 48 49 extern char *whoami; 50 51 extern void display_intro_message(); 52 extern long read_old_password(); 53 extern long read_new_password(); 54 55 #define MISC_EXIT_STATUS 6 56 57 /* 58 * Function: kpasswd 59 * 60 * Purpose: Initialize and call lower level routines to change a password 61 * 62 * Arguments: 63 * 64 * context (r) krb5_context to use 65 * argc/argv (r) principal name to use, optional 66 * read_old_password (f) function to read old password 67 * read_new_password (f) function to read new and change password 68 * display_intro_message (f) function to display intro message 69 * whoami (extern) argv[0] 70 * 71 * Returns: 72 * exit status of 0 for success 73 * 1 principal unknown 74 * 2 old password wrong 75 * 3 cannot initialize admin server session 76 * 4 new passwd mismatch or error trying to change pw 77 * 5 password not typed 78 * 6 misc error 79 * 7 incorrect usage 80 * 81 * Requires: 82 * Passwords cannot be more than 255 characters long. 83 * 84 * Effects: 85 * 86 * If argc is 2, the password for the principal specified in argv[1] 87 * is changed; otherwise, the principal of the default credential 88 * cache or username is used. display_intro_message is called with 89 * the arguments KPW_STR_CHANGING_PW_FOR and the principal name. 90 * read_old_password is then called to prompt for the old password. 91 * The admin system is then initialized, the principal's policy 92 * retrieved and explained, if appropriate, and finally 93 * read_new_password is called to read the new password and change the 94 * principal's password (presumably ovsec_kadm_chpass_principal). 95 * admin system is de-initialized before the function returns. 96 * 97 * Modifies: 98 * 99 * Changes the principal's password. 100 * 101 */ 102 int 103 kpasswd(context, argc, argv) 104 krb5_context context; 105 int argc; 106 char *argv[]; 107 { 108 kadm5_ret_t code; 109 krb5_ccache ccache = NULL; 110 krb5_principal princ = 0; 111 char *princ_str; 112 struct passwd *pw = 0; 113 unsigned int pwsize; 114 char password[255]; /* I don't really like 255 but that's what kinit uses */ 115 char msg_ret[1024], admin_realm[1024]; 116 kadm5_principal_ent_rec principal_entry; 117 kadm5_policy_ent_rec policy_entry; 118 void *server_handle; 119 kadm5_config_params params; 120 char *cpw_service; 121 122 memset((char *)¶ms, 0, sizeof (params)); 123 memset(&principal_entry, 0, sizeof (principal_entry)); 124 memset(&policy_entry, 0, sizeof (policy_entry)); 125 126 if (argc > 2) { 127 com_err(whoami, KPW_STR_USAGE, 0); 128 return(7); 129 /*NOTREACHED*/ 130 } 131 132 /************************************ 133 * Get principal name to change * 134 ************************************/ 135 136 /* Look on the command line first, followed by the default credential 137 cache, followed by defaulting to the Unix user name */ 138 139 if (argc == 2) 140 princ_str = strdup(argv[1]); 141 else { 142 code = krb5_cc_default(context, &ccache); 143 /* If we succeed, find who is in the credential cache */ 144 if (code == 0) { 145 /* Get default principal from cache if one exists */ 146 code = krb5_cc_get_principal(context, ccache, &princ); 147 /* if we got a principal, unparse it, otherwise get out of the if 148 with an error code */ 149 (void) krb5_cc_close(context, ccache); 150 if (code == 0) { 151 code = krb5_unparse_name(context, princ, &princ_str); 152 if (code != 0) { 153 com_err(whoami, code, string_text(KPW_STR_UNPARSE_NAME)); 154 return(MISC_EXIT_STATUS); 155 } 156 } 157 } 158 159 /* this is a crock.. we want to compare against */ 160 /* "KRB5_CC_DOESNOTEXIST" but there is no such error code, and */ 161 /* both the file and stdio types return FCC_NOFILE. If there is */ 162 /* ever another ccache type (or if the error codes are ever */ 163 /* fixed), this code will have to be updated. */ 164 if (code && code != KRB5_FCC_NOFILE) { 165 com_err(whoami, code, string_text(KPW_STR_WHILE_LOOKING_AT_CC)); 166 return(MISC_EXIT_STATUS); 167 } 168 169 /* if either krb5_cc failed check the passwd file */ 170 if (code != 0) { 171 pw = getpwuid( getuid()); 172 if (pw == NULL) { 173 com_err(whoami, 0, string_text(KPW_STR_NOT_IN_PASSWD_FILE)); 174 return(MISC_EXIT_STATUS); 175 } 176 princ_str = strdup(pw->pw_name); 177 } 178 } 179 180 display_intro_message(string_text(KPW_STR_CHANGING_PW_FOR), princ_str); 181 182 /* Need to get a krb5_principal, unless we started from with one from 183 the credential cache */ 184 185 if (! princ) { 186 code = krb5_parse_name (context, princ_str, &princ); 187 if (code != 0) { 188 com_err(whoami, code, string_text(KPW_STR_PARSE_NAME), princ_str); 189 free(princ_str); 190 return(MISC_EXIT_STATUS); 191 } 192 } 193 194 pwsize = sizeof(password); 195 code = read_old_password(context, password, &pwsize); 196 197 if (code != 0) { 198 memset(password, 0, sizeof(password)); 199 com_err(whoami, code, string_text(KPW_STR_WHILE_READING_PASSWORD)); 200 krb5_free_principal(context, princ); 201 free(princ_str); 202 return(MISC_EXIT_STATUS); 203 } 204 if (pwsize == 0) { 205 memset(password, 0, sizeof(password)); 206 com_err(whoami, 0, string_text(KPW_STR_NO_PASSWORD_READ)); 207 krb5_free_principal(context, princ); 208 free(princ_str); 209 return(5); 210 } 211 212 snprintf(admin_realm, sizeof (admin_realm), 213 krb5_princ_realm(context, princ)->data); 214 params.mask |= KADM5_CONFIG_REALM; 215 params.realm = admin_realm; 216 217 218 if (kadm5_get_cpw_host_srv_name(context, admin_realm, &cpw_service)) { 219 fprintf(stderr, gettext("%s: unable to get host based " 220 "service name for realm %s\n"), 221 whoami, admin_realm); 222 exit(1); 223 } 224 225 code = kadm5_init_with_password(princ_str, password, cpw_service, 226 ¶ms, KADM5_STRUCT_VERSION, 227 KADM5_API_VERSION_2, NULL, 228 &server_handle); 229 free(cpw_service); 230 if (code != 0) { 231 if (code == KADM5_BAD_PASSWORD) 232 com_err(whoami, 0, 233 string_text(KPW_STR_OLD_PASSWORD_INCORRECT)); 234 else 235 com_err(whoami, 0, 236 string_text(KPW_STR_CANT_OPEN_ADMIN_SERVER), 237 admin_realm, 238 error_message(code)); 239 krb5_free_principal(context, princ); 240 free(princ_str); 241 return ((code == KADM5_BAD_PASSWORD) ? 2 : 3); 242 } 243 244 /* 245 * we can only check the policy if the server speaks 246 * RPCSEC_GSS 247 */ 248 if (_kadm5_get_kpasswd_protocol(server_handle) == KRB5_CHGPWD_RPCSEC) { 249 /* Explain policy restrictions on new password if any. */ 250 /* 251 * Note: copy of this exists in login 252 * (kverify.c/get_verified_in_tkt). 253 */ 254 255 code = kadm5_get_principal(server_handle, princ, 256 &principal_entry, 257 KADM5_PRINCIPAL_NORMAL_MASK); 258 if (code != 0) { 259 com_err(whoami, 0, 260 string_text((code == KADM5_UNK_PRINC) 261 ? KPW_STR_PRIN_UNKNOWN : 262 KPW_STR_CANT_GET_POLICY_INFO), 263 princ_str); 264 krb5_free_principal(context, princ); 265 free(princ_str); 266 (void) kadm5_destroy(server_handle); 267 return ((code == KADM5_UNK_PRINC) ? 1 : 268 MISC_EXIT_STATUS); 269 } 270 if ((principal_entry.aux_attributes & KADM5_POLICY) != 0) { 271 code = kadm5_get_policy(server_handle, 272 principal_entry.policy, 273 &policy_entry); 274 if (code != 0) { 275 /* 276 * doesn't matter which error comes back, 277 * there's no nice recovery or need to 278 * differentiate to the user 279 */ 280 com_err(whoami, 0, 281 string_text(KPW_STR_CANT_GET_POLICY_INFO), 282 princ_str); 283 (void) kadm5_free_principal_ent(server_handle, 284 &principal_entry); 285 krb5_free_principal(context, princ); 286 free(princ_str); 287 free(princ_str); 288 (void) kadm5_destroy(server_handle); 289 return (MISC_EXIT_STATUS); 290 } 291 com_err(whoami, 0, 292 string_text(KPW_STR_POLICY_EXPLANATION), 293 princ_str, principal_entry.policy, 294 policy_entry.pw_min_length, 295 policy_entry.pw_min_classes); 296 if (code = kadm5_free_principal_ent(server_handle, 297 &principal_entry)) { 298 (void) kadm5_free_policy_ent(server_handle, 299 &policy_entry); 300 krb5_free_principal(context, princ); 301 free(princ_str); 302 com_err(whoami, code, 303 string_text(KPW_STR_WHILE_FREEING_PRINCIPAL)); 304 (void) kadm5_destroy(server_handle); 305 return (MISC_EXIT_STATUS); 306 } 307 if (code = kadm5_free_policy_ent(server_handle, 308 &policy_entry)) { 309 krb5_free_principal(context, princ); 310 free(princ_str); 311 com_err(whoami, code, 312 string_text(KPW_STR_WHILE_FREEING_POLICY)); 313 (void) kadm5_destroy(server_handle); 314 return (MISC_EXIT_STATUS); 315 } 316 } else { 317 /* 318 * kpasswd *COULD* output something here to 319 * encourage the choice of good passwords, 320 * in the absence of an enforced policy. 321 */ 322 if (code = kadm5_free_principal_ent(server_handle, 323 &principal_entry)) { 324 krb5_free_principal(context, princ); 325 free(princ_str); 326 com_err(whoami, code, 327 string_text(KPW_STR_WHILE_FREEING_PRINCIPAL)); 328 (void) kadm5_destroy(server_handle); 329 return (MISC_EXIT_STATUS); 330 } 331 } 332 } /* if protocol == KRB5_CHGPWD_RPCSEC */ 333 334 pwsize = sizeof(password); 335 code = read_new_password(server_handle, password, &pwsize, msg_ret, sizeof (msg_ret), princ); 336 memset(password, 0, sizeof(password)); 337 338 if (code) 339 com_err(whoami, 0, msg_ret); 340 341 krb5_free_principal(context, princ); 342 free(princ_str); 343 344 (void) kadm5_destroy(server_handle); 345 346 if (code == KRB5_LIBOS_CANTREADPWD) 347 return(5); 348 else if (code) 349 return(4); 350 else 351 return(0); 352 } 353