dsdb: Allow dsdb_find_dn_by_guid to show deleted DNs
[samba.git] / source4 / dsdb / kcc / kcc_connection.c
1 /*
2    Unix SMB/CIFS implementation.
3    KCC service periodic handling
4
5    Copyright (C) Crístian Deives
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20 */
21
22 #include "includes.h"
23 #include "lib/events/events.h"
24 #include "dsdb/samdb/samdb.h"
25 #include "auth/auth.h"
26 #include "smbd/service.h"
27 #include "lib/messaging/irpc.h"
28 #include "dsdb/kcc/kcc_service.h"
29 #include "dsdb/kcc/kcc_connection.h"
30 #include <ldb_errors.h>
31 #include "../lib/util/dlinklist.h"
32 #include "librpc/gen_ndr/ndr_misc.h"
33 #include "librpc/gen_ndr/ndr_drsuapi.h"
34 #include "librpc/gen_ndr/ndr_drsblobs.h"
35 #include "param/param.h"
36
37 static int kccsrv_add_connection(struct kccsrv_service *s,
38                                  struct kcc_connection *conn)
39 {
40         struct ldb_message *msg;
41         TALLOC_CTX *tmp_ctx;
42         struct ldb_dn *new_dn, *server_dn;
43         struct GUID guid;
44         /* struct ldb_val schedule_val; */
45         int ret;
46         bool ok;
47
48         tmp_ctx = talloc_new(s);
49         if (!tmp_ctx) {
50                 DEBUG(0, ("failed to talloc\n"));
51                 ret = LDB_ERR_OPERATIONS_ERROR;
52                 goto done;
53         }
54         new_dn = samdb_ntds_settings_dn(s->samdb, tmp_ctx);
55         if (!new_dn) {
56                 DEBUG(0, ("failed to find NTDS settings\n"));
57                 ret = LDB_ERR_OPERATIONS_ERROR;
58                 goto done;
59         }
60         new_dn = ldb_dn_copy(tmp_ctx, new_dn);
61         if (!new_dn) {
62                 DEBUG(0, ("failed to copy NTDS settings\n"));
63                 ret = LDB_ERR_OPERATIONS_ERROR;
64                 goto done;
65         }
66         guid = GUID_random();
67         ok = ldb_dn_add_child_fmt(new_dn, "CN=%s", GUID_string(tmp_ctx, &guid));
68         if (!ok) {
69                 DEBUG(0, ("failed to create nTDSConnection DN\n"));
70                 ret = LDB_ERR_INVALID_DN_SYNTAX;
71                 goto done;
72         }
73         ret = dsdb_find_dn_by_guid(s->samdb, tmp_ctx, &conn->dsa_guid, 0, &server_dn);
74         if (ret != LDB_SUCCESS) {
75                 DEBUG(0, ("failed to find fromServer DN '%s'\n",
76                           GUID_string(tmp_ctx, &conn->dsa_guid)));
77                 goto done;
78         }
79         /*schedule_val = data_blob_const(r1->schedule, sizeof(r1->schedule));*/
80
81         msg = ldb_msg_new(tmp_ctx);
82         msg->dn = new_dn;
83         ldb_msg_add_string(msg, "objectClass", "nTDSConnection");
84         ldb_msg_add_string(msg, "showInAdvancedViewOnly", "TRUE");
85         ldb_msg_add_string(msg, "enabledConnection", "TRUE");
86         ldb_msg_add_linearized_dn(msg, "fromServer", server_dn);
87         /* ldb_msg_add_value(msg, "schedule", &schedule_val, NULL); */
88
89         samdb_msg_add_uint(s->samdb, msg, msg,
90                                 "options", NTDSCONN_OPT_IS_GENERATED);
91
92         ret = ldb_add(s->samdb, msg);
93         if (ret == LDB_SUCCESS) {
94                 DEBUG(2, ("added nTDSConnection object '%s'\n",
95                           ldb_dn_get_linearized(new_dn)));
96         } else {
97                 DEBUG(0, ("failed to add an nTDSConnection object: %s\n",
98                           ldb_strerror(ret)));
99         }
100
101 done:
102         talloc_free(tmp_ctx);
103         return ret;
104 }
105
106 static int kccsrv_delete_connection(struct kccsrv_service *s,
107                                     struct kcc_connection *conn)
108 {
109         TALLOC_CTX *tmp_ctx;
110         struct ldb_dn *dn;
111         int ret;
112
113         tmp_ctx = talloc_new(s);
114         ret = dsdb_find_dn_by_guid(s->samdb, tmp_ctx, &conn->obj_guid, 0, &dn);
115         if (ret != LDB_SUCCESS) {
116                 DEBUG(0, ("failed to find nTDSConnection's DN: %s\n",
117                           ldb_strerror(ret)));
118                 goto done;
119         }
120
121         ret = ldb_delete(s->samdb, dn);
122         if (ret == LDB_SUCCESS) {
123                 DEBUG(2, ("deleted nTDSConnection object '%s'\n",
124                           ldb_dn_get_linearized(dn)));
125         } else {
126                 DEBUG(0, ("failed to delete an nTDSConnection object: %s\n",
127                           ldb_strerror(ret)));
128         }
129
130 done:
131         talloc_free(tmp_ctx);
132         return ret;
133 }
134
135 void kccsrv_apply_connections(struct kccsrv_service *s,
136                               struct kcc_connection_list *ntds_list,
137                               struct kcc_connection_list *dsa_list)
138 {
139         unsigned int i, j, deleted = 0, added = 0;
140         int ret;
141
142         /* XXX
143          *
144          * This routine is not respecting connections that the
145          * administrator can specifically create (NTDSCONN_OPT_IS_GENERATED
146          * bit will not be set)
147          */
148         for (i = 0; ntds_list && i < ntds_list->count; i++) {
149                 struct kcc_connection *ntds = &ntds_list->servers[i];
150                 for (j = 0; j < dsa_list->count; j++) {
151                         struct kcc_connection *dsa = &dsa_list->servers[j];
152                         if (GUID_equal(&ntds->dsa_guid, &dsa->dsa_guid)) {
153                                 break;
154                         }
155                 }
156                 if (j == dsa_list->count) {
157                         ret = kccsrv_delete_connection(s, ntds);
158                         if (ret == LDB_SUCCESS) {
159                                 deleted++;
160                         }
161                 }
162         }
163         DEBUG(4, ("%d connections have been deleted\n", deleted));
164
165         for (i = 0; i < dsa_list->count; i++) {
166                 struct kcc_connection *dsa = &dsa_list->servers[i];
167                 for (j = 0; ntds_list && j < ntds_list->count; j++) {
168                         struct kcc_connection *ntds = &ntds_list->servers[j];
169                         if (GUID_equal(&dsa->dsa_guid, &ntds->dsa_guid)) {
170                                 break;
171                         }
172                 }
173                 if (ntds_list == NULL || j == ntds_list->count) {
174                         ret = kccsrv_add_connection(s, dsa);
175                         if (ret == LDB_SUCCESS) {
176                                 added++;
177                         }
178                 }
179         }
180         DEBUG(4, ("%d connections have been added\n", added));
181 }
182
183 struct kcc_connection_list *kccsrv_find_connections(struct kccsrv_service *s,
184                                                     TALLOC_CTX *mem_ctx)
185 {
186         unsigned int i;
187         int ret;
188         struct ldb_dn *base_dn;
189         struct ldb_result *res;
190         const char *attrs[] = { "objectGUID", "fromServer", NULL };
191         struct kcc_connection_list *list;
192         TALLOC_CTX *tmp_ctx;
193         kcctpl_test(s);
194
195         tmp_ctx = talloc_new(mem_ctx);
196         if (!tmp_ctx) {
197                 DEBUG(0, ("failed to talloc\n"));
198                 return NULL;
199         }
200
201         base_dn = samdb_ntds_settings_dn(s->samdb, tmp_ctx);
202         if (!base_dn) {
203                 DEBUG(0, ("failed to find our own NTDS settings DN\n"));
204                 talloc_free(tmp_ctx);
205                 return NULL;
206         }
207
208         ret = ldb_search(s->samdb, tmp_ctx, &res, base_dn, LDB_SCOPE_ONELEVEL,
209                          attrs, "objectClass=nTDSConnection");
210         if (ret != LDB_SUCCESS) {
211                 DEBUG(0, ("failed nTDSConnection search: %s\n",
212                           ldb_strerror(ret)));
213                 talloc_free(tmp_ctx);
214                 return NULL;
215         }
216
217         list = talloc(tmp_ctx, struct kcc_connection_list);
218         if (!list) {
219                 DEBUG(0, ("out of memory"));
220                 return NULL;
221         }
222         list->servers = talloc_array(list, struct kcc_connection,
223                                      res->count);
224         if (!list->servers) {
225                 DEBUG(0, ("out of memory"));
226                 talloc_free(tmp_ctx);
227                 return NULL;
228         }
229         list->count = 0;
230
231         for (i = 0; i < res->count; i++) {
232                 struct ldb_dn *server_dn;
233
234                 list->servers[i].obj_guid = samdb_result_guid(res->msgs[i],
235                                                               "objectGUID");
236                 server_dn = samdb_result_dn(s->samdb, mem_ctx, res->msgs[i],
237                                             "fromServer", NULL);
238                 ret = dsdb_find_guid_by_dn(s->samdb, server_dn,
239                                            &list->servers[i].dsa_guid);
240                 if (ret != LDB_SUCCESS) {
241                         DEBUG(0, ("Failed to find connection server's GUID by "
242                                   "DN=%s: %s\n",
243                                   ldb_dn_get_linearized(server_dn),
244                                   ldb_strerror(ret)));
245                         continue;
246                 }
247                 list->count++;
248         }
249         DEBUG(4, ("found %d existing nTDSConnection objects\n", list->count));
250         talloc_steal(mem_ctx, list);
251         talloc_free(tmp_ctx);
252         return list;
253 }