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