s3: avoid global include of ads.h.
[samba.git] / source3 / winbindd / idmap_adex / idmap_adex.c
1 /*
2  * idmap_adex: Support for D 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 #include "nss_info.h"
25
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_IDMAP
28
29 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
30
31 NTSTATUS init_module(void);
32
33 /*
34  * IdMap backend
35  */
36
37 /********************************************************************
38  Basic init function responsible for determining our current mode
39  (standalone or using Centeris Cells).  This must return success or
40  it will be dropped from the idmap backend list.
41  *******************************************************************/
42
43 static NTSTATUS _idmap_adex_init(struct idmap_domain *dom,
44                                      const char *params)
45 {
46         ADS_STRUCT *ads = NULL;
47         ADS_STATUS status;
48         static NTSTATUS init_status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
49         struct dom_sid domain_sid;
50         fstring dcname;
51         struct sockaddr_storage ip;
52         struct likewise_cell *lwcell;
53
54         if (NT_STATUS_IS_OK(init_status))
55                 return NT_STATUS_OK;
56
57         /* Silently fail if we are not a member server in security = ads */
58
59         if ((lp_server_role() != ROLE_DOMAIN_MEMBER) ||
60             (lp_security() != SEC_ADS)) {
61                 init_status = NT_STATUS_INVALID_SERVER_STATE;
62                 BAIL_ON_NTSTATUS_ERROR(init_status);
63         }
64
65         /* fetch our domain SID first */
66
67         if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
68                 init_status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
69                 BAIL_ON_NTSTATUS_ERROR(init_status);
70         }
71
72         /* reuse the same ticket cache as winbindd */
73
74         setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
75
76         /* Establish a connection to a DC */
77
78         if ((ads = ads_init(lp_realm(), lp_workgroup(), NULL)) == NULL) {
79                 init_status = NT_STATUS_NO_MEMORY;
80                 BAIL_ON_NTSTATUS_ERROR(init_status);
81         }
82
83         ads->auth.password =
84             secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
85         ads->auth.realm = SMB_STRDUP(lp_realm());
86
87         /* get the DC name here to setup the server affinity cache and
88            local krb5.conf */
89
90         get_dc_name(lp_workgroup(), lp_realm(), dcname, &ip);
91
92         status = ads_connect(ads);
93         if (!ADS_ERR_OK(status)) {
94                 DEBUG(0, ("_idmap_adex_init: ads_connect() failed! (%s)\n",
95                           ads_errstr(status)));
96         }
97         init_status = ads_ntstatus(status);
98         BAIL_ON_NTSTATUS_ERROR(init_status);
99
100
101         /* Find out cell membership */
102
103         init_status = cell_locate_membership(ads);
104         if (!NT_STATUS_IS_OK(init_status)) {
105                 DEBUG(0,("LWI: Fail to locate cell membership (%s).",
106                          nt_errstr(init_status)));
107                 goto done;
108         }
109
110         /* Fill in the cell information */
111
112         lwcell = cell_list_head();
113
114         init_status = cell_lookup_settings(lwcell);
115         BAIL_ON_NTSTATUS_ERROR(init_status);
116
117         /* Miscellaneous setup.  E.g. set up the list of GC
118            servers and domain list for our forest (does not actually
119            connect). */
120
121         init_status = gc_init_list();
122         BAIL_ON_NTSTATUS_ERROR(init_status);
123
124         init_status = domain_init_list();
125         BAIL_ON_NTSTATUS_ERROR(init_status);
126
127 done:
128         if (!NT_STATUS_IS_OK(init_status)) {
129                 DEBUG(1,("Likewise initialization failed (%s)\n",
130                          nt_errstr(init_status)));
131         }
132
133         /* cleanup */
134
135         if (!NT_STATUS_IS_OK(init_status)) {
136                 cell_list_destroy();
137
138                 /* init_status stores the failure reason but we need to
139                    return success or else idmap_init() will drop us from the
140                    backend list */
141                 return NT_STATUS_OK;
142         }
143
144         init_status = NT_STATUS_OK;
145
146         return init_status;
147 }
148
149 /**********************************************************************
150  *********************************************************************/
151
152 static NTSTATUS _idmap_adex_get_sid_from_id(struct
153                                                 idmap_domain
154                                                 *dom, struct
155                                                 id_map
156                                                 **ids)
157 {
158         int i;
159         bool one_mapped = false;
160         bool all_mapped = true;
161         NTSTATUS nt_status;
162         struct likewise_cell *cell;
163
164         /* initialize the status to avoid suprise */
165         for (i = 0; ids[i]; i++) {
166                 ids[i]->status = ID_UNKNOWN;
167         }
168         
169         nt_status = _idmap_adex_init(dom, NULL);
170         if (!NT_STATUS_IS_OK(nt_status))
171                 return nt_status;
172
173         if ((cell = cell_list_head()) == NULL) {
174                 return NT_STATUS_INVALID_SERVER_STATE;
175         }
176
177         /* have to work through these one by one */
178         for (i = 0; ids[i]; i++) {
179                 NTSTATUS status;
180                 status = cell->provider->get_sid_from_id(ids[i]->sid,
181                                                          ids[i]->xid.id,
182                                                          ids[i]->xid.type);
183                 /* Fail if we cannot find any DC */
184                 if (NT_STATUS_EQUAL
185                     (status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
186                         return status;
187                 }
188
189                 if (!NT_STATUS_IS_OK(status)) {
190                         ids[i]->status = ID_UNMAPPED;
191                         all_mapped = false;
192                         continue;
193                 }
194
195                 ids[i]->status = ID_MAPPED;
196                 one_mapped = true;
197         }
198
199         return NT_STATUS_OK;
200 }
201
202 /**********************************************************************
203  *********************************************************************/
204
205 static NTSTATUS _idmap_adex_get_id_from_sid(struct
206                                                 idmap_domain
207                                                 *dom, struct
208                                                 id_map
209                                                 **ids)
210 {
211         int i;
212         bool one_mapped = false;
213         bool all_mapped = true;
214         NTSTATUS nt_status;
215         struct likewise_cell *cell;
216
217         /* initialize the status to avoid suprise */
218         for (i = 0; ids[i]; i++) {
219                 ids[i]->status = ID_UNKNOWN;
220         }
221         
222         nt_status = _idmap_adex_init(dom, NULL);
223         if (!NT_STATUS_IS_OK(nt_status))
224                 return nt_status;
225
226         if ((cell = cell_list_head()) == NULL) {
227                 return NT_STATUS_INVALID_SERVER_STATE;
228         }
229
230         /* have to work through these one by one */
231         for (i = 0; ids[i]; i++) {
232                 NTSTATUS status;
233                 status = cell->provider->get_id_from_sid(&ids[i]->xid.id,
234                                                          &ids[i]->xid.
235                                                          type, ids[i]->sid);
236                 /* Fail if we cannot find any DC */
237                 if (NT_STATUS_EQUAL
238                     (status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
239                         return status;
240                 }
241
242                 if (!NT_STATUS_IS_OK(status)) {
243                         ids[i]->status = ID_UNMAPPED;
244                         all_mapped = false;
245                         continue;
246                 }
247
248                 ids[i]->status = ID_MAPPED;
249                 one_mapped = true;
250         }
251
252         return NT_STATUS_OK;
253 }
254
255 /**********************************************************************
256  *********************************************************************/
257
258 static NTSTATUS _idmap_adex_set_mapping(struct
259                                             idmap_domain
260                                             *dom, const struct
261                                             id_map *map)
262 {
263         DEBUG(0, ("_idmap_adex_set_mapping: not implemented\n"));
264         return NT_STATUS_NOT_IMPLEMENTED;
265 }
266
267 /**********************************************************************
268  *********************************************************************/
269
270 static NTSTATUS _idmap_adex_remove_mapping(struct
271                                                idmap_domain
272                                                *dom, const
273                                                struct
274                                                id_map
275                                                *map)
276 {
277         DEBUG(0, ("_idmap_adex_remove_mapping: not implemented\n"));
278         return NT_STATUS_NOT_IMPLEMENTED;
279 }
280
281 /**********************************************************************
282  *********************************************************************/
283
284 static NTSTATUS _idmap_adex_dump(struct idmap_domain
285                                      *dom, struct id_map **maps, int *num_map)
286 {
287         return NT_STATUS_NOT_IMPLEMENTED;
288 }
289
290 /**********************************************************************
291  *********************************************************************/
292
293 static NTSTATUS _idmap_adex_close(struct idmap_domain
294                                       *dom)
295 {
296         /* FIXME!  need to do cleanup here */
297
298         return NT_STATUS_OK;
299 }
300
301 /*
302  * IdMap NSS plugin
303  */
304
305 /**********************************************************************
306  *********************************************************************/
307
308 static NTSTATUS _nss_adex_init(struct nss_domain_entry
309                                   *e)
310 {
311         return _idmap_adex_init(NULL, NULL);
312 }
313
314 /**********************************************************************
315  *********************************************************************/
316
317 static NTSTATUS _nss_adex_get_info(struct
318                                       nss_domain_entry *e,
319                                       const struct dom_sid * sid,
320                                       TALLOC_CTX * ctx,
321                                       ADS_STRUCT * ads,
322                                       LDAPMessage * msg,
323                                       const char **homedir,
324                                       const char **shell,
325                                       const char **gecos, gid_t * p_gid)
326 {
327         NTSTATUS nt_status;
328         struct likewise_cell *cell;
329
330         nt_status = _idmap_adex_init(NULL, NULL);
331         if (!NT_STATUS_IS_OK(nt_status))
332                 return nt_status;
333
334         if ((cell = cell_list_head()) == NULL) {
335                 return NT_STATUS_INVALID_SERVER_STATE;
336         }
337
338         return cell->provider->get_nss_info(sid, ctx, homedir,
339                                             shell, gecos, p_gid);
340 }
341
342 /**********************************************************************
343  *********************************************************************/
344
345 static NTSTATUS _nss_adex_map_to_alias(TALLOC_CTX * mem_ctx,
346                                        struct nss_domain_entry *e,
347                                        const char *name, char **alias)
348 {
349         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
350         struct likewise_cell *cell = NULL;
351
352         nt_status = _idmap_adex_init(NULL, NULL);
353         BAIL_ON_NTSTATUS_ERROR(nt_status);
354
355         if ((cell = cell_list_head()) == NULL) {
356                 nt_status = NT_STATUS_INVALID_SERVER_STATE;
357                 BAIL_ON_NTSTATUS_ERROR(nt_status);
358         }
359
360         nt_status = cell->provider->map_to_alias(mem_ctx, e->domain,
361                                                  name, alias);
362
363         /* go ahead and allow the cache mgr to mark this in
364            negative cache */
365
366         if (!NT_STATUS_IS_OK(nt_status))
367                 nt_status = NT_STATUS_NONE_MAPPED;
368
369 done:
370         return nt_status;
371 }
372
373 /**********************************************************************
374  *********************************************************************/
375
376 static NTSTATUS _nss_adex_map_from_alias(TALLOC_CTX * mem_ctx,
377                                          struct nss_domain_entry *e,
378                                          const char *alias, char **name)
379 {
380         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
381         struct likewise_cell *cell = NULL;
382
383         nt_status = _idmap_adex_init(NULL, NULL);
384         BAIL_ON_NTSTATUS_ERROR(nt_status);
385
386         if ((cell = cell_list_head()) == NULL) {
387                 nt_status = NT_STATUS_INVALID_SERVER_STATE;
388                 BAIL_ON_NTSTATUS_ERROR(nt_status);
389         }
390
391
392         nt_status = cell->provider->map_from_alias(mem_ctx, e->domain,
393                                                    alias, name);
394
395         /* go ahead and allow the cache mgr to mark this in
396            negative cache */
397
398         if (!NT_STATUS_IS_OK(nt_status))
399                 nt_status = NT_STATUS_NONE_MAPPED;
400
401 done:
402         return nt_status;
403 }
404
405 /**********************************************************************
406  *********************************************************************/
407
408 static NTSTATUS _nss_adex_close(void)
409 {
410         return NT_STATUS_NOT_IMPLEMENTED;
411 }
412
413 /**********************************************************************
414  *********************************************************************/
415
416 static struct idmap_methods adex_idmap_methods = {
417
418         .init             = _idmap_adex_init,
419         .unixids_to_sids  = _idmap_adex_get_sid_from_id,
420         .sids_to_unixids  = _idmap_adex_get_id_from_sid,
421         .set_mapping      = _idmap_adex_set_mapping,
422         .remove_mapping   = _idmap_adex_remove_mapping,
423         .dump_data        = _idmap_adex_dump,
424         .close_fn         = _idmap_adex_close
425 };
426 static struct nss_info_methods adex_nss_methods = {
427         .init           = _nss_adex_init,
428         .get_nss_info   = _nss_adex_get_info,
429         .map_to_alias   = _nss_adex_map_to_alias,
430         .map_from_alias = _nss_adex_map_from_alias,
431         .close_fn       = _nss_adex_close
432 };
433
434 /**********************************************************************
435  Register with the idmap and idmap_nss subsystems. We have to protect
436  against the idmap and nss_info interfaces being in a half-registered
437  state.
438  **********************************************************************/
439 NTSTATUS idmap_adex_init(void)
440 {
441         static NTSTATUS idmap_status = NT_STATUS_UNSUCCESSFUL;
442         static NTSTATUS nss_status = NT_STATUS_UNSUCCESSFUL;
443         if (!NT_STATUS_IS_OK(idmap_status)) {
444                 idmap_status =
445                     smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION,
446                                        "adex", &adex_idmap_methods);
447                 if (!NT_STATUS_IS_OK(idmap_status)) {
448                         DEBUG(0,
449                               ("idmap_centeris_init: Failed to register the adex"
450                                "idmap plugin.\n"));
451                         return idmap_status;
452                 }
453         }
454
455         if (!NT_STATUS_IS_OK(nss_status)) {
456                 nss_status =
457                     smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
458                                            "adex", &adex_nss_methods);
459                 if (!NT_STATUS_IS_OK(nss_status)) {
460                         DEBUG(0,
461                               ("idmap_adex_init: Failed to register the adex"
462                                "nss plugin.\n"));
463                         return nss_status;
464                 }
465         }
466
467         return NT_STATUS_OK;
468 }
469
470 static NTSTATUS nss_info_adex_init(void)
471 {
472         return idmap_adex_init();
473 }