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