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 2 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, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #define DBGC_CLASS DBGC_WINBIND
31 * @file winbindd_util.c
33 * Winbind daemon for NT domain authentication nss module.
38 * Used to clobber name fields that have an undefined value.
40 * Correct code should never look at a field that has this value.
43 static const fstring name_deadbeef
= "<deadbeef>";
45 /* The list of trusted domains. Note that the list can be deleted and
46 recreated using the init_domain_list() function so pointers to
47 individual winbindd_domain structures cannot be made. Keep a copy of
48 the domain name instead. */
50 static struct winbindd_domain
*_domain_list
;
53 When was the last scan of trusted domains done?
58 static time_t last_trustdom_scan
;
60 struct winbindd_domain
*domain_list(void)
64 if ((!_domain_list
) && (!init_domain_list())) {
65 smb_panic("Init_domain_list failed\n");
71 /* Free all entries in the trusted domain list */
73 void free_domain_list(void)
75 struct winbindd_domain
*domain
= _domain_list
;
78 struct winbindd_domain
*next
= domain
->next
;
80 DLIST_REMOVE(_domain_list
, domain
);
86 static BOOL
is_internal_domain(const DOM_SID
*sid
)
91 return (sid_check_is_domain(sid
) || sid_check_is_builtin(sid
));
94 static BOOL
is_in_internal_domain(const DOM_SID
*sid
)
99 return (sid_check_is_in_our_domain(sid
) || sid_check_is_in_builtin(sid
));
103 /* Add a trusted domain to our list of domains */
104 static struct winbindd_domain
*add_trusted_domain(const char *domain_name
, const char *alt_name
,
105 struct winbindd_methods
*methods
,
108 struct winbindd_domain
*domain
;
109 const char *alternative_name
= NULL
;
111 /* ignore alt_name if we are not in an AD domain */
113 if ( (lp_security() == SEC_ADS
) && alt_name
&& *alt_name
) {
114 alternative_name
= alt_name
;
117 /* We can't call domain_list() as this function is called from
118 init_domain_list() and we'll get stuck in a loop. */
119 for (domain
= _domain_list
; domain
; domain
= domain
->next
) {
120 if (strequal(domain_name
, domain
->name
) ||
121 strequal(domain_name
, domain
->alt_name
)) {
124 if (alternative_name
&& *alternative_name
) {
125 if (strequal(alternative_name
, domain
->name
) ||
126 strequal(alternative_name
, domain
->alt_name
)) {
131 if (is_null_sid(sid
)) {
133 } else if (sid_equal(sid
, &domain
->sid
)) {
139 /* Create new domain entry */
141 if ((domain
= SMB_MALLOC_P(struct winbindd_domain
)) == NULL
)
146 ZERO_STRUCTP(domain
);
148 /* prioritise the short name */
149 if (strchr_m(domain_name
, '.') && alternative_name
&& *alternative_name
) {
150 fstrcpy(domain
->name
, alternative_name
);
151 fstrcpy(domain
->alt_name
, domain_name
);
153 fstrcpy(domain
->name
, domain_name
);
154 if (alternative_name
) {
155 fstrcpy(domain
->alt_name
, alternative_name
);
159 domain
->methods
= methods
;
160 domain
->backend
= NULL
;
161 domain
->internal
= is_internal_domain(sid
);
162 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
163 domain
->last_seq_check
= 0;
164 domain
->initialized
= False
;
165 domain
->online
= is_internal_domain(sid
);
167 sid_copy(&domain
->sid
, sid
);
170 /* Link to domain list */
171 DLIST_ADD(_domain_list
, domain
);
173 DEBUG(2,("Added domain %s %s %s\n",
174 domain
->name
, domain
->alt_name
,
175 &domain
->sid
?sid_string_static(&domain
->sid
):""));
180 /********************************************************************
181 rescan our domains looking for new trusted domains
182 ********************************************************************/
184 struct trustdom_state
{
186 struct winbindd_response
*response
;
189 static void trustdom_recv(void *private_data
, BOOL success
);
191 static void add_trusted_domains( struct winbindd_domain
*domain
)
194 struct winbindd_request
*request
;
195 struct winbindd_response
*response
;
197 struct trustdom_state
*state
;
199 mem_ctx
= talloc_init("add_trusted_domains");
200 if (mem_ctx
== NULL
) {
201 DEBUG(0, ("talloc_init failed\n"));
205 request
= TALLOC_ZERO_P(mem_ctx
, struct winbindd_request
);
206 response
= TALLOC_P(mem_ctx
, struct winbindd_response
);
207 state
= TALLOC_P(mem_ctx
, struct trustdom_state
);
209 if ((request
== NULL
) || (response
== NULL
) || (state
== NULL
)) {
210 DEBUG(0, ("talloc failed\n"));
211 talloc_destroy(mem_ctx
);
215 state
->mem_ctx
= mem_ctx
;
216 state
->response
= response
;
218 request
->length
= sizeof(*request
);
219 request
->cmd
= WINBINDD_LIST_TRUSTDOM
;
221 async_domain_request(mem_ctx
, domain
, request
, response
,
222 trustdom_recv
, state
);
225 static void trustdom_recv(void *private_data
, BOOL success
)
227 extern struct winbindd_methods cache_methods
;
228 struct trustdom_state
*state
=
229 talloc_get_type_abort(private_data
, struct trustdom_state
);
230 struct winbindd_response
*response
= state
->response
;
233 if ((!success
) || (response
->result
!= WINBINDD_OK
)) {
234 DEBUG(1, ("Could not receive trustdoms\n"));
235 talloc_destroy(state
->mem_ctx
);
239 p
= (char *)response
->extra_data
.data
;
241 while ((p
!= NULL
) && (*p
!= '\0')) {
242 char *q
, *sidstr
, *alt_name
;
245 alt_name
= strchr(p
, '\\');
246 if (alt_name
== NULL
) {
247 DEBUG(0, ("Got invalid trustdom response\n"));
254 sidstr
= strchr(alt_name
, '\\');
255 if (sidstr
== NULL
) {
256 DEBUG(0, ("Got invalid trustdom response\n"));
263 q
= strchr(sidstr
, '\n');
267 if (!string_to_sid(&sid
, sidstr
)) {
268 DEBUG(0, ("Got invalid trustdom response\n"));
272 if (find_domain_from_name_noinit(p
) == NULL
) {
273 struct winbindd_domain
*domain
;
274 char *alternate_name
= NULL
;
276 /* use the real alt_name if we have one, else pass in NULL */
278 if ( !strequal( alt_name
, "(null)" ) )
279 alternate_name
= alt_name
;
281 domain
= add_trusted_domain(p
, alternate_name
,
284 setup_domain_child(domain
, &domain
->child
, NULL
);
291 SAFE_FREE(response
->extra_data
.data
);
292 talloc_destroy(state
->mem_ctx
);
295 /********************************************************************
296 Periodically we need to refresh the trusted domain cache for smbd
297 ********************************************************************/
299 void rescan_trusted_domains( void )
301 time_t now
= time(NULL
);
303 /* see if the time has come... */
305 if ((now
>= last_trustdom_scan
) &&
306 ((now
-last_trustdom_scan
) < WINBINDD_RESCAN_FREQ
) )
309 /* this will only add new domains we didn't already know about */
311 add_trusted_domains( find_our_domain() );
313 last_trustdom_scan
= now
;
318 struct init_child_state
{
320 struct winbindd_domain
*domain
;
321 struct winbindd_request
*request
;
322 struct winbindd_response
*response
;
323 void (*continuation
)(void *private_data
, BOOL success
);
327 static void init_child_recv(void *private_data
, BOOL success
);
328 static void init_child_getdc_recv(void *private_data
, BOOL success
);
330 enum winbindd_result
init_child_connection(struct winbindd_domain
*domain
,
331 void (*continuation
)(void *private_data
,
336 struct winbindd_request
*request
;
337 struct winbindd_response
*response
;
338 struct init_child_state
*state
;
339 struct winbindd_domain
*request_domain
;
341 mem_ctx
= talloc_init("init_child_connection");
342 if (mem_ctx
== NULL
) {
343 DEBUG(0, ("talloc_init failed\n"));
344 return WINBINDD_ERROR
;
347 request
= TALLOC_ZERO_P(mem_ctx
, struct winbindd_request
);
348 response
= TALLOC_P(mem_ctx
, struct winbindd_response
);
349 state
= TALLOC_P(mem_ctx
, struct init_child_state
);
351 if ((request
== NULL
) || (response
== NULL
) || (state
== NULL
)) {
352 DEBUG(0, ("talloc failed\n"));
353 TALLOC_FREE(mem_ctx
);
354 continuation(private_data
, False
);
355 return WINBINDD_ERROR
;
358 request
->length
= sizeof(*request
);
360 state
->mem_ctx
= mem_ctx
;
361 state
->domain
= domain
;
362 state
->request
= request
;
363 state
->response
= response
;
364 state
->continuation
= continuation
;
365 state
->private_data
= private_data
;
367 if (IS_DC
|| domain
->primary
) {
368 /* The primary domain has to find the DC name itself */
369 request
->cmd
= WINBINDD_INIT_CONNECTION
;
370 fstrcpy(request
->domain_name
, domain
->name
);
371 request
->data
.init_conn
.is_primary
= True
;
372 fstrcpy(request
->data
.init_conn
.dcname
, "");
373 async_request(mem_ctx
, &domain
->child
, request
, response
,
374 init_child_recv
, state
);
375 return WINBINDD_PENDING
;
378 /* This is *not* the primary domain, let's ask our DC about a DC
381 request
->cmd
= WINBINDD_GETDCNAME
;
382 fstrcpy(request
->domain_name
, domain
->name
);
384 /* save online flag */
385 request_domain
= find_our_domain();
386 request_domain
->online
= domain
->online
;
388 async_domain_request(mem_ctx
, request_domain
, request
, response
,
389 init_child_getdc_recv
, state
);
390 return WINBINDD_PENDING
;
393 static void init_child_getdc_recv(void *private_data
, BOOL success
)
395 struct init_child_state
*state
=
396 talloc_get_type_abort(private_data
, struct init_child_state
);
397 const char *dcname
= "";
399 DEBUG(10, ("Received getdcname response\n"));
401 if (success
&& (state
->response
->result
== WINBINDD_OK
)) {
402 dcname
= state
->response
->data
.dc_name
;
405 state
->request
->cmd
= WINBINDD_INIT_CONNECTION
;
406 fstrcpy(state
->request
->domain_name
, state
->domain
->name
);
407 state
->request
->data
.init_conn
.is_primary
= False
;
408 fstrcpy(state
->request
->data
.init_conn
.dcname
, dcname
);
410 async_request(state
->mem_ctx
, &state
->domain
->child
,
411 state
->request
, state
->response
,
412 init_child_recv
, state
);
415 static void init_child_recv(void *private_data
, BOOL success
)
417 struct init_child_state
*state
=
418 talloc_get_type_abort(private_data
, struct init_child_state
);
420 DEBUG(5, ("Received child initialization response for domain %s\n",
421 state
->domain
->name
));
423 if ((!success
) || (state
->response
->result
!= WINBINDD_OK
)) {
424 DEBUG(3, ("Could not init child\n"));
425 state
->continuation(state
->private_data
, False
);
426 talloc_destroy(state
->mem_ctx
);
430 fstrcpy(state
->domain
->name
,
431 state
->response
->data
.domain_info
.name
);
432 fstrcpy(state
->domain
->alt_name
,
433 state
->response
->data
.domain_info
.alt_name
);
434 string_to_sid(&state
->domain
->sid
,
435 state
->response
->data
.domain_info
.sid
);
436 state
->domain
->native_mode
=
437 state
->response
->data
.domain_info
.native_mode
;
438 state
->domain
->active_directory
=
439 state
->response
->data
.domain_info
.active_directory
;
440 state
->domain
->sequence_number
=
441 state
->response
->data
.domain_info
.sequence_number
;
443 state
->domain
->initialized
= 1;
445 if (state
->continuation
!= NULL
)
446 state
->continuation(state
->private_data
, True
);
447 talloc_destroy(state
->mem_ctx
);
450 enum winbindd_result
winbindd_dual_init_connection(struct winbindd_domain
*domain
,
451 struct winbindd_cli_state
*state
)
453 struct in_addr ipaddr
;
455 /* Ensure null termination */
456 state
->request
.domain_name
457 [sizeof(state
->request
.domain_name
)-1]='\0';
458 state
->request
.data
.init_conn
.dcname
459 [sizeof(state
->request
.data
.init_conn
.dcname
)-1]='\0';
461 if (strlen(state
->request
.data
.init_conn
.dcname
) > 0) {
462 fstrcpy(domain
->dcname
, state
->request
.data
.init_conn
.dcname
);
465 if (strlen(domain
->dcname
) > 0) {
466 if (!resolve_name(domain
->dcname
, &ipaddr
, 0x20)) {
467 DEBUG(2, ("Could not resolve DC name %s for domain %s\n",
468 domain
->dcname
, domain
->name
));
469 return WINBINDD_ERROR
;
472 domain
->dcaddr
.sin_family
= PF_INET
;
473 putip((char *)&(domain
->dcaddr
.sin_addr
), (char *)&ipaddr
);
474 domain
->dcaddr
.sin_port
= 0;
477 init_dc_connection(domain
);
480 if (!domain
->initialized
) {
481 /* If we return error here we can't do any cached authentication,
482 but we may be in disconnected mode and can't initialize correctly.
483 Do what the previous code did and just return without initialization,
484 once we go online we'll re-initialize.
486 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
487 "online = %d\n", domain
->name
, (int)domain
->online
));
490 if (!domain
->initialized
) {
491 DEBUG(1, ("Could not initialize domain %s\n",
492 state
->request
.domain_name
));
493 return WINBINDD_ERROR
;
497 fstrcpy(state
->response
.data
.domain_info
.name
, domain
->name
);
498 fstrcpy(state
->response
.data
.domain_info
.alt_name
, domain
->alt_name
);
499 fstrcpy(state
->response
.data
.domain_info
.sid
,
500 sid_string_static(&domain
->sid
));
502 state
->response
.data
.domain_info
.native_mode
503 = domain
->native_mode
;
504 state
->response
.data
.domain_info
.active_directory
505 = domain
->active_directory
;
506 state
->response
.data
.domain_info
.primary
508 state
->response
.data
.domain_info
.sequence_number
=
509 domain
->sequence_number
;
514 /* Look up global info for the winbind daemon */
515 BOOL
init_domain_list(void)
517 extern struct winbindd_methods cache_methods
;
518 extern struct winbindd_methods passdb_methods
;
519 struct winbindd_domain
*domain
;
520 int role
= lp_server_role();
522 /* Free existing list */
525 /* Add ourselves as the first entry. */
527 if ( role
== ROLE_DOMAIN_MEMBER
) {
530 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid
)) {
531 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
535 domain
= add_trusted_domain( lp_workgroup(), lp_realm(),
536 &cache_methods
, &our_sid
);
537 domain
->primary
= True
;
538 setup_domain_child(domain
, &domain
->child
, NULL
);
543 domain
= add_trusted_domain(get_global_sam_name(), NULL
,
544 &passdb_methods
, get_global_sam_sid());
545 if ( role
!= ROLE_DOMAIN_MEMBER
) {
546 domain
->primary
= True
;
548 setup_domain_child(domain
, &domain
->child
, NULL
);
552 domain
= add_trusted_domain("BUILTIN", NULL
, &passdb_methods
,
553 &global_sid_Builtin
);
554 setup_domain_child(domain
, &domain
->child
, NULL
);
560 * Given a domain name, return the struct winbindd domain info for it
562 * @note Do *not* pass lp_workgroup() to this function. domain_list
563 * may modify it's value, and free that pointer. Instead, our local
564 * domain may be found by calling find_our_domain().
568 * @return The domain structure for the named domain, if it is working.
571 struct winbindd_domain
*find_domain_from_name_noinit(const char *domain_name
)
573 struct winbindd_domain
*domain
;
575 /* Search through list */
577 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
578 if (strequal(domain_name
, domain
->name
) ||
579 (domain
->alt_name
[0] &&
580 strequal(domain_name
, domain
->alt_name
))) {
590 struct winbindd_domain
*find_domain_from_name(const char *domain_name
)
592 struct winbindd_domain
*domain
;
594 domain
= find_domain_from_name_noinit(domain_name
);
599 if (!domain
->initialized
)
600 init_dc_connection(domain
);
605 /* Given a domain sid, return the struct winbindd domain info for it */
607 struct winbindd_domain
*find_domain_from_sid_noinit(const DOM_SID
*sid
)
609 struct winbindd_domain
*domain
;
611 /* Search through list */
613 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
614 if (sid_compare_domain(sid
, &domain
->sid
) == 0)
623 /* Given a domain sid, return the struct winbindd domain info for it */
625 struct winbindd_domain
*find_domain_from_sid(const DOM_SID
*sid
)
627 struct winbindd_domain
*domain
;
629 domain
= find_domain_from_sid_noinit(sid
);
634 if (!domain
->initialized
)
635 init_dc_connection(domain
);
640 struct winbindd_domain
*find_our_domain(void)
642 struct winbindd_domain
*domain
;
644 /* Search through list */
646 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
651 smb_panic("Could not find our domain\n");
655 struct winbindd_domain
*find_builtin_domain(void)
658 struct winbindd_domain
*domain
;
660 string_to_sid(&sid
, "S-1-5-32");
661 domain
= find_domain_from_sid(&sid
);
664 smb_panic("Could not find BUILTIN domain\n");
669 /* Find the appropriate domain to lookup a name or SID */
671 struct winbindd_domain
*find_lookup_domain_from_sid(const DOM_SID
*sid
)
673 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
674 * one to contact the external DC's. On member servers the internal
675 * domains are different: These are part of the local SAM. */
677 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n",
678 sid_string_static(sid
)));
680 if (IS_DC
|| is_internal_domain(sid
) || is_in_internal_domain(sid
)) {
681 DEBUG(10, ("calling find_domain_from_sid\n"));
682 return find_domain_from_sid(sid
);
685 /* On a member server a query for SID or name can always go to our
688 DEBUG(10, ("calling find_our_domain\n"));
689 return find_our_domain();
692 struct winbindd_domain
*find_lookup_domain_from_name(const char *domain_name
)
694 if (IS_DC
|| strequal(domain_name
, "BUILTIN") ||
695 strequal(domain_name
, get_global_sam_name()))
696 return find_domain_from_name_noinit(domain_name
);
698 return find_our_domain();
701 /* Lookup a sid in a domain from a name */
703 BOOL
winbindd_lookup_sid_by_name(TALLOC_CTX
*mem_ctx
,
704 struct winbindd_domain
*domain
,
705 const char *domain_name
,
706 const char *name
, DOM_SID
*sid
,
707 enum lsa_SidType
*type
)
712 result
= domain
->methods
->name_to_sid(domain
, mem_ctx
, domain_name
, name
, sid
, type
);
714 /* Return rid and type if lookup successful */
715 if (!NT_STATUS_IS_OK(result
)) {
716 *type
= SID_NAME_UNKNOWN
;
719 return NT_STATUS_IS_OK(result
);
723 * @brief Lookup a name in a domain from a sid.
725 * @param sid Security ID you want to look up.
726 * @param name On success, set to the name corresponding to @p sid.
727 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
728 * @param type On success, contains the type of name: alias, group or
730 * @retval True if the name exists, in which case @p name and @p type
731 * are set, otherwise False.
733 BOOL
winbindd_lookup_name_by_sid(TALLOC_CTX
*mem_ctx
,
737 enum lsa_SidType
*type
)
743 struct winbindd_domain
*domain
;
745 domain
= find_lookup_domain_from_sid(sid
);
748 DEBUG(1,("Can't find domain from sid\n"));
754 result
= domain
->methods
->sid_to_name(domain
, mem_ctx
, sid
, &dom_names
, &names
, type
);
756 /* Return name and type if successful */
758 if ((rv
= NT_STATUS_IS_OK(result
))) {
759 fstrcpy(dom_name
, dom_names
);
760 fstrcpy(name
, names
);
762 *type
= SID_NAME_UNKNOWN
;
763 fstrcpy(name
, name_deadbeef
);
769 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
771 void free_getent_state(struct getent_state
*state
)
773 struct getent_state
*temp
;
775 /* Iterate over state list */
779 while(temp
!= NULL
) {
780 struct getent_state
*next
;
782 /* Free sam entries then list entry */
784 SAFE_FREE(state
->sam_entries
);
785 DLIST_REMOVE(state
, state
);
793 /* Parse winbindd related parameters */
795 BOOL
winbindd_param_init(void)
797 /* Parse winbind uid and winbind_gid parameters */
799 if (!lp_idmap_uid(&server_state
.uid_low
, &server_state
.uid_high
)) {
800 DEBUG(0, ("winbindd: idmap uid range missing or invalid\n"));
801 DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
805 if (!lp_idmap_gid(&server_state
.gid_low
, &server_state
.gid_high
)) {
806 DEBUG(0, ("winbindd: idmap gid range missing or invalid\n"));
807 DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
814 BOOL
is_in_uid_range(uid_t uid
)
816 return ((uid
>= server_state
.uid_low
) &&
817 (uid
<= server_state
.uid_high
));
820 BOOL
is_in_gid_range(gid_t gid
)
822 return ((gid
>= server_state
.gid_low
) &&
823 (gid
<= server_state
.gid_high
));
826 /* Is this a domain which we may assume no DOMAIN\ prefix? */
828 static BOOL
assume_domain(const char *domain
)
830 /* never assume the domain on a standalone server */
832 if ( lp_server_role() == ROLE_STANDALONE
)
835 /* domain member servers may possibly assume for the domain name */
837 if ( lp_server_role() == ROLE_DOMAIN_MEMBER
) {
838 if ( !strequal(lp_workgroup(), domain
) )
841 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
845 /* only left with a domain controller */
847 if ( strequal(get_global_sam_name(), domain
) ) {
854 /* Parse a string of the form DOMAIN\user into a domain and a user */
856 BOOL
parse_domain_user(const char *domuser
, fstring domain
, fstring user
)
858 char *p
= strchr(domuser
,*lp_winbind_separator());
861 fstrcpy(user
, domuser
);
863 if ( assume_domain(lp_workgroup())) {
864 fstrcpy(domain
, lp_workgroup());
870 fstrcpy(domain
, domuser
);
871 domain
[PTR_DIFF(p
, domuser
)] = 0;
879 BOOL
parse_domain_user_talloc(TALLOC_CTX
*mem_ctx
, const char *domuser
,
880 char **domain
, char **user
)
882 fstring fstr_domain
, fstr_user
;
883 if (!parse_domain_user(domuser
, fstr_domain
, fstr_user
)) {
886 *domain
= talloc_strdup(mem_ctx
, fstr_domain
);
887 *user
= talloc_strdup(mem_ctx
, fstr_user
);
888 return ((*domain
!= NULL
) && (*user
!= NULL
));
892 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
893 'winbind separator' options.
895 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
898 If we are a PDC or BDC, and this is for our domain, do likewise.
900 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
901 username is then unqualified in unix
903 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
905 void fill_domain_username(fstring name
, const char *domain
, const char *user
, BOOL can_assume
)
909 fstrcpy(tmp_user
, user
);
910 strlower_m(tmp_user
);
912 if (can_assume
&& assume_domain(domain
)) {
913 strlcpy(name
, tmp_user
, sizeof(fstring
));
915 slprintf(name
, sizeof(fstring
) - 1, "%s%c%s",
916 domain
, *lp_winbind_separator(),
922 * Winbindd socket accessor functions
925 char *get_winbind_priv_pipe_dir(void)
927 return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR
);
930 /* Open the winbindd socket */
932 static int _winbindd_socket
= -1;
933 static int _winbindd_priv_socket
= -1;
935 int open_winbindd_socket(void)
937 if (_winbindd_socket
== -1) {
938 _winbindd_socket
= create_pipe_sock(
939 WINBINDD_SOCKET_DIR
, WINBINDD_SOCKET_NAME
, 0755);
940 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
944 return _winbindd_socket
;
947 int open_winbindd_priv_socket(void)
949 if (_winbindd_priv_socket
== -1) {
950 _winbindd_priv_socket
= create_pipe_sock(
951 get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME
, 0750);
952 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
953 _winbindd_priv_socket
));
956 return _winbindd_priv_socket
;
959 /* Close the winbindd socket */
961 void close_winbindd_socket(void)
963 if (_winbindd_socket
!= -1) {
964 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
966 close(_winbindd_socket
);
967 _winbindd_socket
= -1;
969 if (_winbindd_priv_socket
!= -1) {
970 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
971 _winbindd_priv_socket
));
972 close(_winbindd_priv_socket
);
973 _winbindd_priv_socket
= -1;
978 * Client list accessor functions
981 static struct winbindd_cli_state
*_client_list
;
982 static int _num_clients
;
984 /* Return list of all connected clients */
986 struct winbindd_cli_state
*winbindd_client_list(void)
991 /* Add a connection to the list */
993 void winbindd_add_client(struct winbindd_cli_state
*cli
)
995 DLIST_ADD(_client_list
, cli
);
999 /* Remove a client from the list */
1001 void winbindd_remove_client(struct winbindd_cli_state
*cli
)
1003 DLIST_REMOVE(_client_list
, cli
);
1007 /* Close all open clients */
1009 void winbindd_kill_all_clients(void)
1011 struct winbindd_cli_state
*cl
= winbindd_client_list();
1013 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1016 struct winbindd_cli_state
*next
;
1019 winbindd_remove_client(cl
);
1024 /* Return number of open clients */
1026 int winbindd_num_clients(void)
1028 return _num_clients
;
1031 /*****************************************************************************
1032 For idmap conversion: convert one record to new format
1033 Ancient versions (eg 2.2.3a) of winbindd_idmap.tdb mapped DOMAINNAME/rid
1035 *****************************************************************************/
1036 static int convert_fn(TDB_CONTEXT
*tdb
, TDB_DATA key
, TDB_DATA data
, void *state
)
1038 struct winbindd_domain
*domain
;
1045 BOOL
*failed
= (BOOL
*)state
;
1047 DEBUG(10,("Converting %s\n", key
.dptr
));
1049 p
= strchr(key
.dptr
, '/');
1054 fstrcpy(dom_name
, key
.dptr
);
1057 domain
= find_domain_from_name(dom_name
);
1058 if (domain
== NULL
) {
1059 /* We must delete the old record. */
1060 DEBUG(0,("Unable to find domain %s\n", dom_name
));
1061 DEBUG(0,("deleting record %s\n", key
.dptr
));
1063 if (tdb_delete(tdb
, key
) != 0) {
1064 DEBUG(0, ("Unable to delete record %s\n", key
.dptr
));
1074 sid_copy(&sid
, &domain
->sid
);
1075 sid_append_rid(&sid
, rid
);
1077 sid_to_string(keystr
, &sid
);
1079 key2
.dsize
= strlen(keystr
) + 1;
1081 if (tdb_store(tdb
, key2
, data
, TDB_INSERT
) != 0) {
1082 DEBUG(0,("Unable to add record %s\n", key2
.dptr
));
1087 if (tdb_store(tdb
, data
, key2
, TDB_REPLACE
) != 0) {
1088 DEBUG(0,("Unable to update record %s\n", data
.dptr
));
1093 if (tdb_delete(tdb
, key
) != 0) {
1094 DEBUG(0,("Unable to delete record %s\n", key
.dptr
));
1102 /* These definitions are from sam/idmap_tdb.c. Replicated here just
1103 out of laziness.... :-( */
1105 /* High water mark keys */
1106 #define HWM_GROUP "GROUP HWM"
1107 #define HWM_USER "USER HWM"
1109 /*****************************************************************************
1110 Convert the idmap database from an older version.
1111 *****************************************************************************/
1113 static BOOL
idmap_convert(const char *idmap_name
)
1116 BOOL bigendianheader
;
1117 BOOL failed
= False
;
1118 TDB_CONTEXT
*idmap_tdb
;
1120 if (!(idmap_tdb
= tdb_open_log(idmap_name
, 0,
1121 TDB_DEFAULT
, O_RDWR
,
1123 DEBUG(0, ("idmap_convert: Unable to open idmap database\n"));
1127 bigendianheader
= (tdb_get_flags(idmap_tdb
) & TDB_BIGENDIAN
) ? True
: False
;
1129 vers
= tdb_fetch_int32(idmap_tdb
, "IDMAP_VERSION");
1131 if (((vers
== -1) && bigendianheader
) || (IREV(vers
) == IDMAP_VERSION
)) {
1132 /* Arrggghh ! Bytereversed or old big-endian - make order independent ! */
1134 * high and low records were created on a
1135 * big endian machine and will need byte-reversing.
1140 wm
= tdb_fetch_int32(idmap_tdb
, HWM_USER
);
1145 wm
= server_state
.uid_low
;
1148 if (tdb_store_int32(idmap_tdb
, HWM_USER
, wm
) == -1) {
1149 DEBUG(0, ("idmap_convert: Unable to byteswap user hwm in idmap database\n"));
1150 tdb_close(idmap_tdb
);
1154 wm
= tdb_fetch_int32(idmap_tdb
, HWM_GROUP
);
1158 wm
= server_state
.gid_low
;
1161 if (tdb_store_int32(idmap_tdb
, HWM_GROUP
, wm
) == -1) {
1162 DEBUG(0, ("idmap_convert: Unable to byteswap group hwm in idmap database\n"));
1163 tdb_close(idmap_tdb
);
1168 /* the old format stored as DOMAIN/rid - now we store the SID direct */
1169 tdb_traverse(idmap_tdb
, convert_fn
, &failed
);
1172 DEBUG(0, ("Problem during conversion\n"));
1173 tdb_close(idmap_tdb
);
1177 if (tdb_store_int32(idmap_tdb
, "IDMAP_VERSION", IDMAP_VERSION
) == -1) {
1178 DEBUG(0, ("idmap_convert: Unable to dtore idmap version in databse\n"));
1179 tdb_close(idmap_tdb
);
1183 tdb_close(idmap_tdb
);
1187 /*****************************************************************************
1188 Convert the idmap database from an older version if necessary
1189 *****************************************************************************/
1191 BOOL
winbindd_upgrade_idmap(void)
1194 pstring backup_name
;
1195 SMB_STRUCT_STAT stbuf
;
1196 TDB_CONTEXT
*idmap_tdb
;
1198 pstrcpy(idmap_name
, lock_path("winbindd_idmap.tdb"));
1200 if (!file_exist(idmap_name
, &stbuf
)) {
1201 /* nothing to convert return */
1205 if (!(idmap_tdb
= tdb_open_log(idmap_name
, 0,
1206 TDB_DEFAULT
, O_RDWR
,
1208 DEBUG(0, ("idmap_convert: Unable to open idmap database\n"));
1212 if (tdb_fetch_int32(idmap_tdb
, "IDMAP_VERSION") == IDMAP_VERSION
) {
1213 /* nothing to convert return */
1214 tdb_close(idmap_tdb
);
1218 /* backup_tdb expects the tdb not to be open */
1219 tdb_close(idmap_tdb
);
1221 DEBUG(0, ("Upgrading winbindd_idmap.tdb from an old version\n"));
1223 pstrcpy(backup_name
, idmap_name
);
1224 pstrcat(backup_name
, ".bak");
1226 if (backup_tdb(idmap_name
, backup_name
) != 0) {
1227 DEBUG(0, ("Could not backup idmap database\n"));
1231 return idmap_convert(idmap_name
);
1234 NTSTATUS
lookup_usergroups_cached(struct winbindd_domain
*domain
,
1235 TALLOC_CTX
*mem_ctx
,
1236 const DOM_SID
*user_sid
,
1237 uint32
*p_num_groups
, DOM_SID
**user_sids
)
1239 NET_USER_INFO_3
*info3
= NULL
;
1240 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1242 size_t num_groups
= 0;
1243 DOM_SID group_sid
, primary_group
;
1245 DEBUG(3,(": lookup_usergroups_cached\n"));
1251 info3
= netsamlogon_cache_get(mem_ctx
, user_sid
);
1253 if (info3
== NULL
) {
1254 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1257 if (info3
->num_groups
== 0) {
1259 return NT_STATUS_UNSUCCESSFUL
;
1262 /* always add the primary group to the sid array */
1263 sid_compose(&primary_group
, &info3
->dom_sid
.sid
, info3
->user_rid
);
1265 add_sid_to_array(mem_ctx
, &primary_group
, user_sids
, &num_groups
);
1267 for (i
=0; i
<info3
->num_groups
; i
++) {
1268 sid_copy(&group_sid
, &info3
->dom_sid
.sid
);
1269 sid_append_rid(&group_sid
, info3
->gids
[i
].g_rid
);
1271 add_sid_to_array(mem_ctx
, &group_sid
, user_sids
,
1276 *p_num_groups
= num_groups
;
1277 status
= (user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
1279 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));