xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/kadm5/chpass_s.c (revision d3273b5b76f5afaafe308cead5511dbb8df8c5e9)
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