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