s4:torture: Adapt KDC canon test to Heimdal upstream changes
[samba.git] / third_party / heimdal / lib / kadm5 / modify_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 RCSID("$Id$");
37
38 struct modify_principal_hook_ctx {
39     kadm5_server_context *context;
40     enum kadm5_hook_stage stage;
41     krb5_error_code code;
42     kadm5_principal_ent_t princ;
43     uint32_t mask;
44 };
45
46 static krb5_error_code KRB5_LIB_CALL
47 modify_principal_hook_cb(krb5_context context,
48                          const void *hook,
49                          void *hookctx,
50                          void *userctx)
51 {
52     krb5_error_code ret;
53     const struct kadm5_hook_ftable *ftable = hook;
54     struct modify_principal_hook_ctx *ctx = userctx;
55
56     ret = ftable->modify(context, hookctx, ctx->stage,
57                          ctx->code, ctx->princ, ctx->mask);
58     if (ret != 0 && ret != KRB5_PLUGIN_NO_HANDLE)
59         _kadm5_s_set_hook_error_message(ctx->context, ret, "modify",
60                                         hook, ctx->stage);
61
62     /* only pre-commit plugins can abort */
63     if (ret == 0 || ctx->stage == KADM5_HOOK_STAGE_POSTCOMMIT)
64         ret = KRB5_PLUGIN_NO_HANDLE;
65
66     return ret;
67 }
68
69 static kadm5_ret_t
70 modify_principal_hook(kadm5_server_context *context,
71                       enum kadm5_hook_stage stage,
72                       krb5_error_code code,
73                       kadm5_principal_ent_t princ,
74                       uint32_t mask)
75 {
76     krb5_error_code ret;
77     struct modify_principal_hook_ctx ctx;
78
79     ctx.context = context;
80     ctx.stage = stage;
81     ctx.code = code;
82     ctx.princ = princ;
83     ctx.mask = mask;
84
85     ret = _krb5_plugin_run_f(context->context, &kadm5_hook_plugin_data,
86                              0, &ctx, modify_principal_hook_cb);
87     if (ret == KRB5_PLUGIN_NO_HANDLE)
88         ret = 0;
89
90     return ret;
91 }
92
93 static kadm5_ret_t
94 modify_principal(void *server_handle,
95                  kadm5_principal_ent_t princ,
96                  uint32_t mask,
97                  uint32_t forbidden_mask)
98 {
99     kadm5_server_context *context = server_handle;
100     hdb_entry_ex ent;
101     kadm5_ret_t ret;
102
103     memset(&ent, 0, sizeof(ent));
104
105     if((mask & forbidden_mask))
106         return KADM5_BAD_MASK;
107     if((mask & KADM5_POLICY) && strcmp(princ->policy, "default") != 0)
108         return KADM5_UNK_POLICY;
109
110     if (!context->keep_open) {
111         ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
112         if(ret)
113             return ret;
114     }
115
116     ret = kadm5_log_init(context);
117     if (ret)
118         goto out;
119
120     /*
121      * NOTE: We do not use hdb_fetch_kvno() here, which means we'll
122      *       automatically reject modifications of would-be virtual principals.
123      */
124     ret = context->db->hdb_fetch_kvno(context->context, context->db,
125                                       princ->principal,
126                                       HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA,
127                                       0, &ent);
128     if (ret)
129         goto out2;
130
131     ret = modify_principal_hook(context, KADM5_HOOK_STAGE_PRECOMMIT,
132                                 0, princ, mask);
133     if (ret)
134         goto out3;
135     /*
136      * XXX Make sure that _kadm5_setup_entry() checks that the time of last
137      * change in `ent' matches the one in `princ'.
138      */
139     ret = _kadm5_setup_entry(context, &ent, mask, princ, mask, NULL, 0);
140     if (ret)
141         goto out3;
142     ret = _kadm5_set_modifier(context, &ent.entry);
143     if (ret)
144         goto out3;
145
146     /*
147      * If any keys are bogus, disallow the modify.  If the keys were
148      * bogus as stored in the HDB we could allow those through, but
149      * distinguishing that case from a pre-1.6 client using add_enctype
150      * without the get-keys privilege requires more work (mainly: checking that
151      * the bogus keys in princ->key_data[] have corresponding bogus keys in ent
152      * before calling _kadm5_setup_entry()).
153      */
154     if ((mask & KADM5_KEY_DATA) &&
155         kadm5_some_keys_are_bogus(princ->n_key_data, princ->key_data)) {
156         ret = KADM5_AUTH_GET_KEYS; /* Not quite appropriate, but it'll do */
157         goto out3;
158     }
159
160     ret = hdb_seal_keys(context->context, context->db, &ent.entry);
161     if (ret)
162         goto out3;
163
164     if ((mask & KADM5_POLICY)) {
165         HDB_extension ext;
166
167         memset(&ext, 0, sizeof(ext));
168         /* XXX should be TRUE, but we don't yet support policies */
169         ext.mandatory = FALSE;
170         ext.data.element = choice_HDB_extension_data_policy;
171         ext.data.u.policy = strdup(princ->policy);
172         if (ext.data.u.policy == NULL) {
173             ret = krb5_enomem(context->context);
174             goto out3;
175         }
176         /* This calls free_HDB_extension(), freeing ext.data.u.policy */
177         ret = hdb_replace_extension(context->context, &ent.entry, &ext);
178         free(ext.data.u.policy);
179         if (ret)
180             goto out3;
181     }
182
183     /* This logs the change for iprop and writes to the HDB */
184     ret = kadm5_log_modify(context, &ent.entry,
185                            mask | KADM5_MOD_NAME | KADM5_MOD_TIME);
186
187     (void) modify_principal_hook(context, KADM5_HOOK_STAGE_POSTCOMMIT,
188                                  ret, princ, mask);
189
190  out3:
191     hdb_free_entry(context->context, &ent);
192  out2:
193     (void) kadm5_log_end(context);
194  out:
195     if (!context->keep_open) {
196         kadm5_ret_t ret2;
197         ret2 = context->db->hdb_close(context->context, context->db);
198         if (ret == 0 && ret2 != 0)
199             ret = ret2;
200     }
201     return _kadm5_error_code(ret);
202 }
203
204
205 kadm5_ret_t
206 kadm5_s_modify_principal(void *server_handle,
207                          kadm5_principal_ent_t princ,
208                          uint32_t mask)
209 {
210     return modify_principal(server_handle, princ, mask,
211                             KADM5_LAST_PWD_CHANGE | KADM5_MOD_TIME
212                             | KADM5_MOD_NAME | KADM5_MKVNO
213                             | KADM5_AUX_ATTRIBUTES | KADM5_LAST_SUCCESS
214                             | KADM5_LAST_FAILED);
215 }