HEIMDAL: move code from source4/heimdal* to third_party/heimdal*
[samba.git] / third_party / heimdal / lib / kadm5 / setkey3_s.c
1 /*
2  * Copyright (c) 1997-2001, 2003, 2005-2006 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include "kadm5_locl.h"
35
36 struct setkey_principal_hook_ctx {
37     kadm5_server_context *context;
38     enum kadm5_hook_stage stage;
39     krb5_error_code code;
40     krb5_const_principal princ;
41     uint32_t flags;
42     size_t n_ks_tuple;
43     krb5_key_salt_tuple *ks_tuple;
44     size_t n_keys;
45     krb5_keyblock *keys;
46 };
47
48 static krb5_error_code KRB5_LIB_CALL
49 setkey_principal_hook_cb(krb5_context context,
50                          const void *hook,
51                          void *hookctx,
52                          void *userctx)
53 {
54     krb5_error_code ret;
55     const struct kadm5_hook_ftable *ftable = hook;
56     struct setkey_principal_hook_ctx *ctx = userctx;
57
58     ret = ftable->set_keys(context, hookctx,
59                            ctx->stage, ctx->code,
60                            ctx->princ, ctx->flags,
61                            ctx->n_ks_tuple, ctx->ks_tuple,
62                            ctx->n_keys, ctx->keys);
63     if (ret != 0 && ret != KRB5_PLUGIN_NO_HANDLE)
64         _kadm5_s_set_hook_error_message(ctx->context, ret, "setkey",
65                                         hook, ctx->stage);
66
67     /* only pre-commit plugins can abort */
68     if (ret == 0 || ctx->stage == KADM5_HOOK_STAGE_POSTCOMMIT)
69         ret = KRB5_PLUGIN_NO_HANDLE;
70
71     return ret;
72 }
73
74 static kadm5_ret_t
75 setkey_principal_hook(kadm5_server_context *context,
76                       enum kadm5_hook_stage stage,
77                       krb5_error_code code,
78                       krb5_const_principal princ,
79                       uint32_t flags,
80                       size_t n_ks_tuple,
81                       krb5_key_salt_tuple *ks_tuple,
82                       size_t n_keys,
83                       krb5_keyblock *keyblocks)
84 {
85     krb5_error_code ret;
86     struct setkey_principal_hook_ctx ctx;
87
88     ctx.context = context;
89     ctx.stage = stage;
90     ctx.code = code;
91     ctx.princ = princ;
92     ctx.flags = flags;
93     ctx.n_ks_tuple = n_ks_tuple;
94     ctx.ks_tuple = ks_tuple;
95     ctx.n_keys = n_keys;
96     ctx.keys = keyblocks;
97
98     ret = _krb5_plugin_run_f(context->context, &kadm5_hook_plugin_data,
99                              0, &ctx, setkey_principal_hook_cb);
100     if (ret == KRB5_PLUGIN_NO_HANDLE)
101         ret = 0;
102
103     return ret;
104 }
105
106 /**
107  * Server-side function to set new keys for a principal.
108  */
109 kadm5_ret_t
110 kadm5_s_setkey_principal_3(void *server_handle,
111                            krb5_principal princ,
112                            krb5_boolean keepold,
113                            int n_ks_tuple,
114                            krb5_key_salt_tuple *ks_tuple,
115                            krb5_keyblock *keyblocks, int n_keys)
116 {
117     kadm5_server_context *context = server_handle;
118     hdb_entry_ex ent;
119     kadm5_ret_t ret = 0;
120     size_t i;
121
122     memset(&ent, 0, sizeof(ent));
123     if (!context->keep_open)
124         ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
125     if (ret)
126         return ret;
127
128     ret = kadm5_log_init(context);
129     if (ret) {
130         if (!context->keep_open)
131             context->db->hdb_close(context->context, context->db);
132         return ret;
133     }
134
135     /* NOTE: We do not use hdb_fetch_kvno() here (maybe we should?) */
136     ret = context->db->hdb_fetch_kvno(context->context, context->db, princ,
137                                       HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA,
138                                       0, &ent);
139     if (ret) {
140         (void) kadm5_log_end(context);
141         if (!context->keep_open)
142             context->db->hdb_close(context->context, context->db);
143         return ret;
144     }
145
146     ret = setkey_principal_hook(context, KADM5_HOOK_STAGE_PRECOMMIT, 0,
147                                 princ, keepold ? KADM5_HOOK_FLAG_KEEPOLD : 0,
148                                 n_ks_tuple, ks_tuple, n_keys, keyblocks);
149     if (ret) {
150         (void) kadm5_log_end(context);
151         if (!context->keep_open)
152             context->db->hdb_close(context->context, context->db);
153         return ret;
154     }
155
156     if (keepold) {
157         ret = hdb_add_current_keys_to_history(context->context, &ent.entry);
158     } else
159         ret = hdb_clear_extension(context->context, &ent.entry,
160                                   choice_HDB_extension_data_hist_keys);
161
162     /*
163      * Though in practice all real calls to this function will pass an empty
164      * ks_tuple, and cannot in any case employ any salts that require
165      * additional data, we go the extra mile to set any requested salt type
166      * along with a zero length salt value.  While we're at it we check that
167      * each ks_tuple's enctype matches the corresponding key enctype.
168      */
169     if (ret == 0) {
170         free_Keys(&ent.entry.keys);
171         for (i = 0; i < n_keys; ++i) {
172             Key k;
173             Salt s;
174
175             k.mkvno = 0;
176             k.key = keyblocks[i];
177             if (n_ks_tuple == 0)
178                 k.salt = 0;
179             else {
180                 if (ks_tuple[i].ks_enctype != keyblocks[i].keytype) {
181                     ret = KADM5_SETKEY3_ETYPE_MISMATCH;
182                     break;
183                 }
184                 s.type = ks_tuple[i].ks_salttype;
185                 s.salt.data = 0;
186                 s.opaque = 0;
187                 k.salt = &s;
188             }
189             if ((ret = add_Keys(&ent.entry.keys, &k)) != 0)
190                 break;
191         }
192     }
193
194     if (ret == 0) {
195         ent.entry.kvno++;
196         ent.entry.flags.require_pwchange = 0;
197         hdb_entry_set_pw_change_time(context->context, &ent.entry, 0);
198         hdb_entry_clear_password(context->context, &ent.entry);
199
200         if ((ret = hdb_seal_keys(context->context, context->db,
201                                  &ent.entry)) == 0
202             && (ret = _kadm5_set_modifier(context, &ent.entry)) == 0
203             && (ret = _kadm5_bump_pw_expire(context, &ent.entry)) == 0)
204             ret = kadm5_log_modify(context, &ent.entry,
205                                    KADM5_ATTRIBUTES | KADM5_PRINCIPAL |
206                                    KADM5_MOD_NAME | KADM5_MOD_TIME |
207                                    KADM5_KEY_DATA | KADM5_KVNO |
208                                    KADM5_PW_EXPIRATION | KADM5_TL_DATA);
209     }
210
211     (void) setkey_principal_hook(context, KADM5_HOOK_STAGE_POSTCOMMIT, ret,
212                                  princ, keepold, n_ks_tuple, ks_tuple,
213                                  n_keys, keyblocks);
214
215     hdb_free_entry(context->context, &ent);
216     (void) kadm5_log_end(context);
217     if (!context->keep_open)
218         context->db->hdb_close(context->context, context->db);
219     return _kadm5_error_code(ret);
220 }