1 /* 2 * Copyright 1998-2002 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.24 1997/02/20\ 30 * 06:12:57 probe Exp $ 31 * 32 * 33 */ 34 35 static char rcsid[] = "$Id: kpasswd.c,v 1.24 1997/02/20 " 36 "06:12:57 probe Exp $"; 37 38 #include <kadm5/admin.h> 39 #include <krb5.h> 40 41 #include "kpasswd_strings.h" 42 #define string_text error_message 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 int pwsize; 114 char password[255]; /* I don't really like 255 */ 115 /* but that's what kinit uses */ 116 char msg_ret[1024], admin_realm[1024]; 117 kadm5_principal_ent_rec principal_entry; 118 kadm5_policy_ent_rec policy_entry; 119 void *server_handle; 120 kadm5_config_params params; 121 char *cpw_service; 122 123 memset((char *)¶ms, 0, sizeof (params)); 124 memset(&principal_entry, 0, sizeof (principal_entry)); 125 memset(&policy_entry, 0, sizeof (policy_entry)); 126 127 if (argc > 2) { 128 com_err(whoami, KPW_STR_USAGE, 0); 129 return (7); 130 /* NOTREACHED */ 131 } 132 /* 133 * Get principal name to change 134 */ 135 136 /* 137 * Look on the command line first, followed by the default 138 * credential cache, followed by defaulting to the Unix user name 139 */ 140 141 if (argc == 2) 142 princ_str = strdup(argv[1]); 143 else { 144 code = krb5_cc_default(context, &ccache); 145 /* If we succeed, find who is in the credential cache */ 146 if (code == 0) { 147 /* Get default principal from cache if one exists */ 148 code = krb5_cc_get_principal(context, ccache, &princ); 149 /* 150 * if we got a principal, unparse it, otherwise get 151 * out of the if with an error code 152 */ 153 (void) krb5_cc_close(context, ccache); 154 if (code == 0) { 155 code = krb5_unparse_name(context, 156 princ, &princ_str); 157 if (code != 0) { 158 com_err(whoami, code, 159 string_text( 160 KPW_STR_UNPARSE_NAME)); 161 return (MISC_EXIT_STATUS); 162 } 163 } 164 } 165 /* this is a crock.. we want to compare against */ 166 /* 167 * "KRB5_CC_DOESNOTEXIST" but there is no such error code, 168 * and 169 */ 170 /* 171 * both the file and stdio types return FCC_NOFILE. If 172 * there is 173 */ 174 /* ever another ccache type (or if the error codes are ever */ 175 /* fixed), this code will have to be updated. */ 176 if (code && code != KRB5_FCC_NOFILE) { 177 com_err(whoami, code, 178 string_text(KPW_STR_WHILE_LOOKING_AT_CC)); 179 return (MISC_EXIT_STATUS); 180 } 181 /* if either krb5_cc failed check the passwd file */ 182 if (code != 0) { 183 pw = getpwuid(getuid()); 184 if (pw == NULL) { 185 com_err(whoami, 0, 186 string_text(KPW_STR_NOT_IN_PASSWD_FILE)); 187 return (MISC_EXIT_STATUS); 188 } 189 princ_str = strdup(pw->pw_name); 190 } 191 } 192 193 display_intro_message(string_text(KPW_STR_CHANGING_PW_FOR), princ_str); 194 195 /* 196 * Need to get a krb5_principal, unless we started from with one 197 * from the credential cache 198 */ 199 200 if (!princ) { 201 code = krb5_parse_name(context, princ_str, &princ); 202 if (code != 0) { 203 com_err(whoami, code, 204 string_text(KPW_STR_PARSE_NAME), princ_str); 205 free(princ_str); 206 return (MISC_EXIT_STATUS); 207 } 208 } 209 pwsize = sizeof (password); 210 code = read_old_password(context, password, &pwsize); 211 212 if (code != 0) { 213 memset(password, 0, sizeof (password)); 214 com_err(whoami, code, 215 string_text(KPW_STR_WHILE_READING_PASSWORD)); 216 krb5_free_principal(context, princ); 217 free(princ_str); 218 return (MISC_EXIT_STATUS); 219 } 220 if (pwsize == 0) { 221 memset(password, 0, sizeof (password)); 222 com_err(whoami, 0, string_text(KPW_STR_NO_PASSWORD_READ)); 223 krb5_free_principal(context, princ); 224 free(princ_str); 225 return (5); 226 } 227 228 snprintf(admin_realm, sizeof (admin_realm), 229 krb5_princ_realm(context, princ)->data); 230 params.mask |= KADM5_CONFIG_REALM; 231 params.realm = admin_realm; 232 233 234 if (kadm5_get_cpw_host_srv_name(context, admin_realm, &cpw_service)) { 235 fprintf(stderr, gettext("%s: unable to get host based " 236 "service name for realm %s\n"), 237 whoami, admin_realm); 238 exit(1); 239 } 240 241 code = kadm5_init_with_password(princ_str, password, cpw_service, 242 ¶ms, KADM5_STRUCT_VERSION, 243 KADM5_API_VERSION_2, &server_handle); 244 free(cpw_service); 245 if (code != 0) { 246 if (code == KADM5_BAD_PASSWORD) 247 com_err(whoami, 0, 248 string_text(KPW_STR_OLD_PASSWORD_INCORRECT)); 249 else 250 com_err(whoami, 0, 251 string_text(KPW_STR_CANT_OPEN_ADMIN_SERVER), 252 admin_realm, 253 error_message(code)); 254 krb5_free_principal(context, princ); 255 free(princ_str); 256 return ((code == KADM5_BAD_PASSWORD) ? 2 : 3); 257 } 258 259 /* 260 * we can only check the policy if the server speaks 261 * RPCSEC_GSS 262 */ 263 if (_kadm5_get_kpasswd_protocol(server_handle) == KRB5_CHGPWD_RPCSEC) { 264 /* Explain policy restrictions on new password if any. */ 265 /* 266 * Note: copy of this exists in login 267 * (kverify.c/get_verified_in_tkt). 268 */ 269 270 code = kadm5_get_principal(server_handle, princ, 271 &principal_entry, 272 KADM5_PRINCIPAL_NORMAL_MASK); 273 if (code != 0) { 274 com_err(whoami, 0, 275 string_text((code == KADM5_UNK_PRINC) 276 ? KPW_STR_PRIN_UNKNOWN : 277 KPW_STR_CANT_GET_POLICY_INFO), 278 princ_str); 279 krb5_free_principal(context, princ); 280 free(princ_str); 281 (void) kadm5_destroy(server_handle); 282 return ((code == KADM5_UNK_PRINC) ? 1 : 283 MISC_EXIT_STATUS); 284 } 285 if ((principal_entry.aux_attributes & KADM5_POLICY) != 0) { 286 code = kadm5_get_policy(server_handle, 287 principal_entry.policy, 288 &policy_entry); 289 if (code != 0) { 290 /* 291 * doesn't matter which error comes back, 292 * there's no nice recovery or need to 293 * differentiate to the user 294 */ 295 com_err(whoami, 0, 296 string_text(KPW_STR_CANT_GET_POLICY_INFO), 297 princ_str); 298 (void) kadm5_free_principal_ent(server_handle, 299 &principal_entry); 300 krb5_free_principal(context, princ); 301 free(princ_str); 302 free(princ_str); 303 (void) kadm5_destroy(server_handle); 304 return (MISC_EXIT_STATUS); 305 } 306 com_err(whoami, 0, 307 string_text(KPW_STR_POLICY_EXPLANATION), 308 princ_str, principal_entry.policy, 309 policy_entry.pw_min_length, 310 policy_entry.pw_min_classes); 311 if (code = kadm5_free_principal_ent(server_handle, 312 &principal_entry)) { 313 (void) kadm5_free_policy_ent(server_handle, 314 &policy_entry); 315 krb5_free_principal(context, princ); 316 free(princ_str); 317 com_err(whoami, code, 318 string_text(KPW_STR_WHILE_FREEING_PRINCIPAL)); 319 (void) kadm5_destroy(server_handle); 320 return (MISC_EXIT_STATUS); 321 } 322 if (code = kadm5_free_policy_ent(server_handle, 323 &policy_entry)) { 324 krb5_free_principal(context, princ); 325 free(princ_str); 326 com_err(whoami, code, 327 string_text(KPW_STR_WHILE_FREEING_POLICY)); 328 (void) kadm5_destroy(server_handle); 329 return (MISC_EXIT_STATUS); 330 } 331 } else { 332 /* 333 * kpasswd *COULD* output something here to 334 * encourage the choice of good passwords, 335 * in the absence of an enforced policy. 336 */ 337 if (code = kadm5_free_principal_ent(server_handle, 338 &principal_entry)) { 339 krb5_free_principal(context, princ); 340 free(princ_str); 341 com_err(whoami, code, 342 string_text(KPW_STR_WHILE_FREEING_PRINCIPAL)); 343 (void) kadm5_destroy(server_handle); 344 return (MISC_EXIT_STATUS); 345 } 346 } 347 } /* if protocol == KRB5_CHGPWD_RPCSEC */ 348 349 pwsize = sizeof (password); 350 code = read_new_password(server_handle, password, 351 &pwsize, msg_ret, sizeof (msg_ret), princ); 352 memset(password, 0, sizeof (password)); 353 354 if (code) 355 com_err(whoami, 0, msg_ret); 356 357 krb5_free_principal(context, princ); 358 free(princ_str); 359 360 (void) kadm5_destroy(server_handle); 361 362 if (code == KRB5_LIBOS_CANTREADPWD) 363 return (5); 364 else if (code) 365 return (4); 366 else 367 return (0); 368 } 369