1 /* 2 * Copyright 2006 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, &server_handle); 228 free(cpw_service); 229 if (code != 0) { 230 if (code == KADM5_BAD_PASSWORD) 231 com_err(whoami, 0, 232 string_text(KPW_STR_OLD_PASSWORD_INCORRECT)); 233 else 234 com_err(whoami, 0, 235 string_text(KPW_STR_CANT_OPEN_ADMIN_SERVER), 236 admin_realm, 237 error_message(code)); 238 krb5_free_principal(context, princ); 239 free(princ_str); 240 return ((code == KADM5_BAD_PASSWORD) ? 2 : 3); 241 } 242 243 /* 244 * we can only check the policy if the server speaks 245 * RPCSEC_GSS 246 */ 247 if (_kadm5_get_kpasswd_protocol(server_handle) == KRB5_CHGPWD_RPCSEC) { 248 /* Explain policy restrictions on new password if any. */ 249 /* 250 * Note: copy of this exists in login 251 * (kverify.c/get_verified_in_tkt). 252 */ 253 254 code = kadm5_get_principal(server_handle, princ, 255 &principal_entry, 256 KADM5_PRINCIPAL_NORMAL_MASK); 257 if (code != 0) { 258 com_err(whoami, 0, 259 string_text((code == KADM5_UNK_PRINC) 260 ? KPW_STR_PRIN_UNKNOWN : 261 KPW_STR_CANT_GET_POLICY_INFO), 262 princ_str); 263 krb5_free_principal(context, princ); 264 free(princ_str); 265 (void) kadm5_destroy(server_handle); 266 return ((code == KADM5_UNK_PRINC) ? 1 : 267 MISC_EXIT_STATUS); 268 } 269 if ((principal_entry.aux_attributes & KADM5_POLICY) != 0) { 270 code = kadm5_get_policy(server_handle, 271 principal_entry.policy, 272 &policy_entry); 273 if (code != 0) { 274 /* 275 * doesn't matter which error comes back, 276 * there's no nice recovery or need to 277 * differentiate to the user 278 */ 279 com_err(whoami, 0, 280 string_text(KPW_STR_CANT_GET_POLICY_INFO), 281 princ_str); 282 (void) kadm5_free_principal_ent(server_handle, 283 &principal_entry); 284 krb5_free_principal(context, princ); 285 free(princ_str); 286 free(princ_str); 287 (void) kadm5_destroy(server_handle); 288 return (MISC_EXIT_STATUS); 289 } 290 com_err(whoami, 0, 291 string_text(KPW_STR_POLICY_EXPLANATION), 292 princ_str, principal_entry.policy, 293 policy_entry.pw_min_length, 294 policy_entry.pw_min_classes); 295 if (code = kadm5_free_principal_ent(server_handle, 296 &principal_entry)) { 297 (void) kadm5_free_policy_ent(server_handle, 298 &policy_entry); 299 krb5_free_principal(context, princ); 300 free(princ_str); 301 com_err(whoami, code, 302 string_text(KPW_STR_WHILE_FREEING_PRINCIPAL)); 303 (void) kadm5_destroy(server_handle); 304 return (MISC_EXIT_STATUS); 305 } 306 if (code = kadm5_free_policy_ent(server_handle, 307 &policy_entry)) { 308 krb5_free_principal(context, princ); 309 free(princ_str); 310 com_err(whoami, code, 311 string_text(KPW_STR_WHILE_FREEING_POLICY)); 312 (void) kadm5_destroy(server_handle); 313 return (MISC_EXIT_STATUS); 314 } 315 } else { 316 /* 317 * kpasswd *COULD* output something here to 318 * encourage the choice of good passwords, 319 * in the absence of an enforced policy. 320 */ 321 if (code = kadm5_free_principal_ent(server_handle, 322 &principal_entry)) { 323 krb5_free_principal(context, princ); 324 free(princ_str); 325 com_err(whoami, code, 326 string_text(KPW_STR_WHILE_FREEING_PRINCIPAL)); 327 (void) kadm5_destroy(server_handle); 328 return (MISC_EXIT_STATUS); 329 } 330 } 331 } /* if protocol == KRB5_CHGPWD_RPCSEC */ 332 333 pwsize = sizeof(password); 334 code = read_new_password(server_handle, password, &pwsize, msg_ret, sizeof (msg_ret), princ); 335 memset(password, 0, sizeof(password)); 336 337 if (code) 338 com_err(whoami, 0, msg_ret); 339 340 krb5_free_principal(context, princ); 341 free(princ_str); 342 343 (void) kadm5_destroy(server_handle); 344 345 if (code == KRB5_LIBOS_CANTREADPWD) 346 return(5); 347 else if (code) 348 return(4); 349 else 350 return(0); 351 } 352