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