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