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
30 extern struct winbindd_methods cache_methods
;
31 extern struct winbindd_methods passdb_methods
;
34 * @file winbindd_util.c
36 * Winbind daemon for NT domain authentication nss module.
41 * Used to clobber name fields that have an undefined value.
43 * Correct code should never look at a field that has this value.
46 static const fstring name_deadbeef
= "<deadbeef>";
48 /* The list of trusted domains. Note that the list can be deleted and
49 recreated using the init_domain_list() function so pointers to
50 individual winbindd_domain structures cannot be made. Keep a copy of
51 the domain name instead. */
53 static struct winbindd_domain
*_domain_list
;
56 When was the last scan of trusted domains done?
61 static time_t last_trustdom_scan
;
63 struct winbindd_domain
*domain_list(void)
67 if ((!_domain_list
) && (!init_domain_list())) {
68 smb_panic("Init_domain_list failed\n");
74 /* Free all entries in the trusted domain list */
76 void free_domain_list(void)
78 struct winbindd_domain
*domain
= _domain_list
;
81 struct winbindd_domain
*next
= domain
->next
;
83 DLIST_REMOVE(_domain_list
, domain
);
89 static BOOL
is_internal_domain(const DOM_SID
*sid
)
94 return (sid_check_is_domain(sid
) || sid_check_is_builtin(sid
));
97 static BOOL
is_in_internal_domain(const DOM_SID
*sid
)
102 return (sid_check_is_in_our_domain(sid
) || sid_check_is_in_builtin(sid
));
106 /* Add a trusted domain to our list of domains */
107 static struct winbindd_domain
*add_trusted_domain(const char *domain_name
, const char *alt_name
,
108 struct winbindd_methods
*methods
,
111 struct winbindd_domain
*domain
;
112 const char *alternative_name
= NULL
;
114 /* ignore alt_name if we are not in an AD domain */
116 if ( (lp_security() == SEC_ADS
) && alt_name
&& *alt_name
) {
117 alternative_name
= alt_name
;
120 /* We can't call domain_list() as this function is called from
121 init_domain_list() and we'll get stuck in a loop. */
122 for (domain
= _domain_list
; domain
; domain
= domain
->next
) {
123 if (strequal(domain_name
, domain
->name
) ||
124 strequal(domain_name
, domain
->alt_name
)) {
127 if (alternative_name
&& *alternative_name
) {
128 if (strequal(alternative_name
, domain
->name
) ||
129 strequal(alternative_name
, domain
->alt_name
)) {
134 if (is_null_sid(sid
)) {
136 } else if (sid_equal(sid
, &domain
->sid
)) {
142 /* Create new domain entry */
144 if ((domain
= SMB_MALLOC_P(struct winbindd_domain
)) == NULL
)
149 ZERO_STRUCTP(domain
);
151 /* prioritise the short name */
152 if (strchr_m(domain_name
, '.') && alternative_name
&& *alternative_name
) {
153 fstrcpy(domain
->name
, alternative_name
);
154 fstrcpy(domain
->alt_name
, domain_name
);
156 fstrcpy(domain
->name
, domain_name
);
157 if (alternative_name
) {
158 fstrcpy(domain
->alt_name
, alternative_name
);
162 domain
->methods
= methods
;
163 domain
->backend
= NULL
;
164 domain
->internal
= is_internal_domain(sid
);
165 domain
->sequence_number
= DOM_SEQUENCE_NONE
;
166 domain
->last_seq_check
= 0;
167 domain
->initialized
= False
;
168 domain
->online
= is_internal_domain(sid
);
169 domain
->check_online_timeout
= 0;
171 sid_copy(&domain
->sid
, sid
);
174 /* Link to domain list */
175 DLIST_ADD(_domain_list
, domain
);
177 DEBUG(2,("Added domain %s %s %s\n",
178 domain
->name
, domain
->alt_name
,
179 &domain
->sid
?sid_string_static(&domain
->sid
):""));
184 /********************************************************************
185 rescan our domains looking for new trusted domains
186 ********************************************************************/
188 struct trustdom_state
{
190 struct winbindd_response
*response
;
193 static void trustdom_recv(void *private_data
, BOOL success
);
195 static void add_trusted_domains( struct winbindd_domain
*domain
)
198 struct winbindd_request
*request
;
199 struct winbindd_response
*response
;
201 struct trustdom_state
*state
;
203 mem_ctx
= talloc_init("add_trusted_domains");
204 if (mem_ctx
== NULL
) {
205 DEBUG(0, ("talloc_init failed\n"));
209 request
= TALLOC_ZERO_P(mem_ctx
, struct winbindd_request
);
210 response
= TALLOC_P(mem_ctx
, struct winbindd_response
);
211 state
= TALLOC_P(mem_ctx
, struct trustdom_state
);
213 if ((request
== NULL
) || (response
== NULL
) || (state
== NULL
)) {
214 DEBUG(0, ("talloc failed\n"));
215 talloc_destroy(mem_ctx
);
219 state
->mem_ctx
= mem_ctx
;
220 state
->response
= response
;
222 request
->length
= sizeof(*request
);
223 request
->cmd
= WINBINDD_LIST_TRUSTDOM
;
225 async_domain_request(mem_ctx
, domain
, request
, response
,
226 trustdom_recv
, state
);
229 static void trustdom_recv(void *private_data
, BOOL success
)
231 struct trustdom_state
*state
=
232 talloc_get_type_abort(private_data
, struct trustdom_state
);
233 struct winbindd_response
*response
= state
->response
;
236 if ((!success
) || (response
->result
!= WINBINDD_OK
)) {
237 DEBUG(1, ("Could not receive trustdoms\n"));
238 talloc_destroy(state
->mem_ctx
);
242 p
= (char *)response
->extra_data
.data
;
244 while ((p
!= NULL
) && (*p
!= '\0')) {
245 char *q
, *sidstr
, *alt_name
;
248 alt_name
= strchr(p
, '\\');
249 if (alt_name
== NULL
) {
250 DEBUG(0, ("Got invalid trustdom response\n"));
257 sidstr
= strchr(alt_name
, '\\');
258 if (sidstr
== NULL
) {
259 DEBUG(0, ("Got invalid trustdom response\n"));
266 q
= strchr(sidstr
, '\n');
270 if (!string_to_sid(&sid
, sidstr
)) {
271 /* Allow NULL sid for sibling domains */
272 if ( strcmp(sidstr
,"S-0-0") == 0) {
273 sid_copy( &sid
, &global_sid_NULL
);
275 DEBUG(0, ("Got invalid trustdom response\n"));
280 if (find_domain_from_name_noinit(p
) == NULL
) {
281 struct winbindd_domain
*domain
;
282 char *alternate_name
= NULL
;
284 /* use the real alt_name if we have one, else pass in NULL */
286 if ( !strequal( alt_name
, "(null)" ) )
287 alternate_name
= alt_name
;
289 domain
= add_trusted_domain(p
, alternate_name
,
292 setup_domain_child(domain
, &domain
->child
, NULL
);
299 SAFE_FREE(response
->extra_data
.data
);
300 talloc_destroy(state
->mem_ctx
);
303 /********************************************************************
304 Periodically we need to refresh the trusted domain cache for smbd
305 ********************************************************************/
307 void rescan_trusted_domains( void )
309 time_t now
= time(NULL
);
311 /* see if the time has come... */
313 if ((now
>= last_trustdom_scan
) &&
314 ((now
-last_trustdom_scan
) < WINBINDD_RESCAN_FREQ
) )
317 /* this will only add new domains we didn't already know about */
319 add_trusted_domains( find_our_domain() );
321 last_trustdom_scan
= now
;
326 struct init_child_state
{
328 struct winbindd_domain
*domain
;
329 struct winbindd_request
*request
;
330 struct winbindd_response
*response
;
331 void (*continuation
)(void *private_data
, BOOL success
);
335 static void init_child_recv(void *private_data
, BOOL success
);
336 static void init_child_getdc_recv(void *private_data
, BOOL success
);
338 enum winbindd_result
init_child_connection(struct winbindd_domain
*domain
,
339 void (*continuation
)(void *private_data
,
344 struct winbindd_request
*request
;
345 struct winbindd_response
*response
;
346 struct init_child_state
*state
;
347 struct winbindd_domain
*request_domain
;
349 mem_ctx
= talloc_init("init_child_connection");
350 if (mem_ctx
== NULL
) {
351 DEBUG(0, ("talloc_init failed\n"));
352 return WINBINDD_ERROR
;
355 request
= TALLOC_ZERO_P(mem_ctx
, struct winbindd_request
);
356 response
= TALLOC_P(mem_ctx
, struct winbindd_response
);
357 state
= TALLOC_P(mem_ctx
, struct init_child_state
);
359 if ((request
== NULL
) || (response
== NULL
) || (state
== NULL
)) {
360 DEBUG(0, ("talloc failed\n"));
361 TALLOC_FREE(mem_ctx
);
362 continuation(private_data
, False
);
363 return WINBINDD_ERROR
;
366 request
->length
= sizeof(*request
);
368 state
->mem_ctx
= mem_ctx
;
369 state
->domain
= domain
;
370 state
->request
= request
;
371 state
->response
= response
;
372 state
->continuation
= continuation
;
373 state
->private_data
= private_data
;
375 if (IS_DC
|| domain
->primary
) {
376 /* The primary domain has to find the DC name itself */
377 request
->cmd
= WINBINDD_INIT_CONNECTION
;
378 fstrcpy(request
->domain_name
, domain
->name
);
379 request
->data
.init_conn
.is_primary
= True
;
380 fstrcpy(request
->data
.init_conn
.dcname
, "");
381 async_request(mem_ctx
, &domain
->child
, request
, response
,
382 init_child_recv
, state
);
383 return WINBINDD_PENDING
;
386 /* This is *not* the primary domain, let's ask our DC about a DC
389 request
->cmd
= WINBINDD_GETDCNAME
;
390 fstrcpy(request
->domain_name
, domain
->name
);
392 /* save online flag */
393 request_domain
= find_our_domain();
394 request_domain
->online
= domain
->online
;
396 async_domain_request(mem_ctx
, request_domain
, request
, response
,
397 init_child_getdc_recv
, state
);
398 return WINBINDD_PENDING
;
401 static void init_child_getdc_recv(void *private_data
, BOOL success
)
403 struct init_child_state
*state
=
404 talloc_get_type_abort(private_data
, struct init_child_state
);
405 const char *dcname
= "";
407 DEBUG(10, ("Received getdcname response\n"));
409 if (success
&& (state
->response
->result
== WINBINDD_OK
)) {
410 dcname
= state
->response
->data
.dc_name
;
413 state
->request
->cmd
= WINBINDD_INIT_CONNECTION
;
414 fstrcpy(state
->request
->domain_name
, state
->domain
->name
);
415 state
->request
->data
.init_conn
.is_primary
= False
;
416 fstrcpy(state
->request
->data
.init_conn
.dcname
, dcname
);
418 async_request(state
->mem_ctx
, &state
->domain
->child
,
419 state
->request
, state
->response
,
420 init_child_recv
, state
);
423 static void init_child_recv(void *private_data
, BOOL success
)
425 struct init_child_state
*state
=
426 talloc_get_type_abort(private_data
, struct init_child_state
);
428 DEBUG(5, ("Received child initialization response for domain %s\n",
429 state
->domain
->name
));
431 if ((!success
) || (state
->response
->result
!= WINBINDD_OK
)) {
432 DEBUG(3, ("Could not init child\n"));
433 state
->continuation(state
->private_data
, False
);
434 talloc_destroy(state
->mem_ctx
);
438 fstrcpy(state
->domain
->name
,
439 state
->response
->data
.domain_info
.name
);
440 fstrcpy(state
->domain
->alt_name
,
441 state
->response
->data
.domain_info
.alt_name
);
442 string_to_sid(&state
->domain
->sid
,
443 state
->response
->data
.domain_info
.sid
);
444 state
->domain
->native_mode
=
445 state
->response
->data
.domain_info
.native_mode
;
446 state
->domain
->active_directory
=
447 state
->response
->data
.domain_info
.active_directory
;
448 state
->domain
->sequence_number
=
449 state
->response
->data
.domain_info
.sequence_number
;
451 init_dc_connection(state
->domain
);
453 if (state
->continuation
!= NULL
)
454 state
->continuation(state
->private_data
, True
);
455 talloc_destroy(state
->mem_ctx
);
458 enum winbindd_result
winbindd_dual_init_connection(struct winbindd_domain
*domain
,
459 struct winbindd_cli_state
*state
)
461 /* Ensure null termination */
462 state
->request
.domain_name
463 [sizeof(state
->request
.domain_name
)-1]='\0';
464 state
->request
.data
.init_conn
.dcname
465 [sizeof(state
->request
.data
.init_conn
.dcname
)-1]='\0';
467 if (strlen(state
->request
.data
.init_conn
.dcname
) > 0) {
468 fstrcpy(domain
->dcname
, state
->request
.data
.init_conn
.dcname
);
471 init_dc_connection(domain
);
473 if (!domain
->initialized
) {
474 /* If we return error here we can't do any cached authentication,
475 but we may be in disconnected mode and can't initialize correctly.
476 Do what the previous code did and just return without initialization,
477 once we go online we'll re-initialize.
479 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
480 "online = %d\n", domain
->name
, (int)domain
->online
));
483 fstrcpy(state
->response
.data
.domain_info
.name
, domain
->name
);
484 fstrcpy(state
->response
.data
.domain_info
.alt_name
, domain
->alt_name
);
485 fstrcpy(state
->response
.data
.domain_info
.sid
,
486 sid_string_static(&domain
->sid
));
488 state
->response
.data
.domain_info
.native_mode
489 = domain
->native_mode
;
490 state
->response
.data
.domain_info
.active_directory
491 = domain
->active_directory
;
492 state
->response
.data
.domain_info
.primary
494 state
->response
.data
.domain_info
.sequence_number
=
495 domain
->sequence_number
;
500 /* Look up global info for the winbind daemon */
501 BOOL
init_domain_list(void)
503 struct winbindd_domain
*domain
;
504 int role
= lp_server_role();
506 /* Free existing list */
509 /* Add ourselves as the first entry. */
511 if ( role
== ROLE_DOMAIN_MEMBER
) {
514 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid
)) {
515 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
519 domain
= add_trusted_domain( lp_workgroup(), lp_realm(),
520 &cache_methods
, &our_sid
);
521 domain
->primary
= True
;
522 setup_domain_child(domain
, &domain
->child
, NULL
);
524 /* Even in the parent winbindd we'll need to
525 talk to the DC, so try and see if we can
526 contact it. Theoretically this isn't neccessary
527 as the init_dc_connection() in init_child_recv()
528 will do this, but we can start detecting the DC
530 set_domain_online_request(domain
);
535 domain
= add_trusted_domain(get_global_sam_name(), NULL
,
536 &passdb_methods
, get_global_sam_sid());
537 if ( role
!= ROLE_DOMAIN_MEMBER
) {
538 domain
->primary
= True
;
540 setup_domain_child(domain
, &domain
->child
, NULL
);
544 domain
= add_trusted_domain("BUILTIN", NULL
, &passdb_methods
,
545 &global_sid_Builtin
);
546 setup_domain_child(domain
, &domain
->child
, NULL
);
552 * Given a domain name, return the struct winbindd domain info for it
554 * @note Do *not* pass lp_workgroup() to this function. domain_list
555 * may modify it's value, and free that pointer. Instead, our local
556 * domain may be found by calling find_our_domain().
560 * @return The domain structure for the named domain, if it is working.
563 struct winbindd_domain
*find_domain_from_name_noinit(const char *domain_name
)
565 struct winbindd_domain
*domain
;
567 /* Search through list */
569 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
570 if (strequal(domain_name
, domain
->name
) ||
571 (domain
->alt_name
[0] &&
572 strequal(domain_name
, domain
->alt_name
))) {
582 struct winbindd_domain
*find_domain_from_name(const char *domain_name
)
584 struct winbindd_domain
*domain
;
586 domain
= find_domain_from_name_noinit(domain_name
);
591 if (!domain
->initialized
)
592 init_dc_connection(domain
);
597 /* Given a domain sid, return the struct winbindd domain info for it */
599 struct winbindd_domain
*find_domain_from_sid_noinit(const DOM_SID
*sid
)
601 struct winbindd_domain
*domain
;
603 /* Search through list */
605 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
606 if (sid_compare_domain(sid
, &domain
->sid
) == 0)
615 /* Given a domain sid, return the struct winbindd domain info for it */
617 struct winbindd_domain
*find_domain_from_sid(const DOM_SID
*sid
)
619 struct winbindd_domain
*domain
;
621 domain
= find_domain_from_sid_noinit(sid
);
626 if (!domain
->initialized
)
627 init_dc_connection(domain
);
632 struct winbindd_domain
*find_our_domain(void)
634 struct winbindd_domain
*domain
;
636 /* Search through list */
638 for (domain
= domain_list(); domain
!= NULL
; domain
= domain
->next
) {
643 smb_panic("Could not find our domain\n");
647 struct winbindd_domain
*find_root_domain(void)
649 struct winbindd_domain
*ours
= find_our_domain();
654 if ( strlen(ours
->forest_name
) == 0 )
657 return find_domain_from_name( ours
->forest_name
);
660 struct winbindd_domain
*find_builtin_domain(void)
663 struct winbindd_domain
*domain
;
665 string_to_sid(&sid
, "S-1-5-32");
666 domain
= find_domain_from_sid(&sid
);
669 smb_panic("Could not find BUILTIN domain\n");
674 /* Find the appropriate domain to lookup a name or SID */
676 struct winbindd_domain
*find_lookup_domain_from_sid(const DOM_SID
*sid
)
678 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
679 * one to contact the external DC's. On member servers the internal
680 * domains are different: These are part of the local SAM. */
682 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n",
683 sid_string_static(sid
)));
685 if (IS_DC
|| is_internal_domain(sid
) || is_in_internal_domain(sid
)) {
686 DEBUG(10, ("calling find_domain_from_sid\n"));
687 return find_domain_from_sid(sid
);
690 /* On a member server a query for SID or name can always go to our
693 DEBUG(10, ("calling find_our_domain\n"));
694 return find_our_domain();
697 struct winbindd_domain
*find_lookup_domain_from_name(const char *domain_name
)
699 if (IS_DC
|| strequal(domain_name
, "BUILTIN") ||
700 strequal(domain_name
, get_global_sam_name()))
701 return find_domain_from_name_noinit(domain_name
);
703 return find_our_domain();
706 /* Lookup a sid in a domain from a name */
708 BOOL
winbindd_lookup_sid_by_name(TALLOC_CTX
*mem_ctx
,
709 struct winbindd_domain
*domain
,
710 const char *domain_name
,
711 const char *name
, DOM_SID
*sid
,
712 enum lsa_SidType
*type
)
717 result
= domain
->methods
->name_to_sid(domain
, mem_ctx
, domain_name
, name
, sid
, type
);
719 /* Return rid and type if lookup successful */
720 if (!NT_STATUS_IS_OK(result
)) {
721 *type
= SID_NAME_UNKNOWN
;
724 return NT_STATUS_IS_OK(result
);
728 * @brief Lookup a name in a domain from a sid.
730 * @param sid Security ID you want to look up.
731 * @param name On success, set to the name corresponding to @p sid.
732 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
733 * @param type On success, contains the type of name: alias, group or
735 * @retval True if the name exists, in which case @p name and @p type
736 * are set, otherwise False.
738 BOOL
winbindd_lookup_name_by_sid(TALLOC_CTX
*mem_ctx
,
742 enum lsa_SidType
*type
)
748 struct winbindd_domain
*domain
;
750 domain
= find_lookup_domain_from_sid(sid
);
753 DEBUG(1,("Can't find domain from sid\n"));
759 result
= domain
->methods
->sid_to_name(domain
, mem_ctx
, sid
, &dom_names
, &names
, type
);
761 /* Return name and type if successful */
763 if ((rv
= NT_STATUS_IS_OK(result
))) {
764 fstrcpy(dom_name
, dom_names
);
765 fstrcpy(name
, names
);
767 *type
= SID_NAME_UNKNOWN
;
768 fstrcpy(name
, name_deadbeef
);
774 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
776 void free_getent_state(struct getent_state
*state
)
778 struct getent_state
*temp
;
780 /* Iterate over state list */
784 while(temp
!= NULL
) {
785 struct getent_state
*next
;
787 /* Free sam entries then list entry */
789 SAFE_FREE(state
->sam_entries
);
790 DLIST_REMOVE(state
, state
);
798 /* Parse winbindd related parameters */
800 BOOL
winbindd_param_init(void)
802 /* Parse winbind uid and winbind_gid parameters */
804 if (!lp_idmap_uid(&server_state
.uid_low
, &server_state
.uid_high
)) {
805 DEBUG(0, ("winbindd: idmap uid range missing or invalid\n"));
806 DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
810 if (!lp_idmap_gid(&server_state
.gid_low
, &server_state
.gid_high
)) {
811 DEBUG(0, ("winbindd: idmap gid range missing or invalid\n"));
812 DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
819 BOOL
is_in_uid_range(uid_t uid
)
821 return ((uid
>= server_state
.uid_low
) &&
822 (uid
<= server_state
.uid_high
));
825 BOOL
is_in_gid_range(gid_t gid
)
827 return ((gid
>= server_state
.gid_low
) &&
828 (gid
<= server_state
.gid_high
));
831 /* Is this a domain which we may assume no DOMAIN\ prefix? */
833 static BOOL
assume_domain(const char *domain
)
835 /* never assume the domain on a standalone server */
837 if ( lp_server_role() == ROLE_STANDALONE
)
840 /* domain member servers may possibly assume for the domain name */
842 if ( lp_server_role() == ROLE_DOMAIN_MEMBER
) {
843 if ( !strequal(lp_workgroup(), domain
) )
846 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
850 /* only left with a domain controller */
852 if ( strequal(get_global_sam_name(), domain
) ) {
859 /* Parse a string of the form DOMAIN\user into a domain and a user */
861 BOOL
parse_domain_user(const char *domuser
, fstring domain
, fstring user
)
863 char *p
= strchr(domuser
,*lp_winbind_separator());
866 fstrcpy(user
, domuser
);
868 if ( assume_domain(lp_workgroup())) {
869 fstrcpy(domain
, lp_workgroup());
875 fstrcpy(domain
, domuser
);
876 domain
[PTR_DIFF(p
, domuser
)] = 0;
884 BOOL
parse_domain_user_talloc(TALLOC_CTX
*mem_ctx
, const char *domuser
,
885 char **domain
, char **user
)
887 fstring fstr_domain
, fstr_user
;
888 if (!parse_domain_user(domuser
, fstr_domain
, fstr_user
)) {
891 *domain
= talloc_strdup(mem_ctx
, fstr_domain
);
892 *user
= talloc_strdup(mem_ctx
, fstr_user
);
893 return ((*domain
!= NULL
) && (*user
!= NULL
));
896 /* Ensure an incoming username from NSS is fully qualified. Replace the
897 incoming fstring with DOMAIN <separator> user. Returns the same
898 values as parse_domain_user() but also replaces the incoming username.
899 Used to ensure all names are fully qualified within winbindd.
900 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
901 The protocol definitions of auth_crap, chng_pswd_auth_crap
902 really should be changed to use this instead of doing things
905 BOOL
canonicalize_username(fstring username_inout
, fstring domain
, fstring user
)
907 if (!parse_domain_user(username_inout
, domain
, user
)) {
910 slprintf(username_inout
, sizeof(fstring
) - 1, "%s%c%s",
911 domain
, *lp_winbind_separator(),
917 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
918 'winbind separator' options.
920 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
923 If we are a PDC or BDC, and this is for our domain, do likewise.
925 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
926 username is then unqualified in unix
928 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
930 void fill_domain_username(fstring name
, const char *domain
, const char *user
, BOOL can_assume
)
934 fstrcpy(tmp_user
, user
);
935 strlower_m(tmp_user
);
937 if (can_assume
&& assume_domain(domain
)) {
938 strlcpy(name
, tmp_user
, sizeof(fstring
));
940 slprintf(name
, sizeof(fstring
) - 1, "%s%c%s",
941 domain
, *lp_winbind_separator(),
947 * Winbindd socket accessor functions
950 char *get_winbind_priv_pipe_dir(void)
952 return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR
);
955 /* Open the winbindd socket */
957 static int _winbindd_socket
= -1;
958 static int _winbindd_priv_socket
= -1;
960 int open_winbindd_socket(void)
962 if (_winbindd_socket
== -1) {
963 _winbindd_socket
= create_pipe_sock(
964 WINBINDD_SOCKET_DIR
, WINBINDD_SOCKET_NAME
, 0755);
965 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
969 return _winbindd_socket
;
972 int open_winbindd_priv_socket(void)
974 if (_winbindd_priv_socket
== -1) {
975 _winbindd_priv_socket
= create_pipe_sock(
976 get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME
, 0750);
977 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
978 _winbindd_priv_socket
));
981 return _winbindd_priv_socket
;
984 /* Close the winbindd socket */
986 void close_winbindd_socket(void)
988 if (_winbindd_socket
!= -1) {
989 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
991 close(_winbindd_socket
);
992 _winbindd_socket
= -1;
994 if (_winbindd_priv_socket
!= -1) {
995 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
996 _winbindd_priv_socket
));
997 close(_winbindd_priv_socket
);
998 _winbindd_priv_socket
= -1;
1003 * Client list accessor functions
1006 static struct winbindd_cli_state
*_client_list
;
1007 static int _num_clients
;
1009 /* Return list of all connected clients */
1011 struct winbindd_cli_state
*winbindd_client_list(void)
1013 return _client_list
;
1016 /* Add a connection to the list */
1018 void winbindd_add_client(struct winbindd_cli_state
*cli
)
1020 DLIST_ADD(_client_list
, cli
);
1024 /* Remove a client from the list */
1026 void winbindd_remove_client(struct winbindd_cli_state
*cli
)
1028 DLIST_REMOVE(_client_list
, cli
);
1032 /* Close all open clients */
1034 void winbindd_kill_all_clients(void)
1036 struct winbindd_cli_state
*cl
= winbindd_client_list();
1038 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1041 struct winbindd_cli_state
*next
;
1044 winbindd_remove_client(cl
);
1049 /* Return number of open clients */
1051 int winbindd_num_clients(void)
1053 return _num_clients
;
1056 /*****************************************************************************
1057 For idmap conversion: convert one record to new format
1058 Ancient versions (eg 2.2.3a) of winbindd_idmap.tdb mapped DOMAINNAME/rid
1060 *****************************************************************************/
1061 static int convert_fn(TDB_CONTEXT
*tdb
, TDB_DATA key
, TDB_DATA data
, void *state
)
1063 struct winbindd_domain
*domain
;
1070 BOOL
*failed
= (BOOL
*)state
;
1072 DEBUG(10,("Converting %s\n", key
.dptr
));
1074 p
= strchr(key
.dptr
, '/');
1079 fstrcpy(dom_name
, key
.dptr
);
1082 domain
= find_domain_from_name(dom_name
);
1083 if (domain
== NULL
) {
1084 /* We must delete the old record. */
1085 DEBUG(0,("Unable to find domain %s\n", dom_name
));
1086 DEBUG(0,("deleting record %s\n", key
.dptr
));
1088 if (tdb_delete(tdb
, key
) != 0) {
1089 DEBUG(0, ("Unable to delete record %s\n", key
.dptr
));
1099 sid_copy(&sid
, &domain
->sid
);
1100 sid_append_rid(&sid
, rid
);
1102 sid_to_string(keystr
, &sid
);
1104 key2
.dsize
= strlen(keystr
) + 1;
1106 if (tdb_store(tdb
, key2
, data
, TDB_INSERT
) != 0) {
1107 DEBUG(0,("Unable to add record %s\n", key2
.dptr
));
1112 if (tdb_store(tdb
, data
, key2
, TDB_REPLACE
) != 0) {
1113 DEBUG(0,("Unable to update record %s\n", data
.dptr
));
1118 if (tdb_delete(tdb
, key
) != 0) {
1119 DEBUG(0,("Unable to delete record %s\n", key
.dptr
));
1127 /* These definitions are from sam/idmap_tdb.c. Replicated here just
1128 out of laziness.... :-( */
1130 /* High water mark keys */
1131 #define HWM_GROUP "GROUP HWM"
1132 #define HWM_USER "USER HWM"
1134 /*****************************************************************************
1135 Convert the idmap database from an older version.
1136 *****************************************************************************/
1138 static BOOL
idmap_convert(const char *idmap_name
)
1141 BOOL bigendianheader
;
1142 BOOL failed
= False
;
1143 TDB_CONTEXT
*idmap_tdb
;
1145 if (!(idmap_tdb
= tdb_open_log(idmap_name
, 0,
1146 TDB_DEFAULT
, O_RDWR
,
1148 DEBUG(0, ("idmap_convert: Unable to open idmap database\n"));
1152 bigendianheader
= (tdb_get_flags(idmap_tdb
) & TDB_BIGENDIAN
) ? True
: False
;
1154 vers
= tdb_fetch_int32(idmap_tdb
, "IDMAP_VERSION");
1156 if (((vers
== -1) && bigendianheader
) || (IREV(vers
) == IDMAP_VERSION
)) {
1157 /* Arrggghh ! Bytereversed or old big-endian - make order independent ! */
1159 * high and low records were created on a
1160 * big endian machine and will need byte-reversing.
1165 wm
= tdb_fetch_int32(idmap_tdb
, HWM_USER
);
1170 wm
= server_state
.uid_low
;
1173 if (tdb_store_int32(idmap_tdb
, HWM_USER
, wm
) == -1) {
1174 DEBUG(0, ("idmap_convert: Unable to byteswap user hwm in idmap database\n"));
1175 tdb_close(idmap_tdb
);
1179 wm
= tdb_fetch_int32(idmap_tdb
, HWM_GROUP
);
1183 wm
= server_state
.gid_low
;
1186 if (tdb_store_int32(idmap_tdb
, HWM_GROUP
, wm
) == -1) {
1187 DEBUG(0, ("idmap_convert: Unable to byteswap group hwm in idmap database\n"));
1188 tdb_close(idmap_tdb
);
1193 /* the old format stored as DOMAIN/rid - now we store the SID direct */
1194 tdb_traverse(idmap_tdb
, convert_fn
, &failed
);
1197 DEBUG(0, ("Problem during conversion\n"));
1198 tdb_close(idmap_tdb
);
1202 if (tdb_store_int32(idmap_tdb
, "IDMAP_VERSION", IDMAP_VERSION
) == -1) {
1203 DEBUG(0, ("idmap_convert: Unable to dtore idmap version in databse\n"));
1204 tdb_close(idmap_tdb
);
1208 tdb_close(idmap_tdb
);
1212 /*****************************************************************************
1213 Convert the idmap database from an older version if necessary
1214 *****************************************************************************/
1216 BOOL
winbindd_upgrade_idmap(void)
1219 pstring backup_name
;
1220 SMB_STRUCT_STAT stbuf
;
1221 TDB_CONTEXT
*idmap_tdb
;
1223 pstrcpy(idmap_name
, lock_path("winbindd_idmap.tdb"));
1225 if (!file_exist(idmap_name
, &stbuf
)) {
1226 /* nothing to convert return */
1230 if (!(idmap_tdb
= tdb_open_log(idmap_name
, 0,
1231 TDB_DEFAULT
, O_RDWR
,
1233 DEBUG(0, ("idmap_convert: Unable to open idmap database\n"));
1237 if (tdb_fetch_int32(idmap_tdb
, "IDMAP_VERSION") == IDMAP_VERSION
) {
1238 /* nothing to convert return */
1239 tdb_close(idmap_tdb
);
1243 /* backup_tdb expects the tdb not to be open */
1244 tdb_close(idmap_tdb
);
1246 DEBUG(0, ("Upgrading winbindd_idmap.tdb from an old version\n"));
1248 pstrcpy(backup_name
, idmap_name
);
1249 pstrcat(backup_name
, ".bak");
1251 if (backup_tdb(idmap_name
, backup_name
, 0) != 0) {
1252 DEBUG(0, ("Could not backup idmap database\n"));
1256 return idmap_convert(idmap_name
);
1259 NTSTATUS
lookup_usergroups_cached(struct winbindd_domain
*domain
,
1260 TALLOC_CTX
*mem_ctx
,
1261 const DOM_SID
*user_sid
,
1262 uint32
*p_num_groups
, DOM_SID
**user_sids
)
1264 NET_USER_INFO_3
*info3
= NULL
;
1265 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1267 size_t num_groups
= 0;
1268 DOM_SID group_sid
, primary_group
;
1270 DEBUG(3,(": lookup_usergroups_cached\n"));
1276 info3
= netsamlogon_cache_get(mem_ctx
, user_sid
);
1278 if (info3
== NULL
) {
1279 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1282 if (info3
->num_groups
== 0) {
1284 return NT_STATUS_UNSUCCESSFUL
;
1287 /* always add the primary group to the sid array */
1288 sid_compose(&primary_group
, &info3
->dom_sid
.sid
, info3
->user_rid
);
1290 if (!add_sid_to_array(mem_ctx
, &primary_group
, user_sids
, &num_groups
)) {
1292 return NT_STATUS_NO_MEMORY
;
1295 for (i
=0; i
<info3
->num_groups
; i
++) {
1296 sid_copy(&group_sid
, &info3
->dom_sid
.sid
);
1297 sid_append_rid(&group_sid
, info3
->gids
[i
].g_rid
);
1299 if (!add_sid_to_array(mem_ctx
, &group_sid
, user_sids
,
1302 return NT_STATUS_NO_MEMORY
;
1307 *p_num_groups
= num_groups
;
1308 status
= (user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
1310 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1315 /*********************************************************************
1316 We use this to remove spaces from user and group names
1317 ********************************************************************/
1319 void ws_name_replace( char *name
, char replace
)
1321 char replace_char
[2] = { 0x0, 0x0 };
1323 if ( !lp_winbind_normalize_names() || (replace
== '\0') )
1326 replace_char
[0] = replace
;
1327 all_string_sub( name
, " ", replace_char
, 0 );
1332 /*********************************************************************
1333 We use this to do the inverse of ws_name_replace()
1334 ********************************************************************/
1336 void ws_name_return( char *name
, char replace
)
1338 char replace_char
[2] = { 0x0, 0x0 };
1340 if ( !lp_winbind_normalize_names() || (replace
== '\0') )
1343 replace_char
[0] = replace
;
1344 all_string_sub( name
, replace_char
, " ", 0 );