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