fixing typo in the 'map readonly = permissions' explanation reported by Thomas Bork
[Samba.git] / source / nsswitch / winbindd_util.c
blobecd919d6ffc96cd78faf2fa05a8162dd2765383c
1 /*
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.
24 #include "includes.h"
25 #include "winbindd.h"
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_WINBIND
30 extern struct winbindd_methods cache_methods;
31 extern struct winbindd_methods passdb_methods;
33 /**
34 * @file winbindd_util.c
36 * Winbind daemon for NT domain authentication nss module.
37 **/
40 /* The list of trusted domains. Note that the list can be deleted and
41 recreated using the init_domain_list() function so pointers to
42 individual winbindd_domain structures cannot be made. Keep a copy of
43 the domain name instead. */
45 static struct winbindd_domain *_domain_list;
47 /**
48 When was the last scan of trusted domains done?
50 0 == not ever
53 static time_t last_trustdom_scan;
55 struct winbindd_domain *domain_list(void)
57 /* Initialise list */
59 if ((!_domain_list) && (!init_domain_list())) {
60 smb_panic("Init_domain_list failed\n");
63 return _domain_list;
66 /* Free all entries in the trusted domain list */
68 void free_domain_list(void)
70 struct winbindd_domain *domain = _domain_list;
72 while(domain) {
73 struct winbindd_domain *next = domain->next;
75 DLIST_REMOVE(_domain_list, domain);
76 SAFE_FREE(domain);
77 domain = next;
81 static BOOL is_internal_domain(const DOM_SID *sid)
83 if (sid == NULL)
84 return False;
86 return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
89 static BOOL is_in_internal_domain(const DOM_SID *sid)
91 if (sid == NULL)
92 return False;
94 return (sid_check_is_in_our_domain(sid) || sid_check_is_in_builtin(sid));
98 /* Add a trusted domain to our list of domains */
99 static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
100 struct winbindd_methods *methods,
101 const DOM_SID *sid)
103 struct winbindd_domain *domain;
104 const char *alternative_name = NULL;
106 /* ignore alt_name if we are not in an AD domain */
108 if ( (lp_security() == SEC_ADS) && alt_name && *alt_name) {
109 alternative_name = alt_name;
112 /* We can't call domain_list() as this function is called from
113 init_domain_list() and we'll get stuck in a loop. */
114 for (domain = _domain_list; domain; domain = domain->next) {
115 if (strequal(domain_name, domain->name) ||
116 strequal(domain_name, domain->alt_name)) {
117 return domain;
119 if (alternative_name && *alternative_name) {
120 if (strequal(alternative_name, domain->name) ||
121 strequal(alternative_name, domain->alt_name)) {
122 return domain;
125 if (sid) {
126 if (is_null_sid(sid)) {
128 } else if (sid_equal(sid, &domain->sid)) {
129 return domain;
134 /* Create new domain entry */
136 if ((domain = SMB_MALLOC_P(struct winbindd_domain)) == NULL)
137 return NULL;
139 /* Fill in fields */
141 ZERO_STRUCTP(domain);
143 /* prioritise the short name */
144 if (strchr_m(domain_name, '.') && alternative_name && *alternative_name) {
145 fstrcpy(domain->name, alternative_name);
146 fstrcpy(domain->alt_name, domain_name);
147 } else {
148 fstrcpy(domain->name, domain_name);
149 if (alternative_name) {
150 fstrcpy(domain->alt_name, alternative_name);
154 domain->methods = methods;
155 domain->backend = NULL;
156 domain->internal = is_internal_domain(sid);
157 domain->sequence_number = DOM_SEQUENCE_NONE;
158 domain->last_seq_check = 0;
159 domain->initialized = False;
160 domain->online = is_internal_domain(sid);
161 domain->check_online_timeout = 0;
162 if (sid) {
163 sid_copy(&domain->sid, sid);
166 /* Link to domain list */
167 DLIST_ADD(_domain_list, domain);
169 DEBUG(2,("Added domain %s %s %s\n",
170 domain->name, domain->alt_name,
171 &domain->sid?sid_string_static(&domain->sid):""));
173 return domain;
176 /********************************************************************
177 rescan our domains looking for new trusted domains
178 ********************************************************************/
180 struct trustdom_state {
181 TALLOC_CTX *mem_ctx;
182 struct winbindd_response *response;
185 static void trustdom_recv(void *private_data, BOOL success);
187 static void add_trusted_domains( struct winbindd_domain *domain )
189 TALLOC_CTX *mem_ctx;
190 struct winbindd_request *request;
191 struct winbindd_response *response;
193 struct trustdom_state *state;
195 mem_ctx = talloc_init("add_trusted_domains");
196 if (mem_ctx == NULL) {
197 DEBUG(0, ("talloc_init failed\n"));
198 return;
201 request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
202 response = TALLOC_P(mem_ctx, struct winbindd_response);
203 state = TALLOC_P(mem_ctx, struct trustdom_state);
205 if ((request == NULL) || (response == NULL) || (state == NULL)) {
206 DEBUG(0, ("talloc failed\n"));
207 talloc_destroy(mem_ctx);
208 return;
211 state->mem_ctx = mem_ctx;
212 state->response = response;
214 request->length = sizeof(*request);
215 request->cmd = WINBINDD_LIST_TRUSTDOM;
217 async_domain_request(mem_ctx, domain, request, response,
218 trustdom_recv, state);
221 static void trustdom_recv(void *private_data, BOOL success)
223 struct trustdom_state *state =
224 talloc_get_type_abort(private_data, struct trustdom_state);
225 struct winbindd_response *response = state->response;
226 char *p;
228 if ((!success) || (response->result != WINBINDD_OK)) {
229 DEBUG(1, ("Could not receive trustdoms\n"));
230 talloc_destroy(state->mem_ctx);
231 return;
234 p = (char *)response->extra_data.data;
236 while ((p != NULL) && (*p != '\0')) {
237 char *q, *sidstr, *alt_name;
238 DOM_SID sid;
240 alt_name = strchr(p, '\\');
241 if (alt_name == NULL) {
242 DEBUG(0, ("Got invalid trustdom response\n"));
243 break;
246 *alt_name = '\0';
247 alt_name += 1;
249 sidstr = strchr(alt_name, '\\');
250 if (sidstr == NULL) {
251 DEBUG(0, ("Got invalid trustdom response\n"));
252 break;
255 *sidstr = '\0';
256 sidstr += 1;
258 q = strchr(sidstr, '\n');
259 if (q != NULL)
260 *q = '\0';
262 if (!string_to_sid(&sid, sidstr)) {
263 /* Allow NULL sid for sibling domains */
264 if ( strcmp(sidstr,"S-0-0") == 0) {
265 sid_copy( &sid, &global_sid_NULL);
266 } else {
267 DEBUG(0, ("Got invalid trustdom response\n"));
268 break;
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,
282 &cache_methods,
283 &sid);
284 setup_domain_child(domain, &domain->child, NULL);
286 p=q;
287 if (p != NULL)
288 p += 1;
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) )
307 return;
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;
315 return;
318 struct init_child_state {
319 TALLOC_CTX *mem_ctx;
320 struct winbindd_domain *domain;
321 struct winbindd_request *request;
322 struct winbindd_response *response;
323 void (*continuation)(void *private_data, BOOL success);
324 void *private_data;
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,
332 BOOL success),
333 void *private_data)
335 TALLOC_CTX *mem_ctx;
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
379 * name */
381 request->cmd = WINBINDD_GETDCNAME;
382 fstrcpy(request->domain_name, domain->name);
384 request_domain = find_our_domain();
386 async_domain_request(mem_ctx, request_domain, request, response,
387 init_child_getdc_recv, state);
388 return WINBINDD_PENDING;
391 static void init_child_getdc_recv(void *private_data, BOOL success)
393 struct init_child_state *state =
394 talloc_get_type_abort(private_data, struct init_child_state);
395 const char *dcname = "";
397 DEBUG(10, ("Received getdcname response\n"));
399 if (success && (state->response->result == WINBINDD_OK)) {
400 dcname = state->response->data.dc_name;
403 state->request->cmd = WINBINDD_INIT_CONNECTION;
404 fstrcpy(state->request->domain_name, state->domain->name);
405 state->request->data.init_conn.is_primary = False;
406 fstrcpy(state->request->data.init_conn.dcname, dcname);
408 async_request(state->mem_ctx, &state->domain->child,
409 state->request, state->response,
410 init_child_recv, state);
413 static void init_child_recv(void *private_data, BOOL success)
415 struct init_child_state *state =
416 talloc_get_type_abort(private_data, struct init_child_state);
418 DEBUG(5, ("Received child initialization response for domain %s\n",
419 state->domain->name));
421 if ((!success) || (state->response->result != WINBINDD_OK)) {
422 DEBUG(3, ("Could not init child\n"));
423 state->continuation(state->private_data, False);
424 talloc_destroy(state->mem_ctx);
425 return;
428 fstrcpy(state->domain->name,
429 state->response->data.domain_info.name);
430 fstrcpy(state->domain->alt_name,
431 state->response->data.domain_info.alt_name);
432 string_to_sid(&state->domain->sid,
433 state->response->data.domain_info.sid);
434 state->domain->native_mode =
435 state->response->data.domain_info.native_mode;
436 state->domain->active_directory =
437 state->response->data.domain_info.active_directory;
438 state->domain->sequence_number =
439 state->response->data.domain_info.sequence_number;
441 init_dc_connection(state->domain);
443 if (state->continuation != NULL)
444 state->continuation(state->private_data, True);
445 talloc_destroy(state->mem_ctx);
448 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
449 struct winbindd_cli_state *state)
451 /* Ensure null termination */
452 state->request.domain_name
453 [sizeof(state->request.domain_name)-1]='\0';
454 state->request.data.init_conn.dcname
455 [sizeof(state->request.data.init_conn.dcname)-1]='\0';
457 if (strlen(state->request.data.init_conn.dcname) > 0) {
458 fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
461 init_dc_connection(domain);
463 if (!domain->initialized) {
464 /* If we return error here we can't do any cached authentication,
465 but we may be in disconnected mode and can't initialize correctly.
466 Do what the previous code did and just return without initialization,
467 once we go online we'll re-initialize.
469 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
470 "online = %d\n", domain->name, (int)domain->online ));
473 fstrcpy(state->response.data.domain_info.name, domain->name);
474 fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
475 fstrcpy(state->response.data.domain_info.sid,
476 sid_string_static(&domain->sid));
478 state->response.data.domain_info.native_mode
479 = domain->native_mode;
480 state->response.data.domain_info.active_directory
481 = domain->active_directory;
482 state->response.data.domain_info.primary
483 = domain->primary;
484 state->response.data.domain_info.sequence_number =
485 domain->sequence_number;
487 return WINBINDD_OK;
490 /* Look up global info for the winbind daemon */
491 BOOL init_domain_list(void)
493 struct winbindd_domain *domain;
494 int role = lp_server_role();
496 /* Free existing list */
497 free_domain_list();
499 /* Add ourselves as the first entry. */
501 if ( role == ROLE_DOMAIN_MEMBER ) {
502 DOM_SID our_sid;
504 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
505 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
506 return False;
509 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
510 &cache_methods, &our_sid);
511 domain->primary = True;
512 setup_domain_child(domain, &domain->child, NULL);
514 /* Even in the parent winbindd we'll need to
515 talk to the DC, so try and see if we can
516 contact it. Theoretically this isn't neccessary
517 as the init_dc_connection() in init_child_recv()
518 will do this, but we can start detecting the DC
519 early here. */
520 set_domain_online_request(domain);
523 /* Local SAM */
525 domain = add_trusted_domain(get_global_sam_name(), NULL,
526 &passdb_methods, get_global_sam_sid());
527 if ( role != ROLE_DOMAIN_MEMBER ) {
528 domain->primary = True;
530 setup_domain_child(domain, &domain->child, NULL);
532 /* BUILTIN domain */
534 domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
535 &global_sid_Builtin);
536 setup_domain_child(domain, &domain->child, NULL);
538 return True;
541 /**
542 * Given a domain name, return the struct winbindd domain info for it
544 * @note Do *not* pass lp_workgroup() to this function. domain_list
545 * may modify it's value, and free that pointer. Instead, our local
546 * domain may be found by calling find_our_domain().
547 * directly.
550 * @return The domain structure for the named domain, if it is working.
553 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
555 struct winbindd_domain *domain;
557 /* Search through list */
559 for (domain = domain_list(); domain != NULL; domain = domain->next) {
560 if (strequal(domain_name, domain->name) ||
561 (domain->alt_name[0] &&
562 strequal(domain_name, domain->alt_name))) {
563 return domain;
567 /* Not found */
569 return NULL;
572 struct winbindd_domain *find_domain_from_name(const char *domain_name)
574 struct winbindd_domain *domain;
576 domain = find_domain_from_name_noinit(domain_name);
578 if (domain == NULL)
579 return NULL;
581 if (!domain->initialized)
582 init_dc_connection(domain);
584 return domain;
587 /* Given a domain sid, return the struct winbindd domain info for it */
589 struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
591 struct winbindd_domain *domain;
593 /* Search through list */
595 for (domain = domain_list(); domain != NULL; domain = domain->next) {
596 if (sid_compare_domain(sid, &domain->sid) == 0)
597 return domain;
600 /* Not found */
602 return NULL;
605 /* Given a domain sid, return the struct winbindd domain info for it */
607 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
609 struct winbindd_domain *domain;
611 domain = find_domain_from_sid_noinit(sid);
613 if (domain == NULL)
614 return NULL;
616 if (!domain->initialized)
617 init_dc_connection(domain);
619 return domain;
622 struct winbindd_domain *find_our_domain(void)
624 struct winbindd_domain *domain;
626 /* Search through list */
628 for (domain = domain_list(); domain != NULL; domain = domain->next) {
629 if (domain->primary)
630 return domain;
633 smb_panic("Could not find our domain\n");
634 return NULL;
637 struct winbindd_domain *find_root_domain(void)
639 struct winbindd_domain *ours = find_our_domain();
641 if ( !ours )
642 return NULL;
644 if ( strlen(ours->forest_name) == 0 )
645 return NULL;
647 return find_domain_from_name( ours->forest_name );
650 struct winbindd_domain *find_builtin_domain(void)
652 DOM_SID sid;
653 struct winbindd_domain *domain;
655 string_to_sid(&sid, "S-1-5-32");
656 domain = find_domain_from_sid(&sid);
658 if (domain == NULL)
659 smb_panic("Could not find BUILTIN domain\n");
661 return domain;
664 /* Find the appropriate domain to lookup a name or SID */
666 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
668 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
669 * one to contact the external DC's. On member servers the internal
670 * domains are different: These are part of the local SAM. */
672 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n",
673 sid_string_static(sid)));
675 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
676 DEBUG(10, ("calling find_domain_from_sid\n"));
677 return find_domain_from_sid(sid);
680 /* On a member server a query for SID or name can always go to our
681 * primary DC. */
683 DEBUG(10, ("calling find_our_domain\n"));
684 return find_our_domain();
687 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
689 if (IS_DC || strequal(domain_name, "BUILTIN") ||
690 strequal(domain_name, get_global_sam_name()))
691 return find_domain_from_name_noinit(domain_name);
693 return find_our_domain();
696 /* Lookup a sid in a domain from a name */
698 BOOL winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
699 struct winbindd_domain *domain,
700 const char *domain_name,
701 const char *name, DOM_SID *sid,
702 enum lsa_SidType *type)
704 NTSTATUS result;
706 /* Lookup name */
707 result = domain->methods->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
709 /* Return sid and type if lookup successful */
710 if (!NT_STATUS_IS_OK(result)) {
711 *type = SID_NAME_UNKNOWN;
714 return NT_STATUS_IS_OK(result);
718 * @brief Lookup a name in a domain from a sid.
720 * @param sid Security ID you want to look up.
721 * @param name On success, set to the name corresponding to @p sid.
722 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
723 * @param type On success, contains the type of name: alias, group or
724 * user.
725 * @retval True if the name exists, in which case @p name and @p type
726 * are set, otherwise False.
728 BOOL winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
729 DOM_SID *sid,
730 char **dom_name,
731 char **name,
732 enum lsa_SidType *type)
734 NTSTATUS result;
735 struct winbindd_domain *domain;
737 *dom_name = NULL;
738 *name = NULL;
740 domain = find_lookup_domain_from_sid(sid);
742 if (!domain) {
743 DEBUG(1,("Can't find domain from sid\n"));
744 return False;
747 /* Lookup name */
749 result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
751 /* Return name and type if successful */
753 if (NT_STATUS_IS_OK(result)) {
754 return True;
757 *type = SID_NAME_UNKNOWN;
759 return False;
762 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
764 void free_getent_state(struct getent_state *state)
766 struct getent_state *temp;
768 /* Iterate over state list */
770 temp = state;
772 while(temp != NULL) {
773 struct getent_state *next;
775 /* Free sam entries then list entry */
777 SAFE_FREE(state->sam_entries);
778 DLIST_REMOVE(state, state);
779 next = temp->next;
781 SAFE_FREE(temp);
782 temp = next;
786 /* Is this a domain which we may assume no DOMAIN\ prefix? */
788 static BOOL assume_domain(const char *domain)
790 /* never assume the domain on a standalone server */
792 if ( lp_server_role() == ROLE_STANDALONE )
793 return False;
795 /* domain member servers may possibly assume for the domain name */
797 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
798 if ( !strequal(lp_workgroup(), domain) )
799 return False;
801 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
802 return True;
805 /* only left with a domain controller */
807 if ( strequal(get_global_sam_name(), domain) ) {
808 return True;
811 return False;
814 /* Parse a string of the form DOMAIN\user into a domain and a user */
816 BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
818 char *p = strchr(domuser,*lp_winbind_separator());
820 if ( !p ) {
821 fstrcpy(user, domuser);
823 if ( assume_domain(lp_workgroup())) {
824 fstrcpy(domain, lp_workgroup());
825 } else {
826 return False;
828 } else {
829 fstrcpy(user, p+1);
830 fstrcpy(domain, domuser);
831 domain[PTR_DIFF(p, domuser)] = 0;
834 strupper_m(domain);
836 return True;
839 BOOL parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
840 char **domain, char **user)
842 fstring fstr_domain, fstr_user;
843 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
844 return False;
846 *domain = talloc_strdup(mem_ctx, fstr_domain);
847 *user = talloc_strdup(mem_ctx, fstr_user);
848 return ((*domain != NULL) && (*user != NULL));
851 /* Ensure an incoming username from NSS is fully qualified. Replace the
852 incoming fstring with DOMAIN <separator> user. Returns the same
853 values as parse_domain_user() but also replaces the incoming username.
854 Used to ensure all names are fully qualified within winbindd.
855 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
856 The protocol definitions of auth_crap, chng_pswd_auth_crap
857 really should be changed to use this instead of doing things
858 by hand. JRA. */
860 BOOL canonicalize_username(fstring username_inout, fstring domain, fstring user)
862 if (!parse_domain_user(username_inout, domain, user)) {
863 return False;
865 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
866 domain, *lp_winbind_separator(),
867 user);
868 return True;
872 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
873 'winbind separator' options.
874 This means:
875 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
876 lp_workgroup()
878 If we are a PDC or BDC, and this is for our domain, do likewise.
880 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
881 username is then unqualified in unix
883 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
885 void fill_domain_username(fstring name, const char *domain, const char *user, BOOL can_assume)
887 fstring tmp_user;
889 fstrcpy(tmp_user, user);
890 strlower_m(tmp_user);
892 if (can_assume && assume_domain(domain)) {
893 strlcpy(name, tmp_user, sizeof(fstring));
894 } else {
895 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
896 domain, *lp_winbind_separator(),
897 tmp_user);
902 * Winbindd socket accessor functions
905 char *get_winbind_priv_pipe_dir(void)
907 return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
910 /* Open the winbindd socket */
912 static int _winbindd_socket = -1;
913 static int _winbindd_priv_socket = -1;
915 int open_winbindd_socket(void)
917 if (_winbindd_socket == -1) {
918 _winbindd_socket = create_pipe_sock(
919 WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME, 0755);
920 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
921 _winbindd_socket));
924 return _winbindd_socket;
927 int open_winbindd_priv_socket(void)
929 if (_winbindd_priv_socket == -1) {
930 _winbindd_priv_socket = create_pipe_sock(
931 get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
932 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
933 _winbindd_priv_socket));
936 return _winbindd_priv_socket;
939 /* Close the winbindd socket */
941 void close_winbindd_socket(void)
943 if (_winbindd_socket != -1) {
944 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
945 _winbindd_socket));
946 close(_winbindd_socket);
947 _winbindd_socket = -1;
949 if (_winbindd_priv_socket != -1) {
950 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
951 _winbindd_priv_socket));
952 close(_winbindd_priv_socket);
953 _winbindd_priv_socket = -1;
958 * Client list accessor functions
961 static struct winbindd_cli_state *_client_list;
962 static int _num_clients;
964 /* Return list of all connected clients */
966 struct winbindd_cli_state *winbindd_client_list(void)
968 return _client_list;
971 /* Add a connection to the list */
973 void winbindd_add_client(struct winbindd_cli_state *cli)
975 DLIST_ADD(_client_list, cli);
976 _num_clients++;
979 /* Remove a client from the list */
981 void winbindd_remove_client(struct winbindd_cli_state *cli)
983 DLIST_REMOVE(_client_list, cli);
984 _num_clients--;
987 /* Close all open clients */
989 void winbindd_kill_all_clients(void)
991 struct winbindd_cli_state *cl = winbindd_client_list();
993 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
995 while (cl) {
996 struct winbindd_cli_state *next;
998 next = cl->next;
999 winbindd_remove_client(cl);
1000 cl = next;
1004 /* Return number of open clients */
1006 int winbindd_num_clients(void)
1008 return _num_clients;
1011 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1012 TALLOC_CTX *mem_ctx,
1013 const DOM_SID *user_sid,
1014 uint32 *p_num_groups, DOM_SID **user_sids)
1016 NET_USER_INFO_3 *info3 = NULL;
1017 NTSTATUS status = NT_STATUS_NO_MEMORY;
1018 int i;
1019 size_t num_groups = 0;
1020 DOM_SID group_sid, primary_group;
1022 DEBUG(3,(": lookup_usergroups_cached\n"));
1024 *user_sids = NULL;
1025 num_groups = 0;
1026 *p_num_groups = 0;
1028 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1030 if (info3 == NULL) {
1031 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1034 if (info3->num_groups == 0) {
1035 TALLOC_FREE(info3);
1036 return NT_STATUS_UNSUCCESSFUL;
1039 /* always add the primary group to the sid array */
1040 sid_compose(&primary_group, &info3->dom_sid.sid, info3->user_rid);
1042 if (!add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups)) {
1043 TALLOC_FREE(info3);
1044 return NT_STATUS_NO_MEMORY;
1047 for (i=0; i<info3->num_groups; i++) {
1048 sid_copy(&group_sid, &info3->dom_sid.sid);
1049 sid_append_rid(&group_sid, info3->gids[i].g_rid);
1051 if (!add_sid_to_array(mem_ctx, &group_sid, user_sids,
1052 &num_groups)) {
1053 TALLOC_FREE(info3);
1054 return NT_STATUS_NO_MEMORY;
1058 TALLOC_FREE(info3);
1059 *p_num_groups = num_groups;
1060 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1062 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1064 return status;
1067 /*********************************************************************
1068 We use this to remove spaces from user and group names
1069 ********************************************************************/
1071 void ws_name_replace( char *name, char replace )
1073 char replace_char[2] = { 0x0, 0x0 };
1075 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1076 return;
1078 replace_char[0] = replace;
1079 all_string_sub( name, " ", replace_char, 0 );
1081 return;
1084 /*********************************************************************
1085 We use this to do the inverse of ws_name_replace()
1086 ********************************************************************/
1088 void ws_name_return( char *name, char replace )
1090 char replace_char[2] = { 0x0, 0x0 };
1092 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1093 return;
1095 replace_char[0] = replace;
1096 all_string_sub( name, replace_char, " ", 0 );
1098 return;