2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
8 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
10 * Openvision retains the copyright to derivative works of
11 * this source code. Do *NOT* create a derivative of this
12 * source code before consulting with your legal department.
13 * Do *NOT* integrate *ANY* of this source code into another
14 * product before consulting with your legal department.
16 * For further information, read the top-level Openvision
17 * copyright which is contained in the top-level MIT Kerberos
20 * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
26 * Copyright 1993-1994 OpenVision Technologies, Inc., All Rights Reserved.
33 static char rcsid
[] = "$Id: kpasswd.c 17258 2005-06-21 01:36:03Z raeburn $";
35 #include <kadm5/admin.h>
38 #include "kpasswd_strings.h"
39 #define string_text error_message
50 extern void display_intro_message();
51 extern long read_old_password();
52 extern long read_new_password();
54 #define MISC_EXIT_STATUS 6
59 * Purpose: Initialize and call lower level routines to change a password
63 * context (r) krb5_context to use
64 * argc/argv (r) principal name to use, optional
65 * read_old_password (f) function to read old password
66 * read_new_password (f) function to read new and change password
67 * display_intro_message (f) function to display intro message
68 * whoami (extern) argv[0]
71 * exit status of 0 for success
73 * 2 old password wrong
74 * 3 cannot initialize admin server session
75 * 4 new passwd mismatch or error trying to change pw
76 * 5 password not typed
81 * Passwords cannot be more than 255 characters long.
85 * If argc is 2, the password for the principal specified in argv[1]
86 * is changed; otherwise, the principal of the default credential
87 * cache or username is used. display_intro_message is called with
88 * the arguments KPW_STR_CHANGING_PW_FOR and the principal name.
89 * read_old_password is then called to prompt for the old password.
90 * The admin system is then initialized, the principal's policy
91 * retrieved and explained, if appropriate, and finally
92 * read_new_password is called to read the new password and change the
93 * principal's password (presumably ovsec_kadm_chpass_principal).
94 * admin system is de-initialized before the function returns.
98 * Changes the principal's password.
102 kpasswd(context
, argc
, argv
)
103 krb5_context context
;
108 krb5_ccache ccache
= NULL
;
109 krb5_principal princ
= 0;
111 struct passwd
*pw
= 0;
113 char password
[255]; /* I don't really like 255 but that's what kinit uses */
114 char msg_ret
[1024], admin_realm
[1024];
115 kadm5_principal_ent_rec principal_entry
;
116 kadm5_policy_ent_rec policy_entry
;
118 kadm5_config_params params
;
121 memset((char *)¶ms
, 0, sizeof (params
));
122 memset(&principal_entry
, 0, sizeof (principal_entry
));
123 memset(&policy_entry
, 0, sizeof (policy_entry
));
126 com_err(whoami
, KPW_STR_USAGE
, 0);
131 /************************************
132 * Get principal name to change *
133 ************************************/
135 /* Look on the command line first, followed by the default credential
136 cache, followed by defaulting to the Unix user name */
139 princ_str
= strdup(argv
[1]);
141 code
= krb5_cc_default(context
, &ccache
);
142 /* If we succeed, find who is in the credential cache */
144 /* Get default principal from cache if one exists */
145 code
= krb5_cc_get_principal(context
, ccache
, &princ
);
146 /* if we got a principal, unparse it, otherwise get out of the if
147 with an error code */
148 (void) krb5_cc_close(context
, ccache
);
150 code
= krb5_unparse_name(context
, princ
, &princ_str
);
152 com_err(whoami
, code
, string_text(KPW_STR_UNPARSE_NAME
));
153 return(MISC_EXIT_STATUS
);
158 /* this is a crock.. we want to compare against */
159 /* "KRB5_CC_DOESNOTEXIST" but there is no such error code, and */
160 /* both the file and stdio types return FCC_NOFILE. If there is */
161 /* ever another ccache type (or if the error codes are ever */
162 /* fixed), this code will have to be updated. */
163 if (code
&& code
!= KRB5_FCC_NOFILE
) {
164 com_err(whoami
, code
, string_text(KPW_STR_WHILE_LOOKING_AT_CC
));
165 return(MISC_EXIT_STATUS
);
168 /* if either krb5_cc failed check the passwd file */
170 pw
= getpwuid( getuid());
172 com_err(whoami
, 0, string_text(KPW_STR_NOT_IN_PASSWD_FILE
));
173 return(MISC_EXIT_STATUS
);
175 princ_str
= strdup(pw
->pw_name
);
179 display_intro_message(string_text(KPW_STR_CHANGING_PW_FOR
), princ_str
);
181 /* Need to get a krb5_principal, unless we started from with one from
182 the credential cache */
185 code
= krb5_parse_name (context
, princ_str
, &princ
);
187 com_err(whoami
, code
, string_text(KPW_STR_PARSE_NAME
), princ_str
);
189 return(MISC_EXIT_STATUS
);
193 pwsize
= sizeof(password
);
194 code
= read_old_password(context
, password
, &pwsize
);
197 memset(password
, 0, sizeof(password
));
198 com_err(whoami
, code
, string_text(KPW_STR_WHILE_READING_PASSWORD
));
199 krb5_free_principal(context
, princ
);
201 return(MISC_EXIT_STATUS
);
204 memset(password
, 0, sizeof(password
));
205 com_err(whoami
, 0, string_text(KPW_STR_NO_PASSWORD_READ
));
206 krb5_free_principal(context
, princ
);
211 snprintf(admin_realm
, sizeof (admin_realm
),
212 krb5_princ_realm(context
, princ
)->data
);
213 params
.mask
|= KADM5_CONFIG_REALM
;
214 params
.realm
= admin_realm
;
217 if (kadm5_get_cpw_host_srv_name(context
, admin_realm
, &cpw_service
)) {
218 fprintf(stderr
, gettext("%s: unable to get host based "
219 "service name for realm %s\n"),
220 whoami
, admin_realm
);
224 code
= kadm5_init_with_password(princ_str
, password
, cpw_service
,
225 ¶ms
, KADM5_STRUCT_VERSION
,
226 KADM5_API_VERSION_2
, NULL
,
230 if (code
== KADM5_BAD_PASSWORD
)
232 string_text(KPW_STR_OLD_PASSWORD_INCORRECT
));
235 string_text(KPW_STR_CANT_OPEN_ADMIN_SERVER
),
237 error_message(code
));
238 krb5_free_principal(context
, princ
);
240 return ((code
== KADM5_BAD_PASSWORD
) ? 2 : 3);
244 * we can only check the policy if the server speaks
247 if (_kadm5_get_kpasswd_protocol(server_handle
) == KRB5_CHGPWD_RPCSEC
) {
248 /* Explain policy restrictions on new password if any. */
250 * Note: copy of this exists in login
251 * (kverify.c/get_verified_in_tkt).
254 code
= kadm5_get_principal(server_handle
, princ
,
256 KADM5_PRINCIPAL_NORMAL_MASK
);
259 string_text((code
== KADM5_UNK_PRINC
)
260 ? KPW_STR_PRIN_UNKNOWN
:
261 KPW_STR_CANT_GET_POLICY_INFO
),
263 krb5_free_principal(context
, princ
);
265 (void) kadm5_destroy(server_handle
);
266 return ((code
== KADM5_UNK_PRINC
) ? 1 :
269 if ((principal_entry
.aux_attributes
& KADM5_POLICY
) != 0) {
270 code
= kadm5_get_policy(server_handle
,
271 principal_entry
.policy
,
275 * doesn't matter which error comes back,
276 * there's no nice recovery or need to
277 * differentiate to the user
280 string_text(KPW_STR_CANT_GET_POLICY_INFO
),
282 (void) kadm5_free_principal_ent(server_handle
,
284 krb5_free_principal(context
, princ
);
287 (void) kadm5_destroy(server_handle
);
288 return (MISC_EXIT_STATUS
);
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
,
297 (void) kadm5_free_policy_ent(server_handle
,
299 krb5_free_principal(context
, princ
);
301 com_err(whoami
, code
,
302 string_text(KPW_STR_WHILE_FREEING_PRINCIPAL
));
303 (void) kadm5_destroy(server_handle
);
304 return (MISC_EXIT_STATUS
);
306 if (code
= kadm5_free_policy_ent(server_handle
,
308 krb5_free_principal(context
, princ
);
310 com_err(whoami
, code
,
311 string_text(KPW_STR_WHILE_FREEING_POLICY
));
312 (void) kadm5_destroy(server_handle
);
313 return (MISC_EXIT_STATUS
);
317 * kpasswd *COULD* output something here to
318 * encourage the choice of good passwords,
319 * in the absence of an enforced policy.
321 if (code
= kadm5_free_principal_ent(server_handle
,
323 krb5_free_principal(context
, princ
);
325 com_err(whoami
, code
,
326 string_text(KPW_STR_WHILE_FREEING_PRINCIPAL
));
327 (void) kadm5_destroy(server_handle
);
328 return (MISC_EXIT_STATUS
);
331 } /* if protocol == KRB5_CHGPWD_RPCSEC */
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
));
338 com_err(whoami
, 0, msg_ret
);
340 krb5_free_principal(context
, princ
);
343 (void) kadm5_destroy(server_handle
);
345 if (code
== KRB5_LIBOS_CANTREADPWD
)