1 /* $NetBSD: chpass_s.c,v 1.2 2017/01/28 21:31:49 christos Exp $ */
2
3 /*
4 * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include "kadm5_locl.h"
37
38 __RCSID("$NetBSD: chpass_s.c,v 1.2 2017/01/28 21:31:49 christos Exp $");
39
40 static kadm5_ret_t
change(void * server_handle,krb5_principal princ,int keepold,int n_ks_tuple,krb5_key_salt_tuple * ks_tuple,const char * password,int cond)41 change(void *server_handle,
42 krb5_principal princ,
43 int keepold,
44 int n_ks_tuple,
45 krb5_key_salt_tuple *ks_tuple,
46 const char *password,
47 int cond)
48 {
49 kadm5_server_context *context = server_handle;
50 hdb_entry_ex ent;
51 kadm5_ret_t ret;
52 Key *keys;
53 size_t num_keys;
54 int existsp = 0;
55
56 memset(&ent, 0, sizeof(ent));
57 if (!context->keep_open) {
58 ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
59 if(ret)
60 return ret;
61 }
62
63 ret = kadm5_log_init(context);
64 if (ret)
65 goto out;
66
67 ret = context->db->hdb_fetch_kvno(context->context, context->db, princ,
68 HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
69 if (ret)
70 goto out2;
71
72 if (keepold || cond) {
73 /*
74 * We save these for now so we can handle password history checking;
75 * we handle keepold further below.
76 */
77 ret = hdb_add_current_keys_to_history(context->context, &ent.entry);
78 if (ret)
79 goto out3;
80 }
81
82 if (context->db->hdb_capability_flags & HDB_CAP_F_HANDLE_PASSWORDS) {
83 ret = context->db->hdb_password(context->context, context->db,
84 &ent, password, cond);
85 if (ret)
86 goto out3;
87 } else {
88
89 num_keys = ent.entry.keys.len;
90 keys = ent.entry.keys.val;
91
92 ent.entry.keys.len = 0;
93 ent.entry.keys.val = NULL;
94
95 ret = _kadm5_set_keys(context, &ent.entry, n_ks_tuple, ks_tuple,
96 password);
97 if(ret) {
98 _kadm5_free_keys(context->context, num_keys, keys);
99 goto out3;
100 }
101 _kadm5_free_keys(context->context, num_keys, keys);
102
103 if (cond) {
104 HDB_extension *ext;
105
106 ext = hdb_find_extension(&ent.entry, choice_HDB_extension_data_hist_keys);
107 if (ext != NULL)
108 existsp = _kadm5_exists_keys_hist(ent.entry.keys.val,
109 ent.entry.keys.len,
110 &ext->data.u.hist_keys);
111 }
112
113 if (existsp) {
114 ret = KADM5_PASS_REUSE;
115 krb5_set_error_message(context->context, ret,
116 "Password reuse forbidden");
117 goto out3;
118 }
119 }
120 ent.entry.kvno++;
121
122 ent.entry.flags.require_pwchange = 0;
123
124 if (!keepold) {
125 HDB_extension ext;
126
127 memset(&ext, 0, sizeof (ext));
128 ext.mandatory = FALSE;
129 ext.data.element = choice_HDB_extension_data_hist_keys;
130 ret = hdb_replace_extension(context->context, &ent.entry, &ext);
131 if (ret)
132 goto out3;
133 }
134
135 ret = hdb_seal_keys(context->context, context->db, &ent.entry);
136 if (ret)
137 goto out3;
138
139 ret = _kadm5_set_modifier(context, &ent.entry);
140 if(ret)
141 goto out3;
142
143 ret = _kadm5_bump_pw_expire(context, &ent.entry);
144 if (ret)
145 goto out3;
146
147 /* This logs the change for iprop and writes to the HDB */
148 ret = kadm5_log_modify(context, &ent.entry,
149 KADM5_ATTRIBUTES | KADM5_PRINCIPAL |
150 KADM5_MOD_NAME | KADM5_MOD_TIME |
151 KADM5_KEY_DATA | KADM5_KVNO |
152 KADM5_PW_EXPIRATION | KADM5_TL_DATA);
153
154 out3:
155 hdb_free_entry(context->context, &ent);
156 out2:
157 (void) kadm5_log_end(context);
158 out:
159 if (!context->keep_open) {
160 kadm5_ret_t ret2;
161 ret2 = context->db->hdb_close(context->context, context->db);
162 if (ret == 0 && ret2 != 0)
163 ret = ret2;
164 }
165 return _kadm5_error_code(ret);
166 }
167
168
169
170 /*
171 * change the password of `princ' to `password' if it's not already that.
172 */
173
174 kadm5_ret_t
kadm5_s_chpass_principal_cond(void * server_handle,krb5_principal princ,int keepold,const char * password)175 kadm5_s_chpass_principal_cond(void *server_handle,
176 krb5_principal princ,
177 int keepold,
178 const char *password)
179 {
180 return change (server_handle, princ, keepold, 0, NULL, password, 1);
181 }
182
183 /*
184 * change the password of `princ' to `password'
185 */
186
187 kadm5_ret_t
kadm5_s_chpass_principal(void * server_handle,krb5_principal princ,int keepold,int n_ks_tuple,krb5_key_salt_tuple * ks_tuple,const char * password)188 kadm5_s_chpass_principal(void *server_handle,
189 krb5_principal princ,
190 int keepold,
191 int n_ks_tuple,
192 krb5_key_salt_tuple *ks_tuple,
193 const char *password)
194 {
195 return change (server_handle, princ, keepold,
196 n_ks_tuple, ks_tuple, password, 0);
197 }
198
199 /*
200 * change keys for `princ' to `keys'
201 */
202
203 kadm5_ret_t
kadm5_s_chpass_principal_with_key(void * server_handle,krb5_principal princ,int keepold,int n_key_data,krb5_key_data * key_data)204 kadm5_s_chpass_principal_with_key(void *server_handle,
205 krb5_principal princ,
206 int keepold,
207 int n_key_data,
208 krb5_key_data *key_data)
209 {
210 kadm5_server_context *context = server_handle;
211 hdb_entry_ex ent;
212 kadm5_ret_t ret;
213
214 memset(&ent, 0, sizeof(ent));
215 if (!context->keep_open) {
216 ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
217 if(ret)
218 return ret;
219 }
220
221 ret = kadm5_log_init(context);
222 if (ret)
223 goto out;
224
225 ret = context->db->hdb_fetch_kvno(context->context, context->db, princ, 0,
226 HDB_F_GET_ANY|HDB_F_ADMIN_DATA, &ent);
227 if (ret == HDB_ERR_NOENTRY)
228 goto out2;
229 if (keepold) {
230 ret = hdb_add_current_keys_to_history(context->context, &ent.entry);
231 if (ret)
232 goto out3;
233 }
234 ret = _kadm5_set_keys2(context, &ent.entry, n_key_data, key_data);
235 if (ret)
236 goto out3;
237 ent.entry.kvno++;
238 ret = _kadm5_set_modifier(context, &ent.entry);
239 if (ret)
240 goto out3;
241 ret = _kadm5_bump_pw_expire(context, &ent.entry);
242 if (ret)
243 goto out3;
244
245 if (keepold) {
246 ret = hdb_seal_keys(context->context, context->db, &ent.entry);
247 if (ret)
248 goto out3;
249 } else {
250 HDB_extension ext;
251
252 memset(&ext, 0, sizeof (ext));
253 ext.mandatory = FALSE;
254 ext.data.element = choice_HDB_extension_data_hist_keys;
255 ext.data.u.hist_keys.len = 0;
256 ext.data.u.hist_keys.val = NULL;
257 hdb_replace_extension(context->context, &ent.entry, &ext);
258 }
259
260 /* This logs the change for iprop and writes to the HDB */
261 ret = kadm5_log_modify(context, &ent.entry,
262 KADM5_PRINCIPAL | KADM5_MOD_NAME |
263 KADM5_MOD_TIME | KADM5_KEY_DATA | KADM5_KVNO |
264 KADM5_PW_EXPIRATION | KADM5_TL_DATA);
265
266 out3:
267 hdb_free_entry(context->context, &ent);
268 out2:
269 (void) kadm5_log_end(context);
270 out:
271 if (!context->keep_open) {
272 kadm5_ret_t ret2;
273 ret2 = context->db->hdb_close(context->context, context->db);
274 if (ret == 0 && ret2 != 0)
275 ret = ret2;
276 }
277 return _kadm5_error_code(ret);
278 }
279