r23602: grab final changes for 3.0.25b due out tomorrow
[Samba.git] / source / nsswitch / winbindd_util.c
blob9a0ade55416bd5efd10d894055cdd8132a250edf
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 /**
41 * Used to clobber name fields that have an undefined value.
43 * Correct code should never look at a field that has this value.
44 **/
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;
55 /**
56 When was the last scan of trusted domains done?
58 0 == not ever
61 static time_t last_trustdom_scan;
63 struct winbindd_domain *domain_list(void)
65 /* Initialise list */
67 if ((!_domain_list) && (!init_domain_list())) {
68 smb_panic("Init_domain_list failed\n");
71 return _domain_list;
74 /* Free all entries in the trusted domain list */
76 void free_domain_list(void)
78 struct winbindd_domain *domain = _domain_list;
80 while(domain) {
81 struct winbindd_domain *next = domain->next;
83 DLIST_REMOVE(_domain_list, domain);
84 SAFE_FREE(domain);
85 domain = next;
89 static BOOL is_internal_domain(const DOM_SID *sid)
91 if (sid == NULL)
92 return False;
94 if ( IS_DC )
95 return sid_check_is_builtin(sid);
97 return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
100 static BOOL is_in_internal_domain(const DOM_SID *sid)
102 if (sid == NULL)
103 return False;
105 if ( IS_DC )
106 return sid_check_is_in_builtin(sid);
108 return (sid_check_is_in_our_domain(sid) || sid_check_is_in_builtin(sid));
112 /* Add a trusted domain to our list of domains */
113 static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
114 struct winbindd_methods *methods,
115 const DOM_SID *sid)
117 struct winbindd_domain *domain;
118 const char *alternative_name = NULL;
120 /* ignore alt_name if we are not in an AD domain */
122 if ( (lp_security() == SEC_ADS) && alt_name && *alt_name) {
123 alternative_name = alt_name;
126 /* We can't call domain_list() as this function is called from
127 init_domain_list() and we'll get stuck in a loop. */
128 for (domain = _domain_list; domain; domain = domain->next) {
129 if (strequal(domain_name, domain->name) ||
130 strequal(domain_name, domain->alt_name)) {
131 return domain;
133 if (alternative_name && *alternative_name) {
134 if (strequal(alternative_name, domain->name) ||
135 strequal(alternative_name, domain->alt_name)) {
136 return domain;
139 if (sid) {
140 if (is_null_sid(sid)) {
142 } else if (sid_equal(sid, &domain->sid)) {
143 return domain;
148 /* Create new domain entry */
150 if ((domain = SMB_MALLOC_P(struct winbindd_domain)) == NULL)
151 return NULL;
153 /* Fill in fields */
155 ZERO_STRUCTP(domain);
157 /* prioritise the short name */
158 if (strchr_m(domain_name, '.') && alternative_name && *alternative_name) {
159 fstrcpy(domain->name, alternative_name);
160 fstrcpy(domain->alt_name, domain_name);
161 } else {
162 fstrcpy(domain->name, domain_name);
163 if (alternative_name) {
164 fstrcpy(domain->alt_name, alternative_name);
168 domain->methods = methods;
169 domain->backend = NULL;
170 domain->internal = is_internal_domain(sid);
171 domain->sequence_number = DOM_SEQUENCE_NONE;
172 domain->last_seq_check = 0;
173 domain->initialized = False;
174 domain->online = is_internal_domain(sid);
175 domain->check_online_timeout = 0;
176 if (sid) {
177 sid_copy(&domain->sid, sid);
180 /* Link to domain list */
181 DLIST_ADD(_domain_list, domain);
183 DEBUG(2,("Added domain %s %s %s\n",
184 domain->name, domain->alt_name,
185 &domain->sid?sid_string_static(&domain->sid):""));
187 return domain;
190 /********************************************************************
191 rescan our domains looking for new trusted domains
192 ********************************************************************/
194 struct trustdom_state {
195 TALLOC_CTX *mem_ctx;
196 struct winbindd_response *response;
199 static void trustdom_recv(void *private_data, BOOL success);
201 static void add_trusted_domains( struct winbindd_domain *domain )
203 TALLOC_CTX *mem_ctx;
204 struct winbindd_request *request;
205 struct winbindd_response *response;
207 struct trustdom_state *state;
209 mem_ctx = talloc_init("add_trusted_domains");
210 if (mem_ctx == NULL) {
211 DEBUG(0, ("talloc_init failed\n"));
212 return;
215 request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
216 response = TALLOC_P(mem_ctx, struct winbindd_response);
217 state = TALLOC_P(mem_ctx, struct trustdom_state);
219 if ((request == NULL) || (response == NULL) || (state == NULL)) {
220 DEBUG(0, ("talloc failed\n"));
221 talloc_destroy(mem_ctx);
222 return;
225 state->mem_ctx = mem_ctx;
226 state->response = response;
228 request->length = sizeof(*request);
229 request->cmd = WINBINDD_LIST_TRUSTDOM;
231 async_domain_request(mem_ctx, domain, request, response,
232 trustdom_recv, state);
235 static void trustdom_recv(void *private_data, BOOL success)
237 struct trustdom_state *state =
238 talloc_get_type_abort(private_data, struct trustdom_state);
239 struct winbindd_response *response = state->response;
240 char *p;
242 if ((!success) || (response->result != WINBINDD_OK)) {
243 DEBUG(1, ("Could not receive trustdoms\n"));
244 talloc_destroy(state->mem_ctx);
245 return;
248 p = (char *)response->extra_data.data;
250 while ((p != NULL) && (*p != '\0')) {
251 char *q, *sidstr, *alt_name;
252 DOM_SID sid;
254 alt_name = strchr(p, '\\');
255 if (alt_name == NULL) {
256 DEBUG(0, ("Got invalid trustdom response\n"));
257 break;
260 *alt_name = '\0';
261 alt_name += 1;
263 sidstr = strchr(alt_name, '\\');
264 if (sidstr == NULL) {
265 DEBUG(0, ("Got invalid trustdom response\n"));
266 break;
269 *sidstr = '\0';
270 sidstr += 1;
272 q = strchr(sidstr, '\n');
273 if (q != NULL)
274 *q = '\0';
276 if (!string_to_sid(&sid, sidstr)) {
277 /* Allow NULL sid for sibling domains */
278 if ( strcmp(sidstr,"S-0-0") == 0) {
279 sid_copy( &sid, &global_sid_NULL);
280 } else {
281 DEBUG(0, ("Got invalid trustdom response\n"));
282 break;
286 if (find_domain_from_name_noinit(p) == NULL) {
287 struct winbindd_domain *domain;
288 char *alternate_name = NULL;
290 /* use the real alt_name if we have one, else pass in NULL */
292 if ( !strequal( alt_name, "(null)" ) )
293 alternate_name = alt_name;
295 domain = add_trusted_domain(p, alternate_name,
296 &cache_methods,
297 &sid);
298 setup_domain_child(domain, &domain->child, NULL);
300 p=q;
301 if (p != NULL)
302 p += 1;
305 SAFE_FREE(response->extra_data.data);
306 talloc_destroy(state->mem_ctx);
309 /********************************************************************
310 Periodically we need to refresh the trusted domain cache for smbd
311 ********************************************************************/
313 void rescan_trusted_domains( void )
315 time_t now = time(NULL);
317 /* see if the time has come... */
319 if ((now >= last_trustdom_scan) &&
320 ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
321 return;
323 /* this will only add new domains we didn't already know about */
325 add_trusted_domains( find_our_domain() );
327 last_trustdom_scan = now;
329 return;
332 struct init_child_state {
333 TALLOC_CTX *mem_ctx;
334 struct winbindd_domain *domain;
335 struct winbindd_request *request;
336 struct winbindd_response *response;
337 void (*continuation)(void *private_data, BOOL success);
338 void *private_data;
341 static void init_child_recv(void *private_data, BOOL success);
342 static void init_child_getdc_recv(void *private_data, BOOL success);
344 enum winbindd_result init_child_connection(struct winbindd_domain *domain,
345 void (*continuation)(void *private_data,
346 BOOL success),
347 void *private_data)
349 TALLOC_CTX *mem_ctx;
350 struct winbindd_request *request;
351 struct winbindd_response *response;
352 struct init_child_state *state;
353 struct winbindd_domain *request_domain;
355 mem_ctx = talloc_init("init_child_connection");
356 if (mem_ctx == NULL) {
357 DEBUG(0, ("talloc_init failed\n"));
358 return WINBINDD_ERROR;
361 request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
362 response = TALLOC_P(mem_ctx, struct winbindd_response);
363 state = TALLOC_P(mem_ctx, struct init_child_state);
365 if ((request == NULL) || (response == NULL) || (state == NULL)) {
366 DEBUG(0, ("talloc failed\n"));
367 TALLOC_FREE(mem_ctx);
368 continuation(private_data, False);
369 return WINBINDD_ERROR;
372 request->length = sizeof(*request);
374 state->mem_ctx = mem_ctx;
375 state->domain = domain;
376 state->request = request;
377 state->response = response;
378 state->continuation = continuation;
379 state->private_data = private_data;
381 if (IS_DC || domain->primary) {
382 /* The primary domain has to find the DC name itself */
383 request->cmd = WINBINDD_INIT_CONNECTION;
384 fstrcpy(request->domain_name, domain->name);
385 request->data.init_conn.is_primary = True;
386 fstrcpy(request->data.init_conn.dcname, "");
387 async_request(mem_ctx, &domain->child, request, response,
388 init_child_recv, state);
389 return WINBINDD_PENDING;
392 /* This is *not* the primary domain, let's ask our DC about a DC
393 * name */
395 request->cmd = WINBINDD_GETDCNAME;
396 fstrcpy(request->domain_name, domain->name);
398 request_domain = find_our_domain();
400 async_domain_request(mem_ctx, request_domain, request, response,
401 init_child_getdc_recv, state);
402 return WINBINDD_PENDING;
405 static void init_child_getdc_recv(void *private_data, BOOL success)
407 struct init_child_state *state =
408 talloc_get_type_abort(private_data, struct init_child_state);
409 const char *dcname = "";
411 DEBUG(10, ("Received getdcname response\n"));
413 if (success && (state->response->result == WINBINDD_OK)) {
414 dcname = state->response->data.dc_name;
417 state->request->cmd = WINBINDD_INIT_CONNECTION;
418 fstrcpy(state->request->domain_name, state->domain->name);
419 state->request->data.init_conn.is_primary = False;
420 fstrcpy(state->request->data.init_conn.dcname, dcname);
422 async_request(state->mem_ctx, &state->domain->child,
423 state->request, state->response,
424 init_child_recv, state);
427 static void init_child_recv(void *private_data, BOOL success)
429 struct init_child_state *state =
430 talloc_get_type_abort(private_data, struct init_child_state);
432 DEBUG(5, ("Received child initialization response for domain %s\n",
433 state->domain->name));
435 if ((!success) || (state->response->result != WINBINDD_OK)) {
436 DEBUG(3, ("Could not init child\n"));
437 state->continuation(state->private_data, False);
438 talloc_destroy(state->mem_ctx);
439 return;
442 fstrcpy(state->domain->name,
443 state->response->data.domain_info.name);
444 fstrcpy(state->domain->alt_name,
445 state->response->data.domain_info.alt_name);
446 string_to_sid(&state->domain->sid,
447 state->response->data.domain_info.sid);
448 state->domain->native_mode =
449 state->response->data.domain_info.native_mode;
450 state->domain->active_directory =
451 state->response->data.domain_info.active_directory;
452 state->domain->sequence_number =
453 state->response->data.domain_info.sequence_number;
455 init_dc_connection(state->domain);
457 if (state->continuation != NULL)
458 state->continuation(state->private_data, True);
459 talloc_destroy(state->mem_ctx);
462 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
463 struct winbindd_cli_state *state)
465 /* Ensure null termination */
466 state->request.domain_name
467 [sizeof(state->request.domain_name)-1]='\0';
468 state->request.data.init_conn.dcname
469 [sizeof(state->request.data.init_conn.dcname)-1]='\0';
471 if (strlen(state->request.data.init_conn.dcname) > 0) {
472 fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
475 init_dc_connection(domain);
477 if (!domain->initialized) {
478 /* If we return error here we can't do any cached authentication,
479 but we may be in disconnected mode and can't initialize correctly.
480 Do what the previous code did and just return without initialization,
481 once we go online we'll re-initialize.
483 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
484 "online = %d\n", domain->name, (int)domain->online ));
487 fstrcpy(state->response.data.domain_info.name, domain->name);
488 fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
489 fstrcpy(state->response.data.domain_info.sid,
490 sid_string_static(&domain->sid));
492 state->response.data.domain_info.native_mode
493 = domain->native_mode;
494 state->response.data.domain_info.active_directory
495 = domain->active_directory;
496 state->response.data.domain_info.primary
497 = domain->primary;
498 state->response.data.domain_info.sequence_number =
499 domain->sequence_number;
501 return WINBINDD_OK;
504 /* Look up global info for the winbind daemon */
505 BOOL init_domain_list(void)
507 struct winbindd_domain *domain;
508 int role = lp_server_role();
510 /* Free existing list */
511 free_domain_list();
513 /* Add ourselves as the first entry. */
515 if ( role == ROLE_DOMAIN_MEMBER ) {
516 DOM_SID our_sid;
518 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
519 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
520 return False;
523 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
524 &cache_methods, &our_sid);
525 domain->primary = True;
526 setup_domain_child(domain, &domain->child, NULL);
528 /* Even in the parent winbindd we'll need to
529 talk to the DC, so try and see if we can
530 contact it. Theoretically this isn't neccessary
531 as the init_dc_connection() in init_child_recv()
532 will do this, but we can start detecting the DC
533 early here. */
534 set_domain_online_request(domain);
537 /* Local SAM */
539 domain = add_trusted_domain(get_global_sam_name(), NULL,
540 &passdb_methods, get_global_sam_sid());
541 if ( role != ROLE_DOMAIN_MEMBER ) {
542 domain->primary = True;
544 setup_domain_child(domain, &domain->child, NULL);
546 /* BUILTIN domain */
548 domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
549 &global_sid_Builtin);
550 setup_domain_child(domain, &domain->child, NULL);
552 return True;
555 /**
556 * Given a domain name, return the struct winbindd domain info for it
558 * @note Do *not* pass lp_workgroup() to this function. domain_list
559 * may modify it's value, and free that pointer. Instead, our local
560 * domain may be found by calling find_our_domain().
561 * directly.
564 * @return The domain structure for the named domain, if it is working.
567 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
569 struct winbindd_domain *domain;
571 /* Search through list */
573 for (domain = domain_list(); domain != NULL; domain = domain->next) {
574 if (strequal(domain_name, domain->name) ||
575 (domain->alt_name[0] &&
576 strequal(domain_name, domain->alt_name))) {
577 return domain;
581 /* Not found */
583 return NULL;
586 struct winbindd_domain *find_domain_from_name(const char *domain_name)
588 struct winbindd_domain *domain;
590 domain = find_domain_from_name_noinit(domain_name);
592 if (domain == NULL)
593 return NULL;
595 if (!domain->initialized)
596 init_dc_connection(domain);
598 return domain;
601 /* Given a domain sid, return the struct winbindd domain info for it */
603 struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
605 struct winbindd_domain *domain;
607 /* Search through list */
609 for (domain = domain_list(); domain != NULL; domain = domain->next) {
610 if (sid_compare_domain(sid, &domain->sid) == 0)
611 return domain;
614 /* Not found */
616 return NULL;
619 /* Given a domain sid, return the struct winbindd domain info for it */
621 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
623 struct winbindd_domain *domain;
625 domain = find_domain_from_sid_noinit(sid);
627 if (domain == NULL)
628 return NULL;
630 if (!domain->initialized)
631 init_dc_connection(domain);
633 return domain;
636 struct winbindd_domain *find_our_domain(void)
638 struct winbindd_domain *domain;
640 /* Search through list */
642 for (domain = domain_list(); domain != NULL; domain = domain->next) {
643 if (domain->primary)
644 return domain;
647 smb_panic("Could not find our domain\n");
648 return NULL;
651 struct winbindd_domain *find_root_domain(void)
653 struct winbindd_domain *ours = find_our_domain();
655 if ( !ours )
656 return NULL;
658 if ( strlen(ours->forest_name) == 0 )
659 return NULL;
661 return find_domain_from_name( ours->forest_name );
664 struct winbindd_domain *find_builtin_domain(void)
666 DOM_SID sid;
667 struct winbindd_domain *domain;
669 string_to_sid(&sid, "S-1-5-32");
670 domain = find_domain_from_sid(&sid);
672 if (domain == NULL)
673 smb_panic("Could not find BUILTIN domain\n");
675 return domain;
678 /* Find the appropriate domain to lookup a name or SID */
680 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
682 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
683 * one to contact the external DC's. On member servers the internal
684 * domains are different: These are part of the local SAM. */
686 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n",
687 sid_string_static(sid)));
689 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
690 DEBUG(10, ("calling find_domain_from_sid\n"));
691 return find_domain_from_sid(sid);
694 /* On a member server a query for SID or name can always go to our
695 * primary DC. */
697 DEBUG(10, ("calling find_our_domain\n"));
698 return find_our_domain();
701 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
703 if (IS_DC || strequal(domain_name, "BUILTIN") ||
704 strequal(domain_name, get_global_sam_name()))
705 return find_domain_from_name_noinit(domain_name);
707 return find_our_domain();
710 /* Lookup a sid in a domain from a name */
712 BOOL winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
713 struct winbindd_domain *domain,
714 const char *domain_name,
715 const char *name, DOM_SID *sid,
716 enum lsa_SidType *type)
718 NTSTATUS result;
720 /* Lookup name */
721 result = domain->methods->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
723 /* Return sid and type if lookup successful */
724 if (!NT_STATUS_IS_OK(result)) {
725 *type = SID_NAME_UNKNOWN;
728 return NT_STATUS_IS_OK(result);
732 * @brief Lookup a name in a domain from a sid.
734 * @param sid Security ID you want to look up.
735 * @param name On success, set to the name corresponding to @p sid.
736 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
737 * @param type On success, contains the type of name: alias, group or
738 * user.
739 * @retval True if the name exists, in which case @p name and @p type
740 * are set, otherwise False.
742 BOOL winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
743 DOM_SID *sid,
744 char **dom_name,
745 char **name,
746 enum lsa_SidType *type)
748 NTSTATUS result;
749 struct winbindd_domain *domain;
751 *dom_name = NULL;
752 *name = NULL;
754 domain = find_lookup_domain_from_sid(sid);
756 if (!domain) {
757 DEBUG(1,("Can't find domain from sid\n"));
758 return False;
761 /* Lookup name */
763 result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
765 /* Return name and type if successful */
767 if (NT_STATUS_IS_OK(result)) {
768 return True;
771 *type = SID_NAME_UNKNOWN;
773 return False;
776 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
778 void free_getent_state(struct getent_state *state)
780 struct getent_state *temp;
782 /* Iterate over state list */
784 temp = state;
786 while(temp != NULL) {
787 struct getent_state *next;
789 /* Free sam entries then list entry */
791 SAFE_FREE(state->sam_entries);
792 DLIST_REMOVE(state, state);
793 next = temp->next;
795 SAFE_FREE(temp);
796 temp = next;
800 /* Is this a domain which we may assume no DOMAIN\ prefix? */
802 static BOOL assume_domain(const char *domain)
804 /* never assume the domain on a standalone server */
806 if ( lp_server_role() == ROLE_STANDALONE )
807 return False;
809 /* domain member servers may possibly assume for the domain name */
811 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
812 if ( !strequal(lp_workgroup(), domain) )
813 return False;
815 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
816 return True;
819 /* only left with a domain controller */
821 if ( strequal(get_global_sam_name(), domain) ) {
822 return True;
825 return False;
828 /* Parse a string of the form DOMAIN\user into a domain and a user */
830 BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
832 char *p = strchr(domuser,*lp_winbind_separator());
834 if ( !p ) {
835 fstrcpy(user, domuser);
837 if ( assume_domain(lp_workgroup())) {
838 fstrcpy(domain, lp_workgroup());
839 } else {
840 return False;
842 } else {
843 fstrcpy(user, p+1);
844 fstrcpy(domain, domuser);
845 domain[PTR_DIFF(p, domuser)] = 0;
848 strupper_m(domain);
850 return True;
853 BOOL parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
854 char **domain, char **user)
856 fstring fstr_domain, fstr_user;
857 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
858 return False;
860 *domain = talloc_strdup(mem_ctx, fstr_domain);
861 *user = talloc_strdup(mem_ctx, fstr_user);
862 return ((*domain != NULL) && (*user != NULL));
865 /* Ensure an incoming username from NSS is fully qualified. Replace the
866 incoming fstring with DOMAIN <separator> user. Returns the same
867 values as parse_domain_user() but also replaces the incoming username.
868 Used to ensure all names are fully qualified within winbindd.
869 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
870 The protocol definitions of auth_crap, chng_pswd_auth_crap
871 really should be changed to use this instead of doing things
872 by hand. JRA. */
874 BOOL canonicalize_username(fstring username_inout, fstring domain, fstring user)
876 if (!parse_domain_user(username_inout, domain, user)) {
877 return False;
879 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
880 domain, *lp_winbind_separator(),
881 user);
882 return True;
886 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
887 'winbind separator' options.
888 This means:
889 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
890 lp_workgroup()
892 If we are a PDC or BDC, and this is for our domain, do likewise.
894 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
895 username is then unqualified in unix
897 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
899 void fill_domain_username(fstring name, const char *domain, const char *user, BOOL can_assume)
901 fstring tmp_user;
903 fstrcpy(tmp_user, user);
904 strlower_m(tmp_user);
906 if (can_assume && assume_domain(domain)) {
907 strlcpy(name, tmp_user, sizeof(fstring));
908 } else {
909 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
910 domain, *lp_winbind_separator(),
911 tmp_user);
916 * Winbindd socket accessor functions
919 char *get_winbind_priv_pipe_dir(void)
921 return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
924 /* Open the winbindd socket */
926 static int _winbindd_socket = -1;
927 static int _winbindd_priv_socket = -1;
929 int open_winbindd_socket(void)
931 if (_winbindd_socket == -1) {
932 _winbindd_socket = create_pipe_sock(
933 WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME, 0755);
934 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
935 _winbindd_socket));
938 return _winbindd_socket;
941 int open_winbindd_priv_socket(void)
943 if (_winbindd_priv_socket == -1) {
944 _winbindd_priv_socket = create_pipe_sock(
945 get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
946 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
947 _winbindd_priv_socket));
950 return _winbindd_priv_socket;
953 /* Close the winbindd socket */
955 void close_winbindd_socket(void)
957 if (_winbindd_socket != -1) {
958 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
959 _winbindd_socket));
960 close(_winbindd_socket);
961 _winbindd_socket = -1;
963 if (_winbindd_priv_socket != -1) {
964 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
965 _winbindd_priv_socket));
966 close(_winbindd_priv_socket);
967 _winbindd_priv_socket = -1;
972 * Client list accessor functions
975 static struct winbindd_cli_state *_client_list;
976 static int _num_clients;
978 /* Return list of all connected clients */
980 struct winbindd_cli_state *winbindd_client_list(void)
982 return _client_list;
985 /* Add a connection to the list */
987 void winbindd_add_client(struct winbindd_cli_state *cli)
989 DLIST_ADD(_client_list, cli);
990 _num_clients++;
993 /* Remove a client from the list */
995 void winbindd_remove_client(struct winbindd_cli_state *cli)
997 DLIST_REMOVE(_client_list, cli);
998 _num_clients--;
1001 /* Close all open clients */
1003 void winbindd_kill_all_clients(void)
1005 struct winbindd_cli_state *cl = winbindd_client_list();
1007 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1009 while (cl) {
1010 struct winbindd_cli_state *next;
1012 next = cl->next;
1013 winbindd_remove_client(cl);
1014 cl = next;
1018 /* Return number of open clients */
1020 int winbindd_num_clients(void)
1022 return _num_clients;
1025 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1026 TALLOC_CTX *mem_ctx,
1027 const DOM_SID *user_sid,
1028 uint32 *p_num_groups, DOM_SID **user_sids)
1030 NET_USER_INFO_3 *info3 = NULL;
1031 NTSTATUS status = NT_STATUS_NO_MEMORY;
1032 int i;
1033 size_t num_groups = 0;
1034 DOM_SID group_sid, primary_group;
1036 DEBUG(3,(": lookup_usergroups_cached\n"));
1038 *user_sids = NULL;
1039 num_groups = 0;
1040 *p_num_groups = 0;
1042 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1044 if (info3 == NULL) {
1045 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1048 if (info3->num_groups == 0) {
1049 TALLOC_FREE(info3);
1050 return NT_STATUS_UNSUCCESSFUL;
1053 /* always add the primary group to the sid array */
1054 sid_compose(&primary_group, &info3->dom_sid.sid, info3->user_rid);
1056 if (!add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups)) {
1057 TALLOC_FREE(info3);
1058 return NT_STATUS_NO_MEMORY;
1061 for (i=0; i<info3->num_groups; i++) {
1062 sid_copy(&group_sid, &info3->dom_sid.sid);
1063 sid_append_rid(&group_sid, info3->gids[i].g_rid);
1065 if (!add_sid_to_array(mem_ctx, &group_sid, user_sids,
1066 &num_groups)) {
1067 TALLOC_FREE(info3);
1068 return NT_STATUS_NO_MEMORY;
1072 TALLOC_FREE(info3);
1073 *p_num_groups = num_groups;
1074 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1076 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1078 return status;
1081 /*********************************************************************
1082 We use this to remove spaces from user and group names
1083 ********************************************************************/
1085 void ws_name_replace( char *name, char replace )
1087 char replace_char[2] = { 0x0, 0x0 };
1089 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1090 return;
1092 replace_char[0] = replace;
1093 all_string_sub( name, " ", replace_char, 0 );
1095 return;
1098 /*********************************************************************
1099 We use this to do the inverse of ws_name_replace()
1100 ********************************************************************/
1102 void ws_name_return( char *name, char replace )
1104 char replace_char[2] = { 0x0, 0x0 };
1106 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1107 return;
1109 replace_char[0] = replace;
1110 all_string_sub( name, replace_char, " ", 0 );
1112 return;