s3: avoid global include of ads.h.
[samba.git] / source3 / winbindd / idmap_adex / likewise_cell.c
1 /*
2  * idmap_adex: Support for AD Forests
3  *
4  * Copyright (C) Gerald (Jerry) Carter 2006-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 static struct likewise_cell *_lw_cell_list = NULL;
29
30 /**********************************************************************
31  Return the current HEAD of the list
32  *********************************************************************/
33
34  struct likewise_cell *cell_list_head(void)
35 {
36         return _lw_cell_list;
37 }
38
39
40 /**********************************************************************
41  *********************************************************************/
42
43  void cell_destroy(struct likewise_cell *c)
44 {
45         if (!c)
46                 return;
47
48         if (c->conn)
49                 ads_destroy(&c->conn);
50
51         talloc_destroy(c);
52 }
53
54 /**********************************************************************
55  Free all cell entries and reset the list head to NULL
56  *********************************************************************/
57
58  void cell_list_destroy(void)
59 {
60         struct likewise_cell *p = _lw_cell_list;
61
62         while (p) {
63                 struct likewise_cell *q = p->next;
64
65                 cell_destroy(p);
66
67                 p = q;
68         }
69
70         _lw_cell_list = NULL;
71
72         return;
73 }
74
75 /**********************************************************************
76  Add a new cell structure to the list
77  *********************************************************************/
78
79  struct likewise_cell* cell_new(void)
80 {
81         struct likewise_cell *c;
82
83         /* Each cell struct is a TALLOC_CTX* */
84
85         c = TALLOC_ZERO_P(NULL, struct likewise_cell);
86         if (!c) {
87                 DEBUG(0,("cell_new: memory allocation failure!\n"));
88                 return NULL;
89         }
90
91         return c;
92 }
93
94 /**********************************************************************
95  Add a new cell structure to the list
96  *********************************************************************/
97
98  bool cell_list_add(struct likewise_cell * cell)
99 {
100         if (!cell) {
101                 return false;
102         }
103
104         /* Always add to the end */
105
106         DLIST_ADD_END(_lw_cell_list, cell, struct likewise_cell *);
107
108         return true;
109 }
110
111 /**********************************************************************
112  Add a new cell structure to the list
113  *********************************************************************/
114
115  bool cell_list_remove(struct likewise_cell * cell)
116 {
117         if (!cell) {
118                 return false;
119         }
120
121         /* Remove and drop the cell structure */
122
123         DLIST_REMOVE(_lw_cell_list, cell);
124         talloc_destroy(cell);
125
126         return true;
127 }
128
129 /**********************************************************************
130  Set the containing DNS domain for a cell
131  *********************************************************************/
132
133  void cell_set_dns_domain(struct likewise_cell *c, const char *dns_domain)
134 {
135         c->dns_domain = talloc_strdup(c, dns_domain);
136 }
137
138 /**********************************************************************
139  Set ADS connection for a cell
140  *********************************************************************/
141
142  void cell_set_connection(struct likewise_cell *c, ADS_STRUCT *ads)
143 {
144         c->conn = ads;
145 }
146
147 /**********************************************************************
148  *********************************************************************/
149
150  void cell_set_flags(struct likewise_cell *c, uint32_t flags)
151 {
152         c->flags |= flags;
153 }
154
155 /**********************************************************************
156  *********************************************************************/
157
158  void cell_clear_flags(struct likewise_cell *c, uint32_t flags)
159 {
160         c->flags &= ~flags;
161 }
162
163 /**********************************************************************
164  Set the Cell's DN
165  *********************************************************************/
166
167  void cell_set_dn(struct likewise_cell *c, const char *dn)
168 {
169         if ( c->dn) {
170                 talloc_free(c->dn);
171                 c->dn = NULL;
172         }
173
174         c->dn = talloc_strdup(c, dn);
175 }
176
177 /**********************************************************************
178  *********************************************************************/
179
180  void cell_set_domain_sid(struct likewise_cell *c, struct dom_sid *sid)
181 {
182         sid_copy(&c->domain_sid, sid);
183 }
184
185 /*
186  * Query Routines
187  */
188
189 /**********************************************************************
190  *********************************************************************/
191
192  const char* cell_search_base(struct likewise_cell *c)
193 {
194         if (!c)
195                 return NULL;
196
197         return talloc_asprintf(c, "cn=%s,%s", ADEX_CELL_RDN, c->dn);
198 }
199
200 /**********************************************************************
201  *********************************************************************/
202
203  bool cell_search_forest(struct likewise_cell *c)
204 {
205         uint32_t test_flags = LWCELL_FLAG_SEARCH_FOREST;
206
207         return ((c->flags & test_flags) == test_flags);
208 }
209
210 /**********************************************************************
211  *********************************************************************/
212
213  uint32_t cell_flags(struct likewise_cell *c)
214 {
215         if (!c)
216                 return 0;
217
218         return c->flags;
219 }
220
221 /**********************************************************************
222  *********************************************************************/
223
224  const char *cell_dns_domain(struct likewise_cell *c)
225 {
226         if (!c)
227                 return NULL;
228
229         return c->dns_domain;
230 }
231
232 /**********************************************************************
233  *********************************************************************/
234
235  ADS_STRUCT *cell_connection(struct likewise_cell *c)
236 {
237         if (!c)
238                 return NULL;
239
240         return c->conn;
241 }
242
243 /*
244  * Connection functions
245  */
246
247 /********************************************************************
248  *******************************************************************/
249
250  NTSTATUS cell_connect(struct likewise_cell *c)
251 {
252         ADS_STRUCT *ads = NULL;
253         ADS_STATUS ads_status;
254         fstring dc_name;
255         struct sockaddr_storage dcip;
256         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
257
258         /* have to at least have the AD domain name */
259
260         if (!c->dns_domain) {
261                 nt_status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
262                 BAIL_ON_NTSTATUS_ERROR(nt_status);
263         }
264
265         /* clear out any old information */
266
267         if (c->conn) {
268                 ads_destroy(&c->conn);
269                 c->conn = NULL;
270         }
271
272         /* now setup the new connection */
273
274         ads = ads_init(c->dns_domain, NULL, NULL);
275         BAIL_ON_PTR_ERROR(ads, nt_status);
276
277         ads->auth.password =
278             secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
279         ads->auth.realm = SMB_STRDUP(lp_realm());
280
281         /* Make the connection.  We should already have an initial
282            TGT using the machine creds */
283
284         if (cell_flags(c) & LWCELL_FLAG_GC_CELL) {
285                 ads_status = ads_connect_gc(ads);
286         } else {
287           /* Set up server affinity for normal cells and the client
288              site name cache */
289
290           if (!get_dc_name("", c->dns_domain, dc_name, &dcip)) {
291             nt_status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
292             BAIL_ON_NTSTATUS_ERROR(nt_status);
293           }
294
295           ads_status = ads_connect(ads);
296         }
297
298
299         c->conn = ads;
300
301         nt_status = ads_ntstatus(ads_status);
302
303 done:
304         if (!NT_STATUS_IS_OK(nt_status)) {
305                 ads_destroy(&ads);
306                 c->conn = NULL;
307         }
308
309         return nt_status;
310 }
311
312 /********************************************************************
313  *******************************************************************/
314
315  NTSTATUS cell_connect_dn(struct likewise_cell **c, const char *dn)
316 {
317         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
318         struct likewise_cell *new_cell = NULL;
319         char *dns_domain = NULL;
320
321         if (*c || !dn) {
322                 nt_status = NT_STATUS_INVALID_PARAMETER;
323                 BAIL_ON_NTSTATUS_ERROR(nt_status);
324         }
325
326         if ((new_cell = cell_new()) == NULL) {
327                 nt_status = NT_STATUS_NO_MEMORY;
328                 BAIL_ON_NTSTATUS_ERROR(nt_status);
329         }
330
331         /* Set the DNS domain, dn, etc ... and add it to the list */
332
333         dns_domain = cell_dn_to_dns(dn);
334         cell_set_dns_domain(new_cell, dns_domain);
335         SAFE_FREE(dns_domain);
336
337         cell_set_dn(new_cell, dn);
338
339         nt_status = cell_connect(new_cell);
340         BAIL_ON_NTSTATUS_ERROR(nt_status);
341
342         *c = new_cell;
343
344 done:
345         if (!NT_STATUS_IS_OK(nt_status)) {
346                 DEBUG(1,("LWI: Failled to connect to cell \"%s\" (%s)\n",
347                          dn ? dn : "NULL", nt_errstr(nt_status)));
348                 talloc_destroy(new_cell);
349         }
350
351         return nt_status;
352 }
353
354
355 /********************************************************************
356  *******************************************************************/
357
358 #define MAX_SEARCH_COUNT    2
359
360  ADS_STATUS cell_do_search(struct likewise_cell *c,
361                           const char *search_base,
362                           int scope,
363                           const char *expr,
364                           const char **attrs,
365                           LDAPMessage ** msg)
366 {
367         int search_count = 0;
368         ADS_STATUS status;
369         NTSTATUS nt_status;
370
371         /* check for a NULL connection */
372
373         if (!c->conn) {
374                 nt_status = cell_connect(c);
375                 if (!NT_STATUS_IS_OK(nt_status)) {
376                         status = ADS_ERROR_NT(nt_status);
377                         return status;
378                 }
379         }
380
381         DEBUG(10, ("cell_do_search: Base = %s,  Filter = %s, Scope = %d, GC = %s\n",
382                    search_base, expr, scope,
383                    c->conn->server.gc ? "yes" : "no"));
384
385         /* we try multiple times in case the ADS_STRUCT is bad
386            and we need to reconnect */
387
388         while (search_count < MAX_SEARCH_COUNT) {
389                 *msg = NULL;
390                 status = ads_do_search(c->conn, search_base,
391                                        scope, expr, attrs, msg);
392                 if (ADS_ERR_OK(status)) {
393                         if (DEBUGLEVEL >= 10) {
394                                 LDAPMessage *e = NULL;
395
396                                 int n = ads_count_replies(c->conn, *msg);
397
398                                 DEBUG(10,("cell_do_search: Located %d entries\n", n));
399
400                                 for (e=ads_first_entry(c->conn, *msg);
401                                      e!=NULL;
402                                      e = ads_next_entry(c->conn, e))
403                                 {
404                                         char *dn = ads_get_dn(c->conn, talloc_tos(), e);
405
406                                         DEBUGADD(10,("   dn: %s\n", dn ? dn : "<NULL>"));
407                                         TALLOC_FREE(dn);
408                                 }
409                         }
410
411                         return status;
412                 }
413
414
415                 DEBUG(5, ("cell_do_search: search[%d] failed (%s)\n",
416                           search_count, ads_errstr(status)));
417
418                 search_count++;
419
420                 /* Houston, we have a problem */
421
422                 if (status.error_type == ENUM_ADS_ERROR_LDAP) {
423                         switch (status.err.rc) {
424                         case LDAP_TIMELIMIT_EXCEEDED:
425                         case LDAP_TIMEOUT:
426                         case -1:        /* we get this error if we cannot contact
427                                            the LDAP server */
428                                 nt_status = cell_connect(c);
429                                 if (!NT_STATUS_IS_OK(nt_status)) {
430                                         status = ADS_ERROR_NT(nt_status);
431                                         return status;
432                                 }
433                                 break;
434                         default:
435                                 /* we're all done here */
436                                 return status;
437                         }
438                 }
439         }
440
441         DEBUG(5, ("cell_do_search: exceeded maximum search count!\n"));
442
443         return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
444 }