r23792: convert Samba4 to GPLv3
[ira/wip.git] / source4 / dsdb / samdb / ldb_modules / update_keytab.c
1 /* 
2    ldb database library
3
4    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 /*
21  *  Name: ldb
22  *
23  *  Component: ldb update_keytabs module
24  *
25  *  Description: Update keytabs whenever their matching secret record changes
26  *
27  *  Author: Andrew Bartlett
28  */
29
30 #include "includes.h"
31 #include "ldb/include/ldb_includes.h"
32 #include "auth/credentials/credentials.h"
33 #include "auth/credentials/credentials_krb5.h"
34 #include "system/kerberos.h"
35
36 struct dn_list {
37         struct cli_credentials *creds;
38         struct dn_list *prev, *next;
39 };
40
41 struct update_kt_private {
42         struct dn_list *changed_dns;
43 };
44
45 static int add_modified(struct ldb_module *module, struct ldb_dn *dn, BOOL delete) {
46         struct update_kt_private *data = talloc_get_type(module->private_data, struct update_kt_private);
47         struct dn_list *item;
48         char *filter;
49         struct ldb_result *res;
50         const char *attrs[] = { NULL };
51         int ret;
52         NTSTATUS status;
53
54         filter = talloc_asprintf(data, "(&(dn=%s)(&(objectClass=kerberosSecret)(privateKeytab=*)))",
55                                  ldb_dn_get_linearized(dn));
56         if (!filter) {
57                 ldb_oom(module->ldb);
58                 return LDB_ERR_OPERATIONS_ERROR;
59         }
60
61         ret = ldb_search(module->ldb, dn, LDB_SCOPE_BASE,
62                          filter, attrs, &res);
63         if (ret != LDB_SUCCESS) {
64                 talloc_free(filter);
65                 return ret;
66         }
67
68         if (res->count != 1) {
69                 /* if it's not a kerberosSecret then we don't have anything to update */
70                 talloc_free(res);
71                 talloc_free(filter);
72                 return LDB_SUCCESS;
73         }
74         talloc_free(res);
75
76         item = talloc(data->changed_dns? (void *)data->changed_dns: (void *)data, struct dn_list);
77         if (!item) {
78                 talloc_free(filter);
79                 ldb_oom(module->ldb);
80                 return LDB_ERR_OPERATIONS_ERROR;
81         }
82         
83         item->creds = cli_credentials_init(item);
84         if (!item->creds) {
85                 DEBUG(1, ("cli_credentials_init failed!"));
86                 talloc_free(filter);
87                 ldb_oom(module->ldb);
88                 return LDB_ERR_OPERATIONS_ERROR;
89         }
90
91         cli_credentials_set_conf(item->creds);
92         status = cli_credentials_set_secrets(item->creds, module->ldb, NULL, filter);
93         talloc_free(filter);
94         if (NT_STATUS_IS_OK(status)) {
95                 if (delete) {
96                         /* Ensure we don't helpfully keep an old keytab entry */
97                         cli_credentials_set_kvno(item->creds, cli_credentials_get_kvno(item->creds)+2); 
98                         /* Wipe passwords */
99                         cli_credentials_set_nt_hash(item->creds, NULL, 
100                                                     CRED_SPECIFIED);
101                 }
102                 DLIST_ADD_END(data->changed_dns, item, struct dn_list *);
103         }
104         return LDB_SUCCESS;
105 }
106
107 /* add */
108 static int update_kt_add(struct ldb_module *module, struct ldb_request *req)
109 {
110         int ret;
111         ret = ldb_next_request(module, req);
112         if (ret != LDB_SUCCESS) {
113                 return ret;
114         }
115         return add_modified(module, req->op.add.message->dn, False);
116 }
117
118 /* modify */
119 static int update_kt_modify(struct ldb_module *module, struct ldb_request *req)
120 {
121         int ret;
122         ret = ldb_next_request(module, req);
123         if (ret != LDB_SUCCESS) {
124                 return ret;
125         }
126         return add_modified(module, req->op.mod.message->dn, False);
127 }
128
129 /* delete */
130 static int update_kt_delete(struct ldb_module *module, struct ldb_request *req)
131 {
132         int ret;
133         /* Before we delete it, record the details */
134         ret = add_modified(module, req->op.del.dn, True);
135         if (ret != LDB_SUCCESS) {
136                 return ret;
137         }
138         return ldb_next_request(module, req);
139 }
140
141 /* rename */
142 static int update_kt_rename(struct ldb_module *module, struct ldb_request *req)
143 {
144         int ret;
145         ret = ldb_next_request(module, req);
146         if (ret != LDB_SUCCESS) {
147                 return ret;
148         }
149         return add_modified(module, req->op.rename.newdn, False);
150 }
151
152 /* end a transaction */
153 static int update_kt_end_trans(struct ldb_module *module)
154 {
155         struct update_kt_private *data = talloc_get_type(module->private_data, struct update_kt_private);
156         
157         struct dn_list *p;
158         for (p=data->changed_dns; p; p = p->next) {
159                 int kret;
160                 kret = cli_credentials_update_keytab(p->creds);
161                 if (kret != 0) {
162                         talloc_free(data->changed_dns);
163                         data->changed_dns = NULL;
164                         ldb_asprintf_errstring(module->ldb, "Failed to update keytab: %s", error_message(kret));
165                         return LDB_ERR_OPERATIONS_ERROR;
166                 }
167         }
168
169         talloc_free(data->changed_dns);
170         data->changed_dns = NULL;
171         return ldb_next_end_trans(module);
172 }
173
174 /* end a transaction */
175 static int update_kt_del_trans(struct ldb_module *module)
176 {
177         struct update_kt_private *data = talloc_get_type(module->private_data, struct update_kt_private);
178         
179         talloc_free(data->changed_dns);
180         data->changed_dns = NULL;
181
182         return ldb_next_end_trans(module);
183 }
184
185 static int update_kt_init(struct ldb_module *module)
186 {
187         struct update_kt_private *data;
188
189         data = talloc(module, struct update_kt_private);
190         if (data == NULL) {
191                 ldb_oom(module->ldb);
192                 return LDB_ERR_OPERATIONS_ERROR;
193         }
194
195         module->private_data = data;
196         data->changed_dns = NULL;
197
198         return ldb_next_init(module);
199 }
200
201 static const struct ldb_module_ops update_kt_ops = {
202         .name              = "update_keytab",
203         .init_context      = update_kt_init,
204         .add               = update_kt_add,
205         .modify            = update_kt_modify,
206         .rename            = update_kt_rename,
207         .del               = update_kt_delete,
208         .end_transaction   = update_kt_end_trans,
209         .del_transaction   = update_kt_del_trans,
210 };
211
212 int ldb_update_kt_init(void)
213 {
214         return ldb_register_module(&update_kt_ops);
215 }