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