99dc0cca658affd8e69f2e55148e9c28dd5ebfe5
[nivanova/samba-autobuild/.git] / source3 / winbindd / idmap_adex / domain_util.c
1 /*
2  * idmap_adex: Domain search interface
3  *
4  * Copyright (C) Gerald (Jerry) Carter 2007-2008
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 2 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, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 #include "includes.h"
22 #include "ads.h"
23 #include "idmap.h"
24 #include "idmap_adex.h"
25
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_IDMAP
28
29 struct dc_info {
30         struct dc_info *prev, *next;
31         char *dns_name;
32         struct likewise_cell *domain_cell;
33 };
34
35 static struct dc_info *_dc_server_list = NULL;
36
37
38 /**********************************************************************
39  *********************************************************************/
40
41 static struct dc_info *dc_list_head(void)
42 {
43         return _dc_server_list;
44 }
45
46 /**********************************************************************
47  *********************************************************************/
48
49 static NTSTATUS dc_add_domain(const char *domain)
50 {
51         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
52         struct dc_info *dc = NULL;
53
54         if (!domain) {
55                 return NT_STATUS_INVALID_PARAMETER;
56         }
57
58         DEBUG(10,("dc_add_domain: Attempting to add domain %s\n", domain));
59
60         /* Check for duplicates */
61
62         dc = dc_list_head();
63         while (dc) {
64                 if (strequal (dc->dns_name, domain))
65                         break;
66                 dc = dc->next;
67         }
68
69         if (dc) {
70                 DEBUG(10,("dc_add_domain: %s already in list\n", domain));
71                 return NT_STATUS_OK;
72         }
73
74         dc = talloc_zero(NULL, struct dc_info);
75         BAIL_ON_PTR_ERROR(dc, nt_status);
76
77         dc->dns_name = talloc_strdup(dc, domain);
78         BAIL_ON_PTR_ERROR(dc->dns_name, nt_status);
79
80         DLIST_ADD_END(_dc_server_list, dc, struct dc_info*);
81
82         nt_status = NT_STATUS_OK;
83
84         DEBUG(5,("dc_add_domain: Successfully added %s\n", domain));
85
86 done:
87         if (!NT_STATUS_IS_OK(nt_status)) {
88                 talloc_destroy(dc);
89                 DEBUG(0,("LWI: Failed to add new DC connection for %s (%s)\n",
90                          domain, nt_errstr(nt_status)));
91         }
92
93         return nt_status;
94 }
95
96 /**********************************************************************
97  *********************************************************************/
98
99 static void dc_server_list_destroy(void)
100 {
101         struct dc_info *dc = dc_list_head();
102
103         while (dc) {
104                 struct dc_info *p = dc->next;
105
106                 cell_destroy(dc->domain_cell);
107                 talloc_destroy(dc);
108
109                 dc = p;
110         }
111
112         return;
113 }
114
115
116 /**********************************************************************
117  *********************************************************************/
118
119  NTSTATUS domain_init_list(void)
120 {
121         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
122         struct winbindd_tdc_domain *domains = NULL;
123         size_t num_domains = 0;
124         int i;
125
126         if (_dc_server_list != NULL) {
127                 dc_server_list_destroy();
128         }
129
130         /* Add our domain */
131
132         nt_status = dc_add_domain(lp_realm());
133         BAIL_ON_NTSTATUS_ERROR(nt_status);
134
135         if (!wcache_tdc_fetch_list(&domains, &num_domains)) {
136                 nt_status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
137                 BAIL_ON_NTSTATUS_ERROR(nt_status);
138         }
139
140         /* Add all domains with an incoming trust path */
141
142         for (i=0; i<num_domains; i++) {
143                 uint32_t flags = (NETR_TRUST_FLAG_INBOUND|NETR_TRUST_FLAG_IN_FOREST);
144
145                 /* We just require one of the flags to be set here */
146
147                 if (domains[i].trust_flags & flags) {
148                         nt_status = dc_add_domain(domains[i].dns_name);
149                         BAIL_ON_NTSTATUS_ERROR(nt_status);
150                 }
151         }
152
153         nt_status = NT_STATUS_OK;
154
155 done:
156         if (!NT_STATUS_IS_OK(nt_status)) {
157                 DEBUG(2,("LWI: Failed to initialize DC list (%s)\n",
158                          nt_errstr(nt_status)));
159         }
160
161         TALLOC_FREE(domains);
162
163         return nt_status;
164 }
165
166 /********************************************************************
167  *******************************************************************/
168
169 static NTSTATUS dc_do_search(struct dc_info *dc,
170                              const char *search_base,
171                              int scope,
172                              const char *expr,
173                              const char **attrs,
174                              LDAPMessage ** msg)
175 {
176         ADS_STATUS status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
177         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
178
179         status = cell_do_search(dc->domain_cell, search_base,
180                                 scope, expr, attrs, msg);
181         nt_status = ads_ntstatus(status);
182
183         return nt_status;
184 }
185
186 /**********************************************************************
187  *********************************************************************/
188
189 static struct dc_info *dc_find_domain(const char *dns_domain)
190 {
191         struct dc_info *dc = dc_list_head();
192
193         if (!dc)
194                 return NULL;
195
196         while (dc) {
197                 if (strequal(dc->dns_name, dns_domain)) {
198                         return dc;
199                 }
200
201                 dc = dc->next;
202         }
203
204         return NULL;
205 }
206
207 /**********************************************************************
208  *********************************************************************/
209
210  NTSTATUS dc_search_domains(struct likewise_cell **cell,
211                             LDAPMessage **msg,
212                             const char *dn,
213                             const struct dom_sid *sid)
214 {
215         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
216         TALLOC_CTX *frame = talloc_stackframe();
217         char *dns_domain;
218         const char *attrs[] = { "*", NULL };
219         struct dc_info *dc = NULL;
220         const char *base = NULL;
221
222         if (!dn || !*dn) {
223                 nt_status = NT_STATUS_INVALID_PARAMETER;
224                 BAIL_ON_NTSTATUS_ERROR(nt_status);
225         }
226
227         dns_domain = cell_dn_to_dns(dn);
228         BAIL_ON_PTR_ERROR(dns_domain, nt_status);
229
230         if ((dc = dc_find_domain(dns_domain)) == NULL) {
231                 nt_status = NT_STATUS_TRUSTED_DOMAIN_FAILURE;
232                 BAIL_ON_NTSTATUS_ERROR(nt_status);
233         }
234
235         /* Reparse the cell settings for the domain if necessary */
236
237         if (!dc->domain_cell) {
238                 char *base_dn;
239
240                 base_dn = ads_build_dn(dc->dns_name);
241                 BAIL_ON_PTR_ERROR(base_dn, nt_status);
242
243                 nt_status = cell_connect_dn(&dc->domain_cell, base_dn);
244                 SAFE_FREE(base_dn);
245                 BAIL_ON_NTSTATUS_ERROR(nt_status);
246
247                 nt_status = cell_lookup_settings(dc->domain_cell);
248                 BAIL_ON_NTSTATUS_ERROR(nt_status);
249
250                 /* By definition this is already part of a larger
251                    forest-wide search scope */
252
253                 cell_set_flags(dc->domain_cell, LWCELL_FLAG_SEARCH_FOREST);
254         }
255
256         /* Check whether we are operating in non-schema or RFC2307
257            mode */
258
259         if (cell_flags(dc->domain_cell) & LWCELL_FLAG_USE_RFC2307_ATTRS) {
260                 nt_status = dc_do_search(dc, dn, LDAP_SCOPE_BASE,
261                                          "(objectclass=*)", attrs, msg);
262         } else {
263                 const char *sid_str = NULL;
264                 char *filter = NULL;
265
266                 sid_str = sid_string_talloc(frame, sid);
267                 BAIL_ON_PTR_ERROR(sid_str, nt_status);
268
269                 filter = talloc_asprintf(frame, "(keywords=backLink=%s)",
270                                          sid_str);
271                 BAIL_ON_PTR_ERROR(filter, nt_status);
272
273                 base = cell_search_base(dc->domain_cell);
274                 BAIL_ON_PTR_ERROR(base, nt_status);
275
276                 nt_status = dc_do_search(dc, base, LDAP_SCOPE_SUBTREE,
277                                          filter, attrs, msg);
278         }
279         BAIL_ON_NTSTATUS_ERROR(nt_status);
280
281         *cell = dc->domain_cell;
282
283 done:
284         talloc_destroy(discard_const_p(char, base));
285         talloc_destroy(frame);
286
287         return nt_status;
288 }