1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
4 */
5
6
7 #include "k5-int.h"
8
9 #include <kadm5/admin.h>
10 #include "admin_internal.h"
11
12
13 #define string_text error_message
14
15 /*
16 * Function: kadm5_chpass_principal_util
17 *
18 * Purpose: Wrapper around chpass_principal. We can read new pw, change pw and return useful messages
19 *
20 * Arguments:
21 *
22 * princ (input) a krb5b_principal structure for the
23 * principal whose password we should change.
24 *
25 * new_password (input) NULL or a null terminated string with the
26 * the principal's desired new password. If new_password
27 * is NULL then this routine will read a new password.
28 *
29 * pw_ret (output) if non-NULL, points to a static buffer
30 * containing the new password (if password is prompted
31 * internally), or to the new_password argument (if
32 * that is non-NULL). If the former, then the buffer
33 * is only valid until the next call to the function,
34 * and the caller should be sure to zero it when
35 * it is no longer needed.
36 *
37 * msg_ret (output) a useful message is copied here.
38 *
39 * <return value> exit status of 0 for success, else the com err code
40 * for the last significant routine called.
41 *
42 * Requires:
43 *
44 * A msg_ret should point to a buffer large enough for the messasge.
45 *
46 * Effects:
47 *
48 * Modifies:
49 *
50 *
51 */
52
_kadm5_chpass_principal_util(void * server_handle,void * lhandle,krb5_principal princ,char * new_pw,char ** ret_pw,char * msg_ret,unsigned int msg_len)53 kadm5_ret_t _kadm5_chpass_principal_util(void *server_handle,
54 void *lhandle,
55 krb5_principal princ,
56 char *new_pw,
57 char **ret_pw,
58 char *msg_ret,
59 unsigned int msg_len)
60 {
61 int code, code2;
62 unsigned int pwsize;
63 static char buffer[255];
64 char *new_password;
65 kadm5_principal_ent_rec princ_ent;
66 kadm5_policy_ent_rec policy_ent;
67
68 _KADM5_CHECK_HANDLE(server_handle);
69
70 if (ret_pw)
71 *ret_pw = NULL;
72
73 if (new_pw != NULL) {
74 new_password = new_pw;
75 } else { /* read the password */
76 krb5_context context;
77
78 if ((code = (int) kadm5_init_krb5_context(&context)) == 0) {
79 pwsize = sizeof(buffer);
80 code = krb5_read_password(context, KADM5_PW_FIRST_PROMPT,
81 KADM5_PW_SECOND_PROMPT,
82 buffer, &pwsize);
83 krb5_free_context(context);
84 }
85
86 if (code == 0)
87 new_password = buffer;
88 else {
89 #ifdef ZEROPASSWD
90 memset(buffer, 0, sizeof(buffer));
91 #endif
92 if (code == KRB5_LIBOS_BADPWDMATCH) {
93 strncpy(msg_ret, string_text(CHPASS_UTIL_NEW_PASSWORD_MISMATCH),
94 msg_len - 1);
95 msg_ret[msg_len - 1] = '\0';
96 return(code);
97 } else {
98 snprintf(msg_ret, msg_len, "%s %s\n\n%s",
99 error_message(code),
100 string_text(CHPASS_UTIL_WHILE_READING_PASSWORD),
101 string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED));
102 msg_ret[msg_len - 1] = '\0';
103 return(code);
104 }
105 }
106 if (pwsize == 0) {
107 #ifdef ZEROPASSWD
108 memset(buffer, 0, sizeof(buffer));
109 #endif
110 strncpy(msg_ret, string_text(CHPASS_UTIL_NO_PASSWORD_READ), msg_len - 1);
111 msg_ret[msg_len - 1] = '\0';
112 return(KRB5_LIBOS_CANTREADPWD); /* could do better */
113 }
114 }
115
116 if (ret_pw)
117 *ret_pw = new_password;
118
119 code = kadm5_chpass_principal(server_handle, princ, new_password);
120
121 #ifdef ZEROPASSWD
122 if (!ret_pw)
123 memset(buffer, 0, sizeof(buffer)); /* in case we read a new password */
124 #endif
125
126 if (code == KADM5_OK) {
127 strncpy(msg_ret, string_text(CHPASS_UTIL_PASSWORD_CHANGED), msg_len - 1);
128 msg_ret[msg_len - 1] = '\0';
129 return(0);
130 }
131
132 if ((code != KADM5_PASS_Q_TOOSHORT) &&
133 (code != KADM5_PASS_REUSE) &&(code != KADM5_PASS_Q_CLASS) &&
134 (code != KADM5_PASS_Q_DICT) && (code != KADM5_PASS_TOOSOON)) {
135 /* Can't get more info for other errors */
136 snprintf(msg_ret, msg_len, "%s\n%s %s\n",
137 string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED),
138 error_message(code),
139 string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE));
140 return(code);
141 }
142
143 /* Ok, we have a password quality error. Return a good message */
144
145 if (code == KADM5_PASS_REUSE) {
146 strncpy(msg_ret, string_text(CHPASS_UTIL_PASSWORD_REUSE), msg_len - 1);
147 msg_ret[msg_len - 1] = '\0';
148 return(code);
149 }
150
151 if (code == KADM5_PASS_Q_DICT) {
152 strncpy(msg_ret, string_text(CHPASS_UTIL_PASSWORD_IN_DICTIONARY),
153 msg_len - 1);
154 msg_ret[msg_len - 1] = '\0';
155 return(code);
156 }
157
158 /* Look up policy for the remaining messages */
159
160 code2 = kadm5_get_principal (lhandle, princ, &princ_ent,
161 KADM5_PRINCIPAL_NORMAL_MASK);
162 if (code2 != 0) {
163 snprintf(msg_ret, msg_len, "%s %s\n%s %s\n\n%s\n",
164 error_message(code2),
165 string_text(CHPASS_UTIL_GET_PRINC_INFO),
166 error_message(code),
167 string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE),
168 string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED));
169 msg_ret[msg_len - 1] = '\0';
170 return(code);
171 }
172
173 if ((princ_ent.aux_attributes & KADM5_POLICY) == 0) {
174 /* Some module implements its own password policy. */
175 snprintf(msg_ret, msg_len, "%s\n\n%s",
176 error_message(code),
177 string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED));
178 msg_ret[msg_len - 1] = '\0';
179 (void) kadm5_free_principal_ent(lhandle, &princ_ent);
180 return(code);
181 }
182
183 code2 = kadm5_get_policy(lhandle, princ_ent.policy,
184 &policy_ent);
185 if (code2 != 0) {
186 snprintf(msg_ret, msg_len, "%s %s\n%s %s\n\n%s\n ", error_message(code2),
187 string_text(CHPASS_UTIL_GET_POLICY_INFO),
188 error_message(code),
189 string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE),
190 string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED));
191 (void) kadm5_free_principal_ent(lhandle, &princ_ent);
192 return(code);
193 }
194
195 if (code == KADM5_PASS_Q_TOOSHORT) {
196 snprintf(msg_ret, msg_len, string_text(CHPASS_UTIL_PASSWORD_TOO_SHORT),
197 policy_ent.pw_min_length);
198 (void) kadm5_free_principal_ent(lhandle, &princ_ent);
199 (void) kadm5_free_policy_ent(lhandle, &policy_ent);
200 return(code);
201 }
202
203 /* Can't get more info for other errors */
204
205 if (code == KADM5_PASS_Q_CLASS) {
206 snprintf(msg_ret, msg_len, string_text(CHPASS_UTIL_TOO_FEW_CLASSES),
207 policy_ent.pw_min_classes);
208 (void) kadm5_free_principal_ent(lhandle, &princ_ent);
209 (void) kadm5_free_policy_ent(lhandle, &policy_ent);
210 return(code);
211 }
212
213 if (code == KADM5_PASS_TOOSOON) {
214 time_t until;
215 char *time_string, *ptr;
216
217 until = ts_incr(princ_ent.last_pwd_change, policy_ent.pw_min_life);
218
219 time_string = ctime(&until);
220 if (time_string == NULL)
221 time_string = "(error)";
222 else if (*(ptr = &time_string[strlen(time_string)-1]) == '\n')
223 *ptr = '\0';
224
225 snprintf(msg_ret, msg_len, string_text(CHPASS_UTIL_PASSWORD_TOO_SOON),
226 time_string);
227 (void) kadm5_free_principal_ent(lhandle, &princ_ent);
228 (void) kadm5_free_policy_ent(lhandle, &policy_ent);
229 return(code);
230 }
231
232 /* We should never get here, but just in case ... */
233 snprintf(msg_ret, msg_len, "%s\n%s %s\n",
234 string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED),
235 error_message(code),
236 string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE));
237 (void) kadm5_free_principal_ent(lhandle, &princ_ent);
238 (void) kadm5_free_policy_ent(lhandle, &policy_ent);
239 return(code);
240 }
241