s3-winbindd: Use common helper function for connecting to ADS
[Samba/gebeck_regimport.git] / source3 / winbindd / idmap_ad.c
blob5b9c3774f66474c4cb60deeaa67a5c0b09421780
1 /*
2 * idmap_ad: map between Active Directory and RFC 2307 or "Services for Unix" (SFU) Accounts
4 * Unix SMB/CIFS implementation.
6 * Winbind ADS backend functions
8 * Copyright (C) Andrew Tridgell 2001
9 * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
10 * Copyright (C) Gerald (Jerry) Carter 2004-2007
11 * Copyright (C) Luke Howard 2001-2004
12 * Copyright (C) Michael Adam 2008,2010
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see <http://www.gnu.org/licenses/>.
28 #include "includes.h"
29 #include "winbindd.h"
30 #include "../libds/common/flags.h"
31 #include "ads.h"
32 #include "libads/ldap_schema.h"
33 #include "nss_info.h"
34 #include "secrets.h"
35 #include "idmap.h"
36 #include "../libcli/ldap/ldap_ndr.h"
37 #include "../libcli/security/security.h"
39 #undef DBGC_CLASS
40 #define DBGC_CLASS DBGC_IDMAP
42 #define CHECK_ALLOC_DONE(mem) do { \
43 if (!mem) { \
44 DEBUG(0, ("Out of memory!\n")); \
45 ret = NT_STATUS_NO_MEMORY; \
46 goto done; \
47 } \
48 } while (0)
50 struct idmap_ad_context {
51 ADS_STRUCT *ads;
52 struct posix_schema *ad_schema;
53 enum wb_posix_mapping ad_map_type; /* WB_POSIX_MAP_UNKNOWN */
56 /************************************************************************
57 ***********************************************************************/
59 static ADS_STATUS ad_idmap_cached_connection_internal(struct idmap_domain *dom)
61 struct idmap_ad_context *ctx;
62 char *ldap_server, *realm, *password;
63 struct winbindd_domain *wb_dom;
65 DEBUG(10, ("ad_idmap_cached_connection: called for domain '%s'\n",
66 dom->name));
68 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
70 ads_cached_connection_reuse(&ctx->ads);
71 if (ctx->ads != NULL) {
72 return ADS_SUCCESS;
76 * At this point we only have the NetBIOS domain name.
77 * Check if we can get server nam and realm from SAF cache
78 * and the domain list.
80 ldap_server = saf_fetch(dom->name);
81 DEBUG(10, ("ldap_server from saf cache: '%s'\n", ldap_server?ldap_server:""));
83 wb_dom = find_domain_from_name_noinit(dom->name);
84 if (wb_dom == NULL) {
85 DEBUG(10, ("find_domain_from_name_noinit did not find domain '%s'\n",
86 dom->name));
87 realm = NULL;
88 } else {
89 DEBUG(10, ("find_domain_from_name_noinit found realm '%s' for "
90 " domain '%s'\n", wb_dom->alt_name, dom->name));
91 realm = wb_dom->alt_name;
94 /* the machine acct password might have change - fetch it every time */
95 password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
96 realm = SMB_STRDUP(lp_realm());
98 return ads_cached_connection_connect(&ctx->ads, realm, dom->name,
99 ldap_server, password, realm, 0);
102 /************************************************************************
103 ***********************************************************************/
105 static ADS_STATUS ad_idmap_cached_connection(struct idmap_domain *dom)
107 ADS_STATUS status;
108 struct idmap_ad_context * ctx;
110 status = ad_idmap_cached_connection_internal(dom);
111 if (!ADS_ERR_OK(status)) {
112 return status;
115 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
117 /* if we have a valid ADS_STRUCT and the schema model is
118 defined, then we can return here. */
120 if ( ctx->ad_schema ) {
121 return ADS_SUCCESS;
124 /* Otherwise, set the schema model */
126 if ( (ctx->ad_map_type == WB_POSIX_MAP_SFU) ||
127 (ctx->ad_map_type == WB_POSIX_MAP_SFU20) ||
128 (ctx->ad_map_type == WB_POSIX_MAP_RFC2307) )
130 status = ads_check_posix_schema_mapping(
131 ctx, ctx->ads, ctx->ad_map_type, &ctx->ad_schema);
132 if ( !ADS_ERR_OK(status) ) {
133 DEBUG(2,("ad_idmap_cached_connection: Failed to obtain schema details!\n"));
137 return status;
140 static int idmap_ad_context_destructor(struct idmap_ad_context *ctx)
142 if (ctx->ads != NULL) {
143 /* we own this ADS_STRUCT so make sure it goes away */
144 ctx->ads->is_mine = True;
145 ads_destroy( &ctx->ads );
146 ctx->ads = NULL;
148 return 0;
151 /************************************************************************
152 ***********************************************************************/
154 static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom)
156 struct idmap_ad_context *ctx;
157 char *config_option;
158 const char *schema_mode = NULL;
160 ctx = talloc_zero(dom, struct idmap_ad_context);
161 if (ctx == NULL) {
162 DEBUG(0, ("Out of memory!\n"));
163 return NT_STATUS_NO_MEMORY;
165 talloc_set_destructor(ctx, idmap_ad_context_destructor);
167 config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
168 if (config_option == NULL) {
169 DEBUG(0, ("Out of memory!\n"));
170 talloc_free(ctx);
171 return NT_STATUS_NO_MEMORY;
174 /* default map type */
175 ctx->ad_map_type = WB_POSIX_MAP_RFC2307;
177 /* schema mode */
178 schema_mode = lp_parm_const_string(-1, config_option, "schema_mode", NULL);
179 if ( schema_mode && schema_mode[0] ) {
180 if ( strequal(schema_mode, "sfu") )
181 ctx->ad_map_type = WB_POSIX_MAP_SFU;
182 else if ( strequal(schema_mode, "sfu20" ) )
183 ctx->ad_map_type = WB_POSIX_MAP_SFU20;
184 else if ( strequal(schema_mode, "rfc2307" ) )
185 ctx->ad_map_type = WB_POSIX_MAP_RFC2307;
186 else
187 DEBUG(0,("idmap_ad_initialize: Unknown schema_mode (%s)\n",
188 schema_mode));
191 dom->private_data = ctx;
193 talloc_free(config_option);
195 return NT_STATUS_OK;
198 /************************************************************************
199 ***********************************************************************/
201 static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
203 NTSTATUS ret;
204 TALLOC_CTX *memctx;
205 struct idmap_ad_context *ctx;
206 ADS_STATUS rc;
207 const char *attrs[] = { "sAMAccountType",
208 "objectSid",
209 NULL, /* uidnumber */
210 NULL, /* gidnumber */
211 NULL };
212 LDAPMessage *res = NULL;
213 LDAPMessage *entry = NULL;
214 char *filter = NULL;
215 int idx = 0;
216 int bidx = 0;
217 int count;
218 int i;
219 char *u_filter = NULL;
220 char *g_filter = NULL;
222 /* initialize the status to avoid suprise */
223 for (i = 0; ids[i]; i++) {
224 ids[i]->status = ID_UNKNOWN;
227 /* Only do query if we are online */
228 if (idmap_is_offline()) {
229 return NT_STATUS_FILE_IS_OFFLINE;
232 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
234 if ( (memctx = talloc_new(ctx)) == NULL ) {
235 DEBUG(0, ("Out of memory!\n"));
236 return NT_STATUS_NO_MEMORY;
239 rc = ad_idmap_cached_connection(dom);
240 if (!ADS_ERR_OK(rc)) {
241 DEBUG(1, ("ADS uninitialized: %s\n", ads_errstr(rc)));
242 ret = NT_STATUS_UNSUCCESSFUL;
243 /* ret = ads_ntstatus(rc); */
244 goto done;
247 attrs[2] = ctx->ad_schema->posix_uidnumber_attr;
248 attrs[3] = ctx->ad_schema->posix_gidnumber_attr;
250 again:
251 bidx = idx;
252 for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) {
253 switch (ids[idx]->xid.type) {
254 case ID_TYPE_UID:
255 if ( ! u_filter) {
256 u_filter = talloc_asprintf(memctx, "(&(|"
257 "(sAMAccountType=%d)"
258 "(sAMAccountType=%d)"
259 "(sAMAccountType=%d))(|",
260 ATYPE_NORMAL_ACCOUNT,
261 ATYPE_WORKSTATION_TRUST,
262 ATYPE_INTERDOMAIN_TRUST);
264 u_filter = talloc_asprintf_append_buffer(u_filter, "(%s=%lu)",
265 ctx->ad_schema->posix_uidnumber_attr,
266 (unsigned long)ids[idx]->xid.id);
267 CHECK_ALLOC_DONE(u_filter);
268 break;
270 case ID_TYPE_GID:
271 if ( ! g_filter) {
272 g_filter = talloc_asprintf(memctx, "(&(|"
273 "(sAMAccountType=%d)"
274 "(sAMAccountType=%d))(|",
275 ATYPE_SECURITY_GLOBAL_GROUP,
276 ATYPE_SECURITY_LOCAL_GROUP);
278 g_filter = talloc_asprintf_append_buffer(g_filter, "(%s=%lu)",
279 ctx->ad_schema->posix_gidnumber_attr,
280 (unsigned long)ids[idx]->xid.id);
281 CHECK_ALLOC_DONE(g_filter);
282 break;
284 default:
285 DEBUG(3, ("Error: mapping requested but Unknown ID type\n"));
286 ids[idx]->status = ID_UNKNOWN;
287 continue;
290 filter = talloc_asprintf(memctx, "(|");
291 CHECK_ALLOC_DONE(filter);
292 if ( u_filter) {
293 filter = talloc_asprintf_append_buffer(filter, "%s))", u_filter);
294 CHECK_ALLOC_DONE(filter);
295 TALLOC_FREE(u_filter);
297 if ( g_filter) {
298 filter = talloc_asprintf_append_buffer(filter, "%s))", g_filter);
299 CHECK_ALLOC_DONE(filter);
300 TALLOC_FREE(g_filter);
302 filter = talloc_asprintf_append_buffer(filter, ")");
303 CHECK_ALLOC_DONE(filter);
305 rc = ads_search_retry(ctx->ads, &res, filter, attrs);
306 if (!ADS_ERR_OK(rc)) {
307 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
308 ret = NT_STATUS_UNSUCCESSFUL;
309 goto done;
312 if ( (count = ads_count_replies(ctx->ads, res)) == 0 ) {
313 DEBUG(10, ("No IDs found\n"));
316 entry = res;
317 for (i = 0; (i < count) && entry; i++) {
318 struct dom_sid sid;
319 enum id_type type;
320 struct id_map *map;
321 uint32_t id;
322 uint32_t atype;
324 if (i == 0) { /* first entry */
325 entry = ads_first_entry(ctx->ads, entry);
326 } else { /* following ones */
327 entry = ads_next_entry(ctx->ads, entry);
330 if ( !entry ) {
331 DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
332 break;
335 /* first check if the SID is present */
336 if (!ads_pull_sid(ctx->ads, entry, "objectSid", &sid)) {
337 DEBUG(2, ("Could not retrieve SID from entry\n"));
338 continue;
341 /* get type */
342 if (!ads_pull_uint32(ctx->ads, entry, "sAMAccountType", &atype)) {
343 DEBUG(1, ("could not get SAM account type\n"));
344 continue;
347 switch (atype & 0xF0000000) {
348 case ATYPE_SECURITY_GLOBAL_GROUP:
349 case ATYPE_SECURITY_LOCAL_GROUP:
350 type = ID_TYPE_GID;
351 break;
352 case ATYPE_NORMAL_ACCOUNT:
353 case ATYPE_WORKSTATION_TRUST:
354 case ATYPE_INTERDOMAIN_TRUST:
355 type = ID_TYPE_UID;
356 break;
357 default:
358 DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
359 continue;
362 if (!ads_pull_uint32(ctx->ads, entry, (type==ID_TYPE_UID) ?
363 ctx->ad_schema->posix_uidnumber_attr :
364 ctx->ad_schema->posix_gidnumber_attr,
365 &id))
367 DEBUG(1, ("Could not get unix ID\n"));
368 continue;
371 if (!idmap_unix_id_is_in_range(id, dom)) {
372 DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
373 id, dom->low_id, dom->high_id));
374 continue;
377 map = idmap_find_map_by_id(&ids[bidx], type, id);
378 if (!map) {
379 DEBUG(2, ("WARNING: couldn't match result with requested ID\n"));
380 continue;
383 sid_copy(map->sid, &sid);
385 /* mapped */
386 map->status = ID_MAPPED;
388 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
389 (unsigned long)map->xid.id,
390 map->xid.type));
393 if (res) {
394 ads_msgfree(ctx->ads, res);
397 if (ids[idx]) { /* still some values to map */
398 goto again;
401 ret = NT_STATUS_OK;
403 /* mark all unknown/expired ones as unmapped */
404 for (i = 0; ids[i]; i++) {
405 if (ids[i]->status != ID_MAPPED)
406 ids[i]->status = ID_UNMAPPED;
409 done:
410 talloc_free(memctx);
411 return ret;
414 /************************************************************************
415 ***********************************************************************/
417 static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
419 NTSTATUS ret;
420 TALLOC_CTX *memctx;
421 struct idmap_ad_context *ctx;
422 ADS_STATUS rc;
423 const char *attrs[] = { "sAMAccountType",
424 "objectSid",
425 NULL, /* attr_uidnumber */
426 NULL, /* attr_gidnumber */
427 NULL };
428 LDAPMessage *res = NULL;
429 LDAPMessage *entry = NULL;
430 char *filter = NULL;
431 int idx = 0;
432 int bidx = 0;
433 int count;
434 int i;
435 char *sidstr;
437 /* initialize the status to avoid suprise */
438 for (i = 0; ids[i]; i++) {
439 ids[i]->status = ID_UNKNOWN;
442 /* Only do query if we are online */
443 if (idmap_is_offline()) {
444 return NT_STATUS_FILE_IS_OFFLINE;
447 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
449 if ( (memctx = talloc_new(ctx)) == NULL ) {
450 DEBUG(0, ("Out of memory!\n"));
451 return NT_STATUS_NO_MEMORY;
454 rc = ad_idmap_cached_connection(dom);
455 if (!ADS_ERR_OK(rc)) {
456 DEBUG(1, ("ADS uninitialized: %s\n", ads_errstr(rc)));
457 ret = NT_STATUS_UNSUCCESSFUL;
458 /* ret = ads_ntstatus(rc); */
459 goto done;
462 if (ctx->ad_schema == NULL) {
463 DEBUG(0, ("haven't got ctx->ad_schema ! \n"));
464 ret = NT_STATUS_UNSUCCESSFUL;
465 goto done;
468 attrs[2] = ctx->ad_schema->posix_uidnumber_attr;
469 attrs[3] = ctx->ad_schema->posix_gidnumber_attr;
471 again:
472 filter = talloc_asprintf(memctx, "(&(|"
473 "(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
474 "(sAMAccountType=%d)(sAMAccountType=%d)" /* group account types */
475 ")(|",
476 ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
477 ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
479 CHECK_ALLOC_DONE(filter);
481 bidx = idx;
482 for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) {
484 ids[idx]->status = ID_UNKNOWN;
486 sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), ids[idx]->sid);
487 filter = talloc_asprintf_append_buffer(filter, "(objectSid=%s)", sidstr);
489 TALLOC_FREE(sidstr);
490 CHECK_ALLOC_DONE(filter);
492 filter = talloc_asprintf_append_buffer(filter, "))");
493 CHECK_ALLOC_DONE(filter);
494 DEBUG(10, ("Filter: [%s]\n", filter));
496 rc = ads_search_retry(ctx->ads, &res, filter, attrs);
497 if (!ADS_ERR_OK(rc)) {
498 DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
499 ret = NT_STATUS_UNSUCCESSFUL;
500 goto done;
503 if ( (count = ads_count_replies(ctx->ads, res)) == 0 ) {
504 DEBUG(10, ("No IDs found\n"));
507 entry = res;
508 for (i = 0; (i < count) && entry; i++) {
509 struct dom_sid sid;
510 enum id_type type;
511 struct id_map *map;
512 uint32_t id;
513 uint32_t atype;
515 if (i == 0) { /* first entry */
516 entry = ads_first_entry(ctx->ads, entry);
517 } else { /* following ones */
518 entry = ads_next_entry(ctx->ads, entry);
521 if ( !entry ) {
522 DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
523 break;
526 /* first check if the SID is present */
527 if (!ads_pull_sid(ctx->ads, entry, "objectSid", &sid)) {
528 DEBUG(2, ("Could not retrieve SID from entry\n"));
529 continue;
532 map = idmap_find_map_by_sid(&ids[bidx], &sid);
533 if (!map) {
534 DEBUG(2, ("WARNING: couldn't match result with requested SID\n"));
535 continue;
538 /* get type */
539 if (!ads_pull_uint32(ctx->ads, entry, "sAMAccountType", &atype)) {
540 DEBUG(1, ("could not get SAM account type\n"));
541 continue;
544 switch (atype & 0xF0000000) {
545 case ATYPE_SECURITY_GLOBAL_GROUP:
546 case ATYPE_SECURITY_LOCAL_GROUP:
547 type = ID_TYPE_GID;
548 break;
549 case ATYPE_NORMAL_ACCOUNT:
550 case ATYPE_WORKSTATION_TRUST:
551 case ATYPE_INTERDOMAIN_TRUST:
552 type = ID_TYPE_UID;
553 break;
554 default:
555 DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
556 continue;
559 if (!ads_pull_uint32(ctx->ads, entry, (type==ID_TYPE_UID) ?
560 ctx->ad_schema->posix_uidnumber_attr :
561 ctx->ad_schema->posix_gidnumber_attr,
562 &id))
564 DEBUG(1, ("Could not get unix ID\n"));
565 continue;
567 if (!idmap_unix_id_is_in_range(id, dom)) {
568 DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
569 id, dom->low_id, dom->high_id));
570 continue;
573 /* mapped */
574 map->xid.type = type;
575 map->xid.id = id;
576 map->status = ID_MAPPED;
578 DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
579 (unsigned long)map->xid.id,
580 map->xid.type));
583 if (res) {
584 ads_msgfree(ctx->ads, res);
587 if (ids[idx]) { /* still some values to map */
588 goto again;
591 ret = NT_STATUS_OK;
593 /* mark all unknown/expired ones as unmapped */
594 for (i = 0; ids[i]; i++) {
595 if (ids[i]->status != ID_MAPPED)
596 ids[i]->status = ID_UNMAPPED;
599 done:
600 talloc_free(memctx);
601 return ret;
605 * nss_info_{sfu,sfu20,rfc2307}
608 /************************************************************************
609 Initialize the {sfu,sfu20,rfc2307} state
610 ***********************************************************************/
612 static const char *wb_posix_map_unknown_string = "WB_POSIX_MAP_UNKNOWN";
613 static const char *wb_posix_map_template_string = "WB_POSIX_MAP_TEMPLATE";
614 static const char *wb_posix_map_sfu_string = "WB_POSIX_MAP_SFU";
615 static const char *wb_posix_map_sfu20_string = "WB_POSIX_MAP_SFU20";
616 static const char *wb_posix_map_rfc2307_string = "WB_POSIX_MAP_RFC2307";
617 static const char *wb_posix_map_unixinfo_string = "WB_POSIX_MAP_UNIXINFO";
619 static const char *ad_map_type_string(enum wb_posix_mapping map_type)
621 switch (map_type) {
622 case WB_POSIX_MAP_TEMPLATE:
623 return wb_posix_map_template_string;
624 case WB_POSIX_MAP_SFU:
625 return wb_posix_map_sfu_string;
626 case WB_POSIX_MAP_SFU20:
627 return wb_posix_map_sfu20_string;
628 case WB_POSIX_MAP_RFC2307:
629 return wb_posix_map_rfc2307_string;
630 case WB_POSIX_MAP_UNIXINFO:
631 return wb_posix_map_unixinfo_string;
632 default:
633 return wb_posix_map_unknown_string;
637 static NTSTATUS nss_ad_generic_init(struct nss_domain_entry *e,
638 enum wb_posix_mapping new_ad_map_type)
640 struct idmap_domain *dom;
641 struct idmap_ad_context *ctx;
643 if (e->state != NULL) {
644 dom = talloc_get_type(e->state, struct idmap_domain);
645 } else {
646 dom = talloc_zero(e, struct idmap_domain);
647 if (dom == NULL) {
648 DEBUG(0, ("Out of memory!\n"));
649 return NT_STATUS_NO_MEMORY;
651 e->state = dom;
654 if (e->domain != NULL) {
655 dom->name = talloc_strdup(dom, e->domain);
656 if (dom->name == NULL) {
657 DEBUG(0, ("Out of memory!\n"));
658 return NT_STATUS_NO_MEMORY;
662 if (dom->private_data != NULL) {
663 ctx = talloc_get_type(dom->private_data,
664 struct idmap_ad_context);
665 } else {
666 ctx = talloc_zero(dom, struct idmap_ad_context);
667 if (ctx == NULL) {
668 DEBUG(0, ("Out of memory!\n"));
669 return NT_STATUS_NO_MEMORY;
671 ctx->ad_map_type = WB_POSIX_MAP_RFC2307;
672 dom->private_data = ctx;
675 if ((ctx->ad_map_type != WB_POSIX_MAP_UNKNOWN) &&
676 (ctx->ad_map_type != new_ad_map_type))
678 DEBUG(2, ("nss_ad_generic_init: "
679 "Warning: overriding previously set posix map type "
680 "%s for domain %s with map type %s.\n",
681 ad_map_type_string(ctx->ad_map_type),
682 dom->name,
683 ad_map_type_string(new_ad_map_type)));
686 ctx->ad_map_type = new_ad_map_type;
688 return NT_STATUS_OK;
691 static NTSTATUS nss_sfu_init( struct nss_domain_entry *e )
693 return nss_ad_generic_init(e, WB_POSIX_MAP_SFU);
696 static NTSTATUS nss_sfu20_init( struct nss_domain_entry *e )
698 return nss_ad_generic_init(e, WB_POSIX_MAP_SFU20);
701 static NTSTATUS nss_rfc2307_init( struct nss_domain_entry *e )
703 return nss_ad_generic_init(e, WB_POSIX_MAP_RFC2307);
707 /************************************************************************
708 ***********************************************************************/
710 static NTSTATUS nss_ad_get_info( struct nss_domain_entry *e,
711 const struct dom_sid *sid,
712 TALLOC_CTX *mem_ctx,
713 const char **homedir,
714 const char **shell,
715 const char **gecos,
716 uint32 *gid )
718 const char *attrs[] = {NULL, /* attr_homedir */
719 NULL, /* attr_shell */
720 NULL, /* attr_gecos */
721 NULL, /* attr_gidnumber */
722 NULL };
723 char *filter = NULL;
724 LDAPMessage *msg_internal = NULL;
725 ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
726 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
727 char *sidstr = NULL;
728 struct idmap_domain *dom;
729 struct idmap_ad_context *ctx;
731 DEBUG(10, ("nss_ad_get_info called for sid [%s] in domain '%s'\n",
732 sid_string_dbg(sid), e->domain?e->domain:"NULL"));
734 /* Only do query if we are online */
735 if (idmap_is_offline()) {
736 return NT_STATUS_FILE_IS_OFFLINE;
739 dom = talloc_get_type(e->state, struct idmap_domain);
740 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
742 ads_status = ad_idmap_cached_connection(dom);
743 if (!ADS_ERR_OK(ads_status)) {
744 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
747 if (!ctx->ad_schema) {
748 DEBUG(10, ("nss_ad_get_info: no ad_schema configured!\n"));
749 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
752 if (!sid || !homedir || !shell || !gecos) {
753 return NT_STATUS_INVALID_PARAMETER;
756 /* Have to do our own query */
758 DEBUG(10, ("nss_ad_get_info: no ads connection given, doing our "
759 "own query\n"));
761 attrs[0] = ctx->ad_schema->posix_homedir_attr;
762 attrs[1] = ctx->ad_schema->posix_shell_attr;
763 attrs[2] = ctx->ad_schema->posix_gecos_attr;
764 attrs[3] = ctx->ad_schema->posix_gidnumber_attr;
766 sidstr = ldap_encode_ndr_dom_sid(mem_ctx, sid);
767 filter = talloc_asprintf(mem_ctx, "(objectSid=%s)", sidstr);
768 TALLOC_FREE(sidstr);
770 if (!filter) {
771 nt_status = NT_STATUS_NO_MEMORY;
772 goto done;
775 ads_status = ads_search_retry(ctx->ads, &msg_internal, filter, attrs);
776 if (!ADS_ERR_OK(ads_status)) {
777 nt_status = ads_ntstatus(ads_status);
778 goto done;
781 *homedir = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_homedir_attr);
782 *shell = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_shell_attr);
783 *gecos = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_gecos_attr);
785 if (gid) {
786 if (!ads_pull_uint32(ctx->ads, msg_internal, ctx->ad_schema->posix_gidnumber_attr, gid))
787 *gid = (uint32)-1;
790 nt_status = NT_STATUS_OK;
792 done:
793 if (msg_internal) {
794 ads_msgfree(ctx->ads, msg_internal);
797 return nt_status;
800 /**********************************************************************
801 *********************************************************************/
803 static NTSTATUS nss_ad_map_to_alias(TALLOC_CTX *mem_ctx,
804 struct nss_domain_entry *e,
805 const char *name,
806 char **alias)
808 const char *attrs[] = {NULL, /* attr_uid */
809 NULL };
810 char *filter = NULL;
811 LDAPMessage *msg = NULL;
812 ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
813 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
814 struct idmap_domain *dom;
815 struct idmap_ad_context *ctx = NULL;
817 /* Check incoming parameters */
819 if ( !e || !e->domain || !name || !*alias) {
820 nt_status = NT_STATUS_INVALID_PARAMETER;
821 goto done;
824 /* Only do query if we are online */
826 if (idmap_is_offline()) {
827 nt_status = NT_STATUS_FILE_IS_OFFLINE;
828 goto done;
831 dom = talloc_get_type(e->state, struct idmap_domain);
832 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
834 ads_status = ad_idmap_cached_connection(dom);
835 if (!ADS_ERR_OK(ads_status)) {
836 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
839 if (!ctx->ad_schema) {
840 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
841 goto done;
844 attrs[0] = ctx->ad_schema->posix_uid_attr;
846 filter = talloc_asprintf(mem_ctx,
847 "(sAMAccountName=%s)",
848 name);
849 if (!filter) {
850 nt_status = NT_STATUS_NO_MEMORY;
851 goto done;
854 ads_status = ads_search_retry(ctx->ads, &msg, filter, attrs);
855 if (!ADS_ERR_OK(ads_status)) {
856 nt_status = ads_ntstatus(ads_status);
857 goto done;
860 *alias = ads_pull_string(ctx->ads, mem_ctx, msg, ctx->ad_schema->posix_uid_attr);
862 if (!*alias) {
863 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
866 nt_status = NT_STATUS_OK;
868 done:
869 if (filter) {
870 talloc_destroy(filter);
872 if (msg) {
873 ads_msgfree(ctx->ads, msg);
876 return nt_status;
879 /**********************************************************************
880 *********************************************************************/
882 static NTSTATUS nss_ad_map_from_alias( TALLOC_CTX *mem_ctx,
883 struct nss_domain_entry *e,
884 const char *alias,
885 char **name )
887 const char *attrs[] = {"sAMAccountName",
888 NULL };
889 char *filter = NULL;
890 LDAPMessage *msg = NULL;
891 ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
892 NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
893 char *username;
894 struct idmap_domain *dom;
895 struct idmap_ad_context *ctx = NULL;
897 /* Check incoming parameters */
899 if ( !alias || !name) {
900 nt_status = NT_STATUS_INVALID_PARAMETER;
901 goto done;
904 /* Only do query if we are online */
906 if (idmap_is_offline()) {
907 nt_status = NT_STATUS_FILE_IS_OFFLINE;
908 goto done;
911 dom = talloc_get_type(e->state, struct idmap_domain);
912 ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
914 ads_status = ad_idmap_cached_connection(dom);
915 if (!ADS_ERR_OK(ads_status)) {
916 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
919 if (!ctx->ad_schema) {
920 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
921 goto done;
924 filter = talloc_asprintf(mem_ctx,
925 "(%s=%s)",
926 ctx->ad_schema->posix_uid_attr,
927 alias);
928 if (!filter) {
929 nt_status = NT_STATUS_NO_MEMORY;
930 goto done;
933 ads_status = ads_search_retry(ctx->ads, &msg, filter, attrs);
934 if (!ADS_ERR_OK(ads_status)) {
935 nt_status = ads_ntstatus(ads_status);
936 goto done;
939 username = ads_pull_string(ctx->ads, mem_ctx, msg,
940 "sAMAccountName");
941 if (!username) {
942 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
945 *name = talloc_asprintf(mem_ctx, "%s\\%s",
946 lp_workgroup(),
947 username);
948 if (!*name) {
949 nt_status = NT_STATUS_NO_MEMORY;
950 goto done;
953 nt_status = NT_STATUS_OK;
955 done:
956 if (filter) {
957 talloc_destroy(filter);
959 if (msg) {
960 ads_msgfree(ctx->ads, msg);
963 return nt_status;
966 /************************************************************************
967 Function dispatch tables for the idmap and nss plugins
968 ***********************************************************************/
970 static struct idmap_methods ad_methods = {
971 .init = idmap_ad_initialize,
972 .unixids_to_sids = idmap_ad_unixids_to_sids,
973 .sids_to_unixids = idmap_ad_sids_to_unixids,
976 /* The SFU and RFC2307 NSS plugins share everything but the init
977 function which sets the intended schema model to use */
979 static struct nss_info_methods nss_rfc2307_methods = {
980 .init = nss_rfc2307_init,
981 .get_nss_info = nss_ad_get_info,
982 .map_to_alias = nss_ad_map_to_alias,
983 .map_from_alias = nss_ad_map_from_alias,
986 static struct nss_info_methods nss_sfu_methods = {
987 .init = nss_sfu_init,
988 .get_nss_info = nss_ad_get_info,
989 .map_to_alias = nss_ad_map_to_alias,
990 .map_from_alias = nss_ad_map_from_alias,
993 static struct nss_info_methods nss_sfu20_methods = {
994 .init = nss_sfu20_init,
995 .get_nss_info = nss_ad_get_info,
996 .map_to_alias = nss_ad_map_to_alias,
997 .map_from_alias = nss_ad_map_from_alias,
1002 /************************************************************************
1003 Initialize the plugins
1004 ***********************************************************************/
1006 NTSTATUS samba_init_module(void)
1008 static NTSTATUS status_idmap_ad = NT_STATUS_UNSUCCESSFUL;
1009 static NTSTATUS status_nss_rfc2307 = NT_STATUS_UNSUCCESSFUL;
1010 static NTSTATUS status_nss_sfu = NT_STATUS_UNSUCCESSFUL;
1011 static NTSTATUS status_nss_sfu20 = NT_STATUS_UNSUCCESSFUL;
1013 /* Always register the AD method first in order to get the
1014 idmap_domain interface called */
1016 if ( !NT_STATUS_IS_OK(status_idmap_ad) ) {
1017 status_idmap_ad = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION,
1018 "ad", &ad_methods);
1019 if ( !NT_STATUS_IS_OK(status_idmap_ad) )
1020 return status_idmap_ad;
1023 if ( !NT_STATUS_IS_OK( status_nss_rfc2307 ) ) {
1024 status_nss_rfc2307 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
1025 "rfc2307", &nss_rfc2307_methods );
1026 if ( !NT_STATUS_IS_OK(status_nss_rfc2307) )
1027 return status_nss_rfc2307;
1030 if ( !NT_STATUS_IS_OK( status_nss_sfu ) ) {
1031 status_nss_sfu = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
1032 "sfu", &nss_sfu_methods );
1033 if ( !NT_STATUS_IS_OK(status_nss_sfu) )
1034 return status_nss_sfu;
1037 if ( !NT_STATUS_IS_OK( status_nss_sfu20 ) ) {
1038 status_nss_sfu20 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
1039 "sfu20", &nss_sfu20_methods );
1040 if ( !NT_STATUS_IS_OK(status_nss_sfu20) )
1041 return status_nss_sfu20;
1044 return NT_STATUS_OK;