2 Unix SMB/CIFS implementation.
4 Winbind daemon for ntdom nss module
6 Copyright (C) Tim Potter 2000-2001
7 Copyright (C) 2001 by Martin Pool <mbp@samba.org>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #define DBGC_CLASS DBGC_WINBIND
29 extern struct winbindd_methods cache_methods;
30 extern struct winbindd_methods passdb_methods;
33 * @file winbindd_util.c
35 * Winbind daemon for NT domain authentication nss module.
38 /* The list of trusted domains. Note that the list can be deleted and
39 recreated using the init_domain_list() function so pointers to
40 individual winbindd_domain structures cannot be made. Keep a copy of
41 the domain name instead. */
43 static struct winbindd_domain *_domain_list;
46 When was the last scan of trusted domains done?
51 static time_t last_trustdom_scan;
53 struct winbindd_domain *domain_list(void)
57 if ((!_domain_list) && (!init_domain_list())) {
58 smb_panic("Init_domain_list failed");
64 /* Free all entries in the trusted domain list */
66 void free_domain_list(void)
68 struct winbindd_domain *domain = _domain_list;
71 struct winbindd_domain *next = domain->next;
73 DLIST_REMOVE(_domain_list, domain);
79 static BOOL is_internal_domain(const DOM_SID *sid)
85 return sid_check_is_builtin(sid);
87 return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
90 static BOOL is_in_internal_domain(const DOM_SID *sid)
96 return sid_check_is_in_builtin(sid);
98 return (sid_check_is_in_our_domain(sid) || sid_check_is_in_builtin(sid));
102 /* Add a trusted domain to our list of domains */
103 static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
104 struct winbindd_methods *methods,
107 struct winbindd_domain *domain;
108 const char *alternative_name = NULL;
110 /* ignore alt_name if we are not in an AD domain */
112 if ( (lp_security() == SEC_ADS) && alt_name && *alt_name) {
113 alternative_name = alt_name;
116 /* We can't call domain_list() as this function is called from
117 init_domain_list() and we'll get stuck in a loop. */
118 for (domain = _domain_list; domain; domain = domain->next) {
119 if (strequal(domain_name, domain->name) ||
120 strequal(domain_name, domain->alt_name))
125 if (alternative_name && *alternative_name)
127 if (strequal(alternative_name, domain->name) ||
128 strequal(alternative_name, domain->alt_name))
136 if (is_null_sid(sid)) {
140 if (sid_equal(sid, &domain->sid)) {
146 /* See if we found a match. Check if we need to update the
150 if ( sid_equal( &domain->sid, &global_sid_NULL ) )
151 sid_copy( &domain->sid, sid );
156 /* Create new domain entry */
158 if ((domain = SMB_MALLOC_P(struct winbindd_domain)) == NULL)
163 ZERO_STRUCTP(domain);
165 /* prioritise the short name */
166 if (strchr_m(domain_name, '.') && alternative_name && *alternative_name) {
167 fstrcpy(domain->name, alternative_name);
168 fstrcpy(domain->alt_name, domain_name);
170 fstrcpy(domain->name, domain_name);
171 if (alternative_name) {
172 fstrcpy(domain->alt_name, alternative_name);
176 domain->methods = methods;
177 domain->backend = NULL;
178 domain->internal = is_internal_domain(sid);
179 domain->sequence_number = DOM_SEQUENCE_NONE;
180 domain->last_seq_check = 0;
181 domain->initialized = False;
182 domain->online = is_internal_domain(sid);
183 domain->check_online_timeout = 0;
185 sid_copy(&domain->sid, sid);
188 /* Link to domain list */
189 DLIST_ADD(_domain_list, domain);
191 wcache_tdc_add_domain( domain );
193 DEBUG(2,("Added domain %s %s %s\n",
194 domain->name, domain->alt_name,
195 &domain->sid?sid_string_static(&domain->sid):""));
200 /********************************************************************
201 rescan our domains looking for new trusted domains
202 ********************************************************************/
204 struct trustdom_state {
208 struct winbindd_response *response;
211 static void trustdom_recv(void *private_data, BOOL success);
212 static void rescan_forest_root_trusts( void );
213 static void rescan_forest_trusts( void );
215 static void add_trusted_domains( struct winbindd_domain *domain )
218 struct winbindd_request *request;
219 struct winbindd_response *response;
220 uint32 fr_flags = (DS_DOMAIN_TREE_ROOT|DS_DOMAIN_IN_FOREST);
222 struct trustdom_state *state;
224 mem_ctx = talloc_init("add_trusted_domains");
225 if (mem_ctx == NULL) {
226 DEBUG(0, ("talloc_init failed\n"));
230 request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
231 response = TALLOC_P(mem_ctx, struct winbindd_response);
232 state = TALLOC_P(mem_ctx, struct trustdom_state);
234 if ((request == NULL) || (response == NULL) || (state == NULL)) {
235 DEBUG(0, ("talloc failed\n"));
236 talloc_destroy(mem_ctx);
240 state->mem_ctx = mem_ctx;
241 state->response = response;
243 /* Flags used to know how to continue the forest trust search */
245 state->primary = domain->primary;
246 state->forest_root = ((domain->domain_flags & fr_flags) == fr_flags );
248 request->length = sizeof(*request);
249 request->cmd = WINBINDD_LIST_TRUSTDOM;
251 async_domain_request(mem_ctx, domain, request, response,
252 trustdom_recv, state);
255 static void trustdom_recv(void *private_data, BOOL success)
257 struct trustdom_state *state =
258 talloc_get_type_abort(private_data, struct trustdom_state);
259 struct winbindd_response *response = state->response;
262 if ((!success) || (response->result != WINBINDD_OK)) {
263 DEBUG(1, ("Could not receive trustdoms\n"));
264 talloc_destroy(state->mem_ctx);
268 p = (char *)response->extra_data.data;
270 while ((p != NULL) && (*p != '\0')) {
271 char *q, *sidstr, *alt_name;
273 struct winbindd_domain *domain;
274 char *alternate_name = NULL;
276 alt_name = strchr(p, '\\');
277 if (alt_name == NULL) {
278 DEBUG(0, ("Got invalid trustdom response\n"));
285 sidstr = strchr(alt_name, '\\');
286 if (sidstr == NULL) {
287 DEBUG(0, ("Got invalid trustdom response\n"));
294 q = strchr(sidstr, '\n');
298 if (!string_to_sid(&sid, sidstr)) {
299 /* Allow NULL sid for sibling domains */
300 if ( strcmp(sidstr,"S-0-0") == 0) {
301 sid_copy( &sid, &global_sid_NULL);
303 DEBUG(0, ("Got invalid trustdom response\n"));
308 /* use the real alt_name if we have one, else pass in NULL */
310 if ( !strequal( alt_name, "(null)" ) )
311 alternate_name = alt_name;
313 /* If we have an existing domain structure, calling
314 add_trusted_domain() will update the SID if
315 necessary. This is important because we need the
316 SID for sibling domains */
318 if ( find_domain_from_name_noinit(p) != NULL ) {
319 domain = add_trusted_domain(p, alternate_name,
323 domain = add_trusted_domain(p, alternate_name,
326 setup_domain_child(domain, &domain->child, NULL);
333 SAFE_FREE(response->extra_data.data);
336 Cases to consider when scanning trusts:
337 (a) we are calling from a child domain (primary && !forest_root)
338 (b) we are calling from the root of the forest (primary && forest_root)
339 (c) we are calling from a trusted forest domain (!primary
343 if ( state->primary ) {
344 /* If this is our primary domain and we are not the in the
345 forest root, we have to scan the root trusts first */
347 if ( !state->forest_root )
348 rescan_forest_root_trusts();
350 rescan_forest_trusts();
352 } else if ( state->forest_root ) {
353 /* Once we have done root forest trust search, we can
354 go on to search thing trusted forests */
356 rescan_forest_trusts();
359 talloc_destroy(state->mem_ctx);
364 /********************************************************************
365 Scan the trusts of our forest root
366 ********************************************************************/
368 static void rescan_forest_root_trusts( void )
370 struct winbindd_tdc_domain *dom_list = NULL;
371 size_t num_trusts = 0;
374 /* The only transitive trusts supported by Windows 2003 AD are
375 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
376 first two are handled in forest and listed by
377 DsEnumerateDomainTrusts(). Forest trusts are not so we
378 have to do that ourselves. */
380 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
383 for ( i=0; i<num_trusts; i++ ) {
384 struct winbindd_domain *d = NULL;
386 /* Find the forest root. Don't necessarily trust
387 the domain_list() as our primary domain may not
388 have been initialized. */
390 if ( !(dom_list[i].trust_flags & DS_DOMAIN_TREE_ROOT) ) {
394 /* Here's the forest root */
396 d = find_domain_from_name_noinit( dom_list[i].domain_name );
399 d = add_trusted_domain( dom_list[i].domain_name,
400 dom_list[i].dns_name,
405 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
406 "for domain tree root %s (%s)\n",
407 d->name, d->alt_name ));
409 d->domain_flags = dom_list[i].trust_flags;
410 d->domain_type = dom_list[i].trust_type;
411 d->domain_trust_attribs = dom_list[i].trust_attribs;
413 add_trusted_domains( d );
418 TALLOC_FREE( dom_list );
423 /********************************************************************
424 scan the transitive forest trists (not our own)
425 ********************************************************************/
428 static void rescan_forest_trusts( void )
430 struct winbindd_domain *d = NULL;
431 struct winbindd_tdc_domain *dom_list = NULL;
432 size_t num_trusts = 0;
435 /* The only transitive trusts supported by Windows 2003 AD are
436 (a) Parent-Child, (b) Tree-Root, and (c) Forest. The
437 first two are handled in forest and listed by
438 DsEnumerateDomainTrusts(). Forest trusts are not so we
439 have to do that ourselves. */
441 if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
444 for ( i=0; i<num_trusts; i++ ) {
445 uint32 flags = dom_list[i].trust_flags;
446 uint32 type = dom_list[i].trust_type;
447 uint32 attribs = dom_list[i].trust_attribs;
449 d = find_domain_from_name_noinit( dom_list[i].domain_name );
451 /* ignore our primary and internal domains */
453 if ( d && (d->internal || d->primary ) )
456 if ( (flags & DS_DOMAIN_DIRECT_INBOUND) &&
457 (type == DS_DOMAIN_TRUST_TYPE_UPLEVEL) &&
458 (attribs == DS_DOMAIN_TRUST_ATTRIB_FOREST_TRANSITIVE) )
460 /* add the trusted domain if we don't know
464 d = add_trusted_domain( dom_list[i].domain_name,
465 dom_list[i].dns_name,
470 DEBUG(10,("Following trust path for domain %s (%s)\n",
471 d->name, d->alt_name ));
472 add_trusted_domains( d );
476 TALLOC_FREE( dom_list );
481 /*********************************************************************
482 The process of updating the trusted domain list is a three step
485 (b) ask the root domain in our forest
486 (c) ask the a DC in any Win2003 trusted forests
487 *********************************************************************/
489 void rescan_trusted_domains( void )
491 time_t now = time(NULL);
493 /* see if the time has come... */
495 if ((now >= last_trustdom_scan) &&
496 ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
499 /* clear the TRUSTDOM cache first */
503 /* this will only add new domains we didn't already know about
504 in the domain_list()*/
506 add_trusted_domains( find_our_domain() );
508 last_trustdom_scan = now;
513 struct init_child_state {
515 struct winbindd_domain *domain;
516 struct winbindd_request *request;
517 struct winbindd_response *response;
518 void (*continuation)(void *private_data, BOOL success);
522 static void init_child_recv(void *private_data, BOOL success);
523 static void init_child_getdc_recv(void *private_data, BOOL success);
525 enum winbindd_result init_child_connection(struct winbindd_domain *domain,
526 void (*continuation)(void *private_data,
531 struct winbindd_request *request;
532 struct winbindd_response *response;
533 struct init_child_state *state;
534 struct winbindd_domain *request_domain;
536 mem_ctx = talloc_init("init_child_connection");
537 if (mem_ctx == NULL) {
538 DEBUG(0, ("talloc_init failed\n"));
539 return WINBINDD_ERROR;
542 request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
543 response = TALLOC_P(mem_ctx, struct winbindd_response);
544 state = TALLOC_P(mem_ctx, struct init_child_state);
546 if ((request == NULL) || (response == NULL) || (state == NULL)) {
547 DEBUG(0, ("talloc failed\n"));
548 TALLOC_FREE(mem_ctx);
549 continuation(private_data, False);
550 return WINBINDD_ERROR;
553 request->length = sizeof(*request);
555 state->mem_ctx = mem_ctx;
556 state->domain = domain;
557 state->request = request;
558 state->response = response;
559 state->continuation = continuation;
560 state->private_data = private_data;
562 if (IS_DC || domain->primary || domain->internal ) {
563 /* The primary domain has to find the DC name itself */
564 request->cmd = WINBINDD_INIT_CONNECTION;
565 fstrcpy(request->domain_name, domain->name);
566 request->data.init_conn.is_primary = domain->internal ? False : True;
567 fstrcpy(request->data.init_conn.dcname, "");
568 async_request(mem_ctx, &domain->child, request, response,
569 init_child_recv, state);
570 return WINBINDD_PENDING;
573 /* This is *not* the primary domain, let's ask our DC about a DC
576 request->cmd = WINBINDD_GETDCNAME;
577 fstrcpy(request->domain_name, domain->name);
579 request_domain = find_our_domain();
580 async_domain_request(mem_ctx, request_domain, request, response,
581 init_child_getdc_recv, state);
582 return WINBINDD_PENDING;
585 static void init_child_getdc_recv(void *private_data, BOOL success)
587 struct init_child_state *state =
588 talloc_get_type_abort(private_data, struct init_child_state);
589 const char *dcname = "";
591 DEBUG(10, ("Received getdcname response\n"));
593 if (success && (state->response->result == WINBINDD_OK)) {
594 dcname = state->response->data.dc_name;
597 state->request->cmd = WINBINDD_INIT_CONNECTION;
598 fstrcpy(state->request->domain_name, state->domain->name);
599 state->request->data.init_conn.is_primary = False;
600 fstrcpy(state->request->data.init_conn.dcname, dcname);
602 async_request(state->mem_ctx, &state->domain->child,
603 state->request, state->response,
604 init_child_recv, state);
607 static void init_child_recv(void *private_data, BOOL success)
609 struct init_child_state *state =
610 talloc_get_type_abort(private_data, struct init_child_state);
612 DEBUG(5, ("Received child initialization response for domain %s\n",
613 state->domain->name));
615 if ((!success) || (state->response->result != WINBINDD_OK)) {
616 DEBUG(3, ("Could not init child\n"));
617 state->continuation(state->private_data, False);
618 talloc_destroy(state->mem_ctx);
622 fstrcpy(state->domain->name,
623 state->response->data.domain_info.name);
624 fstrcpy(state->domain->alt_name,
625 state->response->data.domain_info.alt_name);
626 string_to_sid(&state->domain->sid,
627 state->response->data.domain_info.sid);
628 state->domain->native_mode =
629 state->response->data.domain_info.native_mode;
630 state->domain->active_directory =
631 state->response->data.domain_info.active_directory;
632 state->domain->sequence_number =
633 state->response->data.domain_info.sequence_number;
635 init_dc_connection(state->domain);
637 if (state->continuation != NULL)
638 state->continuation(state->private_data, True);
639 talloc_destroy(state->mem_ctx);
642 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
643 struct winbindd_cli_state *state)
645 /* Ensure null termination */
646 state->request.domain_name
647 [sizeof(state->request.domain_name)-1]='\0';
648 state->request.data.init_conn.dcname
649 [sizeof(state->request.data.init_conn.dcname)-1]='\0';
651 if (strlen(state->request.data.init_conn.dcname) > 0) {
652 fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
655 init_dc_connection(domain);
657 if (!domain->initialized) {
658 /* If we return error here we can't do any cached authentication,
659 but we may be in disconnected mode and can't initialize correctly.
660 Do what the previous code did and just return without initialization,
661 once we go online we'll re-initialize.
663 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
664 "online = %d\n", domain->name, (int)domain->online ));
667 fstrcpy(state->response.data.domain_info.name, domain->name);
668 fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
669 fstrcpy(state->response.data.domain_info.sid,
670 sid_string_static(&domain->sid));
672 state->response.data.domain_info.native_mode
673 = domain->native_mode;
674 state->response.data.domain_info.active_directory
675 = domain->active_directory;
676 state->response.data.domain_info.primary
678 state->response.data.domain_info.sequence_number =
679 domain->sequence_number;
684 /* Look up global info for the winbind daemon */
685 BOOL init_domain_list(void)
687 struct winbindd_domain *domain;
688 int role = lp_server_role();
690 /* Free existing list */
693 /* Add ourselves as the first entry. */
695 if ( role == ROLE_DOMAIN_MEMBER ) {
698 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
699 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
703 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
704 &cache_methods, &our_sid);
705 domain->primary = True;
706 setup_domain_child(domain, &domain->child, NULL);
708 /* Even in the parent winbindd we'll need to
709 talk to the DC, so try and see if we can
710 contact it. Theoretically this isn't neccessary
711 as the init_dc_connection() in init_child_recv()
712 will do this, but we can start detecting the DC
714 set_domain_online_request(domain);
719 domain = add_trusted_domain(get_global_sam_name(), NULL,
720 &passdb_methods, get_global_sam_sid());
721 if ( role != ROLE_DOMAIN_MEMBER ) {
722 domain->primary = True;
724 setup_domain_child(domain, &domain->child, NULL);
728 domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
729 &global_sid_Builtin);
730 setup_domain_child(domain, &domain->child, NULL);
735 void check_domain_trusted( const char *name, const DOM_SID *user_sid )
737 struct winbindd_domain *domain;
741 domain = find_domain_from_name_noinit( name );
745 sid_copy( &dom_sid, user_sid );
746 if ( !sid_split_rid( &dom_sid, &rid ) )
749 /* add the newly discovered trusted domain */
751 domain = add_trusted_domain( name, NULL, &cache_methods,
757 /* assume this is a trust from a one-way transitive
760 domain->active_directory = True;
761 domain->domain_flags = DS_DOMAIN_DIRECT_OUTBOUND;
762 domain->domain_type = DS_DOMAIN_TRUST_TYPE_UPLEVEL;
763 domain->internal = False;
764 domain->online = True;
766 setup_domain_child(domain, &domain->child, NULL);
768 wcache_tdc_add_domain( domain );
774 * Given a domain name, return the struct winbindd domain info for it
776 * @note Do *not* pass lp_workgroup() to this function. domain_list
777 * may modify it's value, and free that pointer. Instead, our local
778 * domain may be found by calling find_our_domain().
782 * @return The domain structure for the named domain, if it is working.
785 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
787 struct winbindd_domain *domain;
789 /* Search through list */
791 for (domain = domain_list(); domain != NULL; domain = domain->next) {
792 if (strequal(domain_name, domain->name) ||
793 (domain->alt_name[0] &&
794 strequal(domain_name, domain->alt_name))) {
804 struct winbindd_domain *find_domain_from_name(const char *domain_name)
806 struct winbindd_domain *domain;
808 domain = find_domain_from_name_noinit(domain_name);
813 if (!domain->initialized)
814 init_dc_connection(domain);
819 /* Given a domain sid, return the struct winbindd domain info for it */
821 struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
823 struct winbindd_domain *domain;
825 /* Search through list */
827 for (domain = domain_list(); domain != NULL; domain = domain->next) {
828 if (sid_compare_domain(sid, &domain->sid) == 0)
837 /* Given a domain sid, return the struct winbindd domain info for it */
839 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
841 struct winbindd_domain *domain;
843 domain = find_domain_from_sid_noinit(sid);
848 if (!domain->initialized)
849 init_dc_connection(domain);
854 struct winbindd_domain *find_our_domain(void)
856 struct winbindd_domain *domain;
858 /* Search through list */
860 for (domain = domain_list(); domain != NULL; domain = domain->next) {
865 smb_panic("Could not find our domain");
869 struct winbindd_domain *find_root_domain(void)
871 struct winbindd_domain *ours = find_our_domain();
876 if ( strlen(ours->forest_name) == 0 )
879 return find_domain_from_name( ours->forest_name );
882 struct winbindd_domain *find_builtin_domain(void)
885 struct winbindd_domain *domain;
887 string_to_sid(&sid, "S-1-5-32");
888 domain = find_domain_from_sid(&sid);
890 if (domain == NULL) {
891 smb_panic("Could not find BUILTIN domain");
897 /* Find the appropriate domain to lookup a name or SID */
899 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
901 /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
903 if ( sid_check_is_in_unix_groups(sid) ||
904 sid_check_is_unix_groups(sid) ||
905 sid_check_is_in_unix_users(sid) ||
906 sid_check_is_unix_users(sid) )
908 return find_domain_from_sid(get_global_sam_sid());
911 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
912 * one to contact the external DC's. On member servers the internal
913 * domains are different: These are part of the local SAM. */
915 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n",
916 sid_string_static(sid)));
918 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
919 DEBUG(10, ("calling find_domain_from_sid\n"));
920 return find_domain_from_sid(sid);
923 /* On a member server a query for SID or name can always go to our
926 DEBUG(10, ("calling find_our_domain\n"));
927 return find_our_domain();
930 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
932 if ( strequal(domain_name, unix_users_domain_name() ) ||
933 strequal(domain_name, unix_groups_domain_name() ) )
935 return find_domain_from_name_noinit( get_global_sam_name() );
938 if (IS_DC || strequal(domain_name, "BUILTIN") ||
939 strequal(domain_name, get_global_sam_name()))
940 return find_domain_from_name_noinit(domain_name);
942 /* The "Unix User" and "Unix Group" domain our handled by passdb */
944 return find_our_domain();
947 /* Lookup a sid in a domain from a name */
949 BOOL winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
950 enum winbindd_cmd orig_cmd,
951 struct winbindd_domain *domain,
952 const char *domain_name,
953 const char *name, DOM_SID *sid,
954 enum lsa_SidType *type)
959 result = domain->methods->name_to_sid(domain, mem_ctx, orig_cmd,
960 domain_name, name, sid, type);
962 /* Return sid and type if lookup successful */
963 if (!NT_STATUS_IS_OK(result)) {
964 *type = SID_NAME_UNKNOWN;
967 return NT_STATUS_IS_OK(result);
971 * @brief Lookup a name in a domain from a sid.
973 * @param sid Security ID you want to look up.
974 * @param name On success, set to the name corresponding to @p sid.
975 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
976 * @param type On success, contains the type of name: alias, group or
978 * @retval True if the name exists, in which case @p name and @p type
979 * are set, otherwise False.
981 BOOL winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
982 struct winbindd_domain *domain,
986 enum lsa_SidType *type)
995 result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
997 /* Return name and type if successful */
999 if (NT_STATUS_IS_OK(result)) {
1003 *type = SID_NAME_UNKNOWN;
1008 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
1010 void free_getent_state(struct getent_state *state)
1012 struct getent_state *temp;
1014 /* Iterate over state list */
1018 while(temp != NULL) {
1019 struct getent_state *next;
1021 /* Free sam entries then list entry */
1023 SAFE_FREE(state->sam_entries);
1024 DLIST_REMOVE(state, state);
1032 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1034 static BOOL assume_domain(const char *domain)
1036 /* never assume the domain on a standalone server */
1038 if ( lp_server_role() == ROLE_STANDALONE )
1041 /* domain member servers may possibly assume for the domain name */
1043 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1044 if ( !strequal(lp_workgroup(), domain) )
1047 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
1051 /* only left with a domain controller */
1053 if ( strequal(get_global_sam_name(), domain) ) {
1060 /* Parse a string of the form DOMAIN\user into a domain and a user */
1062 BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
1064 char *p = strchr(domuser,*lp_winbind_separator());
1067 fstrcpy(user, domuser);
1069 if ( assume_domain(lp_workgroup())) {
1070 fstrcpy(domain, lp_workgroup());
1076 fstrcpy(domain, domuser);
1077 domain[PTR_DIFF(p, domuser)] = 0;
1085 BOOL parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1086 char **domain, char **user)
1088 fstring fstr_domain, fstr_user;
1089 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1092 *domain = talloc_strdup(mem_ctx, fstr_domain);
1093 *user = talloc_strdup(mem_ctx, fstr_user);
1094 return ((*domain != NULL) && (*user != NULL));
1097 /* Ensure an incoming username from NSS is fully qualified. Replace the
1098 incoming fstring with DOMAIN <separator> user. Returns the same
1099 values as parse_domain_user() but also replaces the incoming username.
1100 Used to ensure all names are fully qualified within winbindd.
1101 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1102 The protocol definitions of auth_crap, chng_pswd_auth_crap
1103 really should be changed to use this instead of doing things
1106 BOOL canonicalize_username(fstring username_inout, fstring domain, fstring user)
1108 if (!parse_domain_user(username_inout, domain, user)) {
1111 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1112 domain, *lp_winbind_separator(),
1118 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1119 'winbind separator' options.
1121 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1124 If we are a PDC or BDC, and this is for our domain, do likewise.
1126 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
1127 username is then unqualified in unix
1129 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1131 void fill_domain_username(fstring name, const char *domain, const char *user, BOOL can_assume)
1135 fstrcpy(tmp_user, user);
1136 strlower_m(tmp_user);
1138 if (can_assume && assume_domain(domain)) {
1139 strlcpy(name, tmp_user, sizeof(fstring));
1141 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1142 domain, *lp_winbind_separator(),
1148 * Winbindd socket accessor functions
1151 char *get_winbind_priv_pipe_dir(void)
1153 return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
1157 * Client list accessor functions
1160 static struct winbindd_cli_state *_client_list;
1161 static int _num_clients;
1163 /* Return list of all connected clients */
1165 struct winbindd_cli_state *winbindd_client_list(void)
1167 return _client_list;
1170 /* Add a connection to the list */
1172 void winbindd_add_client(struct winbindd_cli_state *cli)
1174 DLIST_ADD(_client_list, cli);
1178 /* Remove a client from the list */
1180 void winbindd_remove_client(struct winbindd_cli_state *cli)
1182 DLIST_REMOVE(_client_list, cli);
1186 /* Close all open clients */
1188 void winbindd_kill_all_clients(void)
1190 struct winbindd_cli_state *cl = winbindd_client_list();
1192 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1195 struct winbindd_cli_state *next;
1198 winbindd_remove_client(cl);
1203 /* Return number of open clients */
1205 int winbindd_num_clients(void)
1207 return _num_clients;
1210 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1211 TALLOC_CTX *mem_ctx,
1212 const DOM_SID *user_sid,
1213 uint32 *p_num_groups, DOM_SID **user_sids)
1215 NET_USER_INFO_3 *info3 = NULL;
1216 NTSTATUS status = NT_STATUS_NO_MEMORY;
1218 size_t num_groups = 0;
1219 DOM_SID group_sid, primary_group;
1221 DEBUG(3,(": lookup_usergroups_cached\n"));
1227 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1229 if (info3 == NULL) {
1230 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1233 if (info3->num_groups == 0) {
1235 return NT_STATUS_UNSUCCESSFUL;
1238 /* always add the primary group to the sid array */
1239 sid_compose(&primary_group, &info3->dom_sid.sid, info3->user_rid);
1241 if (!add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups)) {
1243 return NT_STATUS_NO_MEMORY;
1246 for (i=0; i<info3->num_groups; i++) {
1247 sid_copy(&group_sid, &info3->dom_sid.sid);
1248 sid_append_rid(&group_sid, info3->gids[i].g_rid);
1250 if (!add_sid_to_array(mem_ctx, &group_sid, user_sids,
1253 return NT_STATUS_NO_MEMORY;
1258 *p_num_groups = num_groups;
1259 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1261 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1266 /*********************************************************************
1267 We use this to remove spaces from user and group names
1268 ********************************************************************/
1270 void ws_name_replace( char *name, char replace )
1272 char replace_char[2] = { 0x0, 0x0 };
1274 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1277 replace_char[0] = replace;
1278 all_string_sub( name, " ", replace_char, 0 );
1283 /*********************************************************************
1284 We use this to do the inverse of ws_name_replace()
1285 ********************************************************************/
1287 void ws_name_return( char *name, char replace )
1289 char replace_char[2] = { 0x0, 0x0 };
1291 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1294 replace_char[0] = replace;
1295 all_string_sub( name, replace_char, " ", 0 );
1300 /*********************************************************************
1301 ********************************************************************/
1303 BOOL winbindd_can_contact_domain( struct winbindd_domain *domain )
1305 /* We can contact the domain if it is our primary domain */
1307 if ( domain->primary )
1310 /* Can always contact a domain that is in out forest */
1312 if ( domain->domain_flags & DS_DOMAIN_IN_FOREST )
1315 /* We cannot contact the domain if it is running AD and
1316 we have no inbound trust */
1318 if ( domain->active_directory &&
1319 ((domain->domain_flags&DS_DOMAIN_DIRECT_INBOUND) != DS_DOMAIN_DIRECT_INBOUND) )
1324 /* Assume everything else is ok (probably not true but what