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 OpenVision Technologies, Inc., All Rights Reserved.
37 #include <kadm5/admin.h>
38 #include "admin_internal.h"
43 #define string_text error_message
45 const char *chpw_error_message(kadm5_ret_t code
);
48 * Function: kadm5_chpass_principal_util
50 * Purpose: Wrapper around chpass_principal. We can read new pw, change pw and return useful messages
54 * princ (input) a krb5b_principal structure for the
55 * principal whose password we should change.
57 * new_password (input) NULL or a null terminated string with the
58 * the principal's desired new password. If new_password
59 * is NULL then this routine will read a new password.
61 * pw_ret (output) if non-NULL, points to a static buffer
62 * containing the new password (if password is prompted
63 * internally), or to the new_password argument (if
64 * that is non-NULL). If the former, then the buffer
65 * is only valid until the next call to the function,
66 * and the caller should be sure to zero it when
67 * it is no longer needed.
69 * msg_ret (output) a useful message is copied here.
71 * <return value> exit status of 0 for success, else the com err code
72 * for the last significant routine called.
76 * A msg_ret should point to a buffer large enough for the messasge.
85 kadm5_ret_t
_kadm5_chpass_principal_util(void *server_handle
,
95 static char buffer
[255];
97 kadm5_principal_ent_rec princ_ent
;
98 kadm5_policy_ent_rec policy_ent
;
99 krb5_chgpwd_prot passwd_protocol
;
101 _KADM5_CHECK_HANDLE(server_handle
);
106 if (new_pw
!= NULL
) {
107 new_password
= new_pw
;
108 } else { /* read the password */
109 krb5_context context
;
111 if ((code
= (int) kadm5_init_krb5_context(&context
)) == 0) {
112 pwsize
= sizeof(buffer
);
113 code
= krb5_read_password(context
, KADM5_PW_FIRST_PROMPT
,
114 KADM5_PW_SECOND_PROMPT
,
116 krb5_free_context(context
);
120 new_password
= buffer
;
123 memset(buffer
, 0, sizeof(buffer
));
125 if (code
== KRB5_LIBOS_BADPWDMATCH
) {
126 (void) strncpy(msg_ret
, string_text(CHPASS_UTIL_NEW_PASSWORD_MISMATCH
),
128 msg_ret
[msg_len
- 1] = '\0';
131 (void) strncpy(msg_ret
, error_message(code
), msg_len
- 1);
132 (void) strncat(msg_ret
, " ", msg_len
- 1);
133 (void) strncat(msg_ret
, string_text(CHPASS_UTIL_WHILE_READING_PASSWORD
),
135 (void) strncat(msg_ret
, string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED
),
137 msg_ret
[msg_len
- 1] = '\0';
143 memset(buffer
, 0, sizeof(buffer
));
145 strncpy(msg_ret
, string_text(CHPASS_UTIL_NO_PASSWORD_READ
), msg_len
- 1);
146 msg_ret
[msg_len
- 1] = '\0';
147 return(KRB5_LIBOS_CANTREADPWD
); /* could do better */
152 *ret_pw
= new_password
;
154 passwd_protocol
= _kadm5_get_kpasswd_protocol(server_handle
);
155 if (passwd_protocol
== KRB5_CHGPWD_CHANGEPW_V2
) {
156 kadm5_ret_t srvr_rsp_code
;
160 srvr_msg
.data
= NULL
;
162 code
= kadm5_chpass_principal_v2(server_handle
, princ
,
167 sprintf(msg_ret
, "%s%s%.*s\n",
168 chpw_error_message(srvr_rsp_code
),
169 srvr_msg
.length
? ": " : "",
171 srvr_msg
.data
? srvr_msg
.data
: "");
173 return (srvr_rsp_code
);
177 } else if (passwd_protocol
== KRB5_CHGPWD_RPCSEC
) {
178 code
= kadm5_chpass_principal(server_handle
, princ
,
183 memset(buffer
, 0, sizeof(buffer
)); /* in case we read a new password */
186 if (code
== KADM5_OK
) {
187 strncpy(msg_ret
, string_text(CHPASS_UTIL_PASSWORD_CHANGED
), msg_len
- 1);
188 msg_ret
[msg_len
- 1] = '\0';
192 if ((code
!= KADM5_PASS_Q_TOOSHORT
) &&
193 (code
!= KADM5_PASS_REUSE
) &&(code
!= KADM5_PASS_Q_CLASS
) &&
194 (code
!= KADM5_PASS_Q_DICT
) && (code
!= KADM5_PASS_TOOSOON
)) {
195 /* Can't get more info for other errors */
196 sprintf(buffer
, "%s %s", error_message(code
),
197 string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE
));
198 sprintf(msg_ret
, "%s\n%s\n", string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED
),
203 /* Ok, we have a password quality error. Return a good message */
205 if (code
== KADM5_PASS_REUSE
) {
206 strncpy(msg_ret
, string_text(CHPASS_UTIL_PASSWORD_REUSE
), msg_len
- 1);
207 msg_ret
[msg_len
- 1] = '\0';
211 if (code
== KADM5_PASS_Q_DICT
) {
212 strncpy(msg_ret
, string_text(CHPASS_UTIL_PASSWORD_IN_DICTIONARY
),
214 msg_ret
[msg_len
- 1] = '\0';
218 /* Look up policy for the remaining messages */
220 code2
= kadm5_get_principal (lhandle
, princ
, &princ_ent
,
221 KADM5_PRINCIPAL_NORMAL_MASK
);
223 strncpy(msg_ret
, error_message(code2
), msg_len
- 1);
224 strncat(msg_ret
, " ", msg_len
- 1 - strlen(msg_ret
));
225 strncat(msg_ret
, string_text(CHPASS_UTIL_GET_PRINC_INFO
), msg_len
- 1 - strlen(msg_ret
));
226 strncat(msg_ret
, "\n", msg_len
- 1 - strlen(msg_ret
));
227 strncat(msg_ret
, error_message(code
), msg_len
- 1 - strlen(msg_ret
));
228 strncat(msg_ret
, " ", msg_len
- 1 - strlen(msg_ret
));
229 strncat(msg_ret
, string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE
),
230 msg_len
- 1 - strlen(msg_ret
));
231 strncat(msg_ret
, "\n\n", msg_len
- 1 - strlen(msg_ret
));
232 strncat(msg_ret
, string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED
),
233 msg_len
- 1 - strlen(msg_ret
));
234 strncat(msg_ret
, "\n", msg_len
- 1 - strlen(msg_ret
));
235 msg_ret
[msg_len
- 1] = '\0';
239 if ((princ_ent
.aux_attributes
& KADM5_POLICY
) == 0) {
240 strncpy(msg_ret
, error_message(code
), msg_len
- 1 - strlen(msg_ret
));
241 strncat(msg_ret
, " ", msg_len
- 1 - strlen(msg_ret
));
242 strncpy(msg_ret
, string_text(CHPASS_UTIL_NO_POLICY_YET_Q_ERROR
),
243 msg_len
- 1 - strlen(msg_ret
));
244 strncat(msg_ret
, "\n\n", msg_len
- 1 - strlen(msg_ret
));
245 strncpy(msg_ret
, string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED
),
246 msg_len
- 1 - strlen(msg_ret
));
247 msg_ret
[msg_len
- 1] = '\0';
249 (void) kadm5_free_principal_ent(lhandle
, &princ_ent
);
253 code2
= kadm5_get_policy(lhandle
, princ_ent
.policy
,
256 sprintf(msg_ret
, "%s %s\n%s %s\n\n%s\n ", error_message(code2
),
257 string_text(CHPASS_UTIL_GET_POLICY_INFO
),
259 string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE
),
260 string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED
));
261 (void) kadm5_free_principal_ent(lhandle
, &princ_ent
);
265 if (code
== KADM5_PASS_Q_TOOSHORT
) {
266 sprintf(msg_ret
, string_text(CHPASS_UTIL_PASSWORD_TOO_SHORT
),
267 policy_ent
.pw_min_length
);
268 (void) kadm5_free_principal_ent(lhandle
, &princ_ent
);
269 (void) kadm5_free_policy_ent(lhandle
, &policy_ent
);
274 if (code
== KADM5_PASS_Q_CLASS
) {
275 sprintf(msg_ret
, string_text(CHPASS_UTIL_TOO_FEW_CLASSES
),
276 policy_ent
.pw_min_classes
);
277 (void) kadm5_free_principal_ent(lhandle
, &princ_ent
);
278 (void) kadm5_free_policy_ent(lhandle
, &policy_ent
);
282 if (code
== KADM5_PASS_TOOSOON
) {
284 char *time_string
, *ptr
;
286 until
= princ_ent
.last_pwd_change
+ policy_ent
.pw_min_life
;
288 time_string
= ctime(&until
);
289 if (*(ptr
= &time_string
[strlen(time_string
)-1]) == '\n')
292 sprintf(msg_ret
, string_text(CHPASS_UTIL_PASSWORD_TOO_SOON
),
294 (void) kadm5_free_principal_ent(lhandle
, &princ_ent
);
295 (void) kadm5_free_policy_ent(lhandle
, &policy_ent
);
299 /* We should never get here, but just in case ... */
300 sprintf(buffer
, "%s %s", error_message(code
),
301 string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE
));
302 sprintf(msg_ret
, "%s\n%s\n", string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED
),
304 (void) kadm5_free_principal_ent(lhandle
, &princ_ent
);
305 (void) kadm5_free_policy_ent(lhandle
, &policy_ent
);
309 sprintf(msg_ret
, "%s\n%s\n",
310 string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED
),
311 "Password protocol in krb5.conf is not supported\n");
317 * krb5_chpw_result_code_string
319 * convert the return code received from the password server
320 * to a human-readable string.
323 chpw_error_message(kadm5_ret_t result_code
)
325 switch (result_code
) {
326 case KRB5_KPASSWD_MALFORMED
:
327 return (dgettext(TEXT_DOMAIN
, "Malformed request error"));
328 case KRB5_KPASSWD_HARDERROR
:
329 return (dgettext(TEXT_DOMAIN
, "Server error"));
330 case KRB5_KPASSWD_AUTHERROR
:
331 return (dgettext(TEXT_DOMAIN
, "Authentication error"));
332 case KRB5_KPASSWD_SOFTERROR
:
333 return (dgettext(TEXT_DOMAIN
, "Password change rejected"));
334 case KRB5_KPASSWD_ACCESSDENIED
:
335 return (dgettext(TEXT_DOMAIN
,
336 "Not authorized to change password"));
337 case KRB5_KPASSWD_BAD_VERSION
:
338 return (dgettext(TEXT_DOMAIN
, "Protocol version unsupported"));
339 case KRB5_KPASSWD_INITIAL_FLAG_NEEDED
:
340 return (dgettext(TEXT_DOMAIN
,
341 "initial flag required in changepw request"));
342 case KRB5_KPASSWD_POLICY_REJECT
:
343 return (dgettext(TEXT_DOMAIN
, "new password fails policy"));
344 case KRB5_KPASSWD_BAD_PRINCIPAL
:
345 return (dgettext(TEXT_DOMAIN
,
346 "target principal does not exist for "
347 "changepw request"));
348 case KRB5_KPASSWD_ETYPE_NOSUPP
:
349 return (dgettext(TEXT_DOMAIN
,
350 "changepw request key sequence has an "
351 "unsupported Etype"));
353 return (dgettext(TEXT_DOMAIN
, "Password change failed"));