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 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 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 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 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