r20057: Attempt to fix connect timeouts when connected on
[Samba/nascimento.git] / source3 / nsswitch / winbindd_util.c
blob98990664e377f0b678794f31fa213f36ad7681e3
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 /**
31 * @file winbindd_util.c
33 * Winbind daemon for NT domain authentication nss module.
34 **/
37 /**
38 * Used to clobber name fields that have an undefined value.
40 * Correct code should never look at a field that has this value.
41 **/
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;
52 /**
53 When was the last scan of trusted domains done?
55 0 == not ever
58 static time_t last_trustdom_scan;
60 struct winbindd_domain *domain_list(void)
62 /* Initialise list */
64 if ((!_domain_list) && (!init_domain_list())) {
65 smb_panic("Init_domain_list failed\n");
68 return _domain_list;
71 /* Free all entries in the trusted domain list */
73 void free_domain_list(void)
75 struct winbindd_domain *domain = _domain_list;
77 while(domain) {
78 struct winbindd_domain *next = domain->next;
80 DLIST_REMOVE(_domain_list, domain);
81 SAFE_FREE(domain);
82 domain = next;
86 static BOOL is_internal_domain(const DOM_SID *sid)
88 if (sid == NULL)
89 return False;
91 return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
94 static BOOL is_in_internal_domain(const DOM_SID *sid)
96 if (sid == NULL)
97 return False;
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,
106 const DOM_SID *sid)
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)) {
122 return domain;
124 if (alternative_name && *alternative_name) {
125 if (strequal(alternative_name, domain->name) ||
126 strequal(alternative_name, domain->alt_name)) {
127 return domain;
130 if (sid) {
131 if (is_null_sid(sid)) {
133 } else if (sid_equal(sid, &domain->sid)) {
134 return domain;
139 /* Create new domain entry */
141 if ((domain = SMB_MALLOC_P(struct winbindd_domain)) == NULL)
142 return NULL;
144 /* Fill in fields */
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);
152 } else {
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);
166 domain->check_online_timeout = 0;
167 if (sid) {
168 sid_copy(&domain->sid, sid);
171 /* Link to domain list */
172 DLIST_ADD(_domain_list, domain);
174 DEBUG(2,("Added domain %s %s %s\n",
175 domain->name, domain->alt_name,
176 &domain->sid?sid_string_static(&domain->sid):""));
178 return domain;
181 /********************************************************************
182 rescan our domains looking for new trusted domains
183 ********************************************************************/
185 struct trustdom_state {
186 TALLOC_CTX *mem_ctx;
187 struct winbindd_response *response;
190 static void trustdom_recv(void *private_data, BOOL success);
192 static void add_trusted_domains( struct winbindd_domain *domain )
194 TALLOC_CTX *mem_ctx;
195 struct winbindd_request *request;
196 struct winbindd_response *response;
198 struct trustdom_state *state;
200 mem_ctx = talloc_init("add_trusted_domains");
201 if (mem_ctx == NULL) {
202 DEBUG(0, ("talloc_init failed\n"));
203 return;
206 request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
207 response = TALLOC_P(mem_ctx, struct winbindd_response);
208 state = TALLOC_P(mem_ctx, struct trustdom_state);
210 if ((request == NULL) || (response == NULL) || (state == NULL)) {
211 DEBUG(0, ("talloc failed\n"));
212 talloc_destroy(mem_ctx);
213 return;
216 state->mem_ctx = mem_ctx;
217 state->response = response;
219 request->length = sizeof(*request);
220 request->cmd = WINBINDD_LIST_TRUSTDOM;
222 async_domain_request(mem_ctx, domain, request, response,
223 trustdom_recv, state);
226 static void trustdom_recv(void *private_data, BOOL success)
228 extern struct winbindd_methods cache_methods;
229 struct trustdom_state *state =
230 talloc_get_type_abort(private_data, struct trustdom_state);
231 struct winbindd_response *response = state->response;
232 char *p;
234 if ((!success) || (response->result != WINBINDD_OK)) {
235 DEBUG(1, ("Could not receive trustdoms\n"));
236 talloc_destroy(state->mem_ctx);
237 return;
240 p = (char *)response->extra_data.data;
242 while ((p != NULL) && (*p != '\0')) {
243 char *q, *sidstr, *alt_name;
244 DOM_SID sid;
246 alt_name = strchr(p, '\\');
247 if (alt_name == NULL) {
248 DEBUG(0, ("Got invalid trustdom response\n"));
249 break;
252 *alt_name = '\0';
253 alt_name += 1;
255 sidstr = strchr(alt_name, '\\');
256 if (sidstr == NULL) {
257 DEBUG(0, ("Got invalid trustdom response\n"));
258 break;
261 *sidstr = '\0';
262 sidstr += 1;
264 q = strchr(sidstr, '\n');
265 if (q != NULL)
266 *q = '\0';
268 if (!string_to_sid(&sid, sidstr)) {
269 DEBUG(0, ("Got invalid trustdom response\n"));
270 break;
273 if (find_domain_from_name_noinit(p) == NULL) {
274 struct winbindd_domain *domain;
275 char *alternate_name = NULL;
277 /* use the real alt_name if we have one, else pass in NULL */
279 if ( !strequal( alt_name, "(null)" ) )
280 alternate_name = alt_name;
282 domain = add_trusted_domain(p, alternate_name,
283 &cache_methods,
284 &sid);
285 setup_domain_child(domain, &domain->child, NULL);
287 p=q;
288 if (p != NULL)
289 p += 1;
292 SAFE_FREE(response->extra_data.data);
293 talloc_destroy(state->mem_ctx);
296 /********************************************************************
297 Periodically we need to refresh the trusted domain cache for smbd
298 ********************************************************************/
300 void rescan_trusted_domains( void )
302 time_t now = time(NULL);
304 /* see if the time has come... */
306 if ((now >= last_trustdom_scan) &&
307 ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
308 return;
310 /* this will only add new domains we didn't already know about */
312 add_trusted_domains( find_our_domain() );
314 last_trustdom_scan = now;
316 return;
319 struct init_child_state {
320 TALLOC_CTX *mem_ctx;
321 struct winbindd_domain *domain;
322 struct winbindd_request *request;
323 struct winbindd_response *response;
324 void (*continuation)(void *private_data, BOOL success);
325 void *private_data;
328 static void init_child_recv(void *private_data, BOOL success);
329 static void init_child_getdc_recv(void *private_data, BOOL success);
331 enum winbindd_result init_child_connection(struct winbindd_domain *domain,
332 void (*continuation)(void *private_data,
333 BOOL success),
334 void *private_data)
336 TALLOC_CTX *mem_ctx;
337 struct winbindd_request *request;
338 struct winbindd_response *response;
339 struct init_child_state *state;
340 struct winbindd_domain *request_domain;
342 mem_ctx = talloc_init("init_child_connection");
343 if (mem_ctx == NULL) {
344 DEBUG(0, ("talloc_init failed\n"));
345 return WINBINDD_ERROR;
348 request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
349 response = TALLOC_P(mem_ctx, struct winbindd_response);
350 state = TALLOC_P(mem_ctx, struct init_child_state);
352 if ((request == NULL) || (response == NULL) || (state == NULL)) {
353 DEBUG(0, ("talloc failed\n"));
354 TALLOC_FREE(mem_ctx);
355 continuation(private_data, False);
356 return WINBINDD_ERROR;
359 request->length = sizeof(*request);
361 state->mem_ctx = mem_ctx;
362 state->domain = domain;
363 state->request = request;
364 state->response = response;
365 state->continuation = continuation;
366 state->private_data = private_data;
368 if (IS_DC || domain->primary) {
369 /* The primary domain has to find the DC name itself */
370 request->cmd = WINBINDD_INIT_CONNECTION;
371 fstrcpy(request->domain_name, domain->name);
372 request->data.init_conn.is_primary = True;
373 fstrcpy(request->data.init_conn.dcname, "");
374 async_request(mem_ctx, &domain->child, request, response,
375 init_child_recv, state);
376 return WINBINDD_PENDING;
379 /* This is *not* the primary domain, let's ask our DC about a DC
380 * name */
382 request->cmd = WINBINDD_GETDCNAME;
383 fstrcpy(request->domain_name, domain->name);
385 /* save online flag */
386 request_domain = find_our_domain();
387 request_domain->online = domain->online;
389 async_domain_request(mem_ctx, request_domain, request, response,
390 init_child_getdc_recv, state);
391 return WINBINDD_PENDING;
394 static void init_child_getdc_recv(void *private_data, BOOL success)
396 struct init_child_state *state =
397 talloc_get_type_abort(private_data, struct init_child_state);
398 const char *dcname = "";
400 DEBUG(10, ("Received getdcname response\n"));
402 if (success && (state->response->result == WINBINDD_OK)) {
403 dcname = state->response->data.dc_name;
406 state->request->cmd = WINBINDD_INIT_CONNECTION;
407 fstrcpy(state->request->domain_name, state->domain->name);
408 state->request->data.init_conn.is_primary = False;
409 fstrcpy(state->request->data.init_conn.dcname, dcname);
411 async_request(state->mem_ctx, &state->domain->child,
412 state->request, state->response,
413 init_child_recv, state);
416 static void init_child_recv(void *private_data, BOOL success)
418 struct init_child_state *state =
419 talloc_get_type_abort(private_data, struct init_child_state);
421 DEBUG(5, ("Received child initialization response for domain %s\n",
422 state->domain->name));
424 if ((!success) || (state->response->result != WINBINDD_OK)) {
425 DEBUG(3, ("Could not init child\n"));
426 state->continuation(state->private_data, False);
427 talloc_destroy(state->mem_ctx);
428 return;
431 fstrcpy(state->domain->name,
432 state->response->data.domain_info.name);
433 fstrcpy(state->domain->alt_name,
434 state->response->data.domain_info.alt_name);
435 string_to_sid(&state->domain->sid,
436 state->response->data.domain_info.sid);
437 state->domain->native_mode =
438 state->response->data.domain_info.native_mode;
439 state->domain->active_directory =
440 state->response->data.domain_info.active_directory;
441 state->domain->sequence_number =
442 state->response->data.domain_info.sequence_number;
444 state->domain->initialized = 1;
446 if (state->continuation != NULL)
447 state->continuation(state->private_data, True);
448 talloc_destroy(state->mem_ctx);
451 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
452 struct winbindd_cli_state *state)
454 /* Ensure null termination */
455 state->request.domain_name
456 [sizeof(state->request.domain_name)-1]='\0';
457 state->request.data.init_conn.dcname
458 [sizeof(state->request.data.init_conn.dcname)-1]='\0';
460 if (strlen(state->request.data.init_conn.dcname) > 0) {
461 fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
464 init_dc_connection(domain);
466 if (!domain->initialized) {
467 /* If we return error here we can't do any cached authentication,
468 but we may be in disconnected mode and can't initialize correctly.
469 Do what the previous code did and just return without initialization,
470 once we go online we'll re-initialize.
472 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
473 "online = %d\n", domain->name, (int)domain->online ));
476 fstrcpy(state->response.data.domain_info.name, domain->name);
477 fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
478 fstrcpy(state->response.data.domain_info.sid,
479 sid_string_static(&domain->sid));
481 state->response.data.domain_info.native_mode
482 = domain->native_mode;
483 state->response.data.domain_info.active_directory
484 = domain->active_directory;
485 state->response.data.domain_info.primary
486 = domain->primary;
487 state->response.data.domain_info.sequence_number =
488 domain->sequence_number;
490 return WINBINDD_OK;
493 /* Look up global info for the winbind daemon */
494 BOOL init_domain_list(void)
496 extern struct winbindd_methods cache_methods;
497 extern struct winbindd_methods passdb_methods;
498 struct winbindd_domain *domain;
499 int role = lp_server_role();
501 /* Free existing list */
502 free_domain_list();
504 /* Add ourselves as the first entry. */
506 if ( role == ROLE_DOMAIN_MEMBER ) {
507 DOM_SID our_sid;
509 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
510 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
511 return False;
514 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
515 &cache_methods, &our_sid);
516 domain->primary = True;
517 setup_domain_child(domain, &domain->child, NULL);
520 /* Local SAM */
522 domain = add_trusted_domain(get_global_sam_name(), NULL,
523 &passdb_methods, get_global_sam_sid());
524 if ( role != ROLE_DOMAIN_MEMBER ) {
525 domain->primary = True;
527 setup_domain_child(domain, &domain->child, NULL);
529 /* BUILTIN domain */
531 domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
532 &global_sid_Builtin);
533 setup_domain_child(domain, &domain->child, NULL);
535 return True;
538 /**
539 * Given a domain name, return the struct winbindd domain info for it
541 * @note Do *not* pass lp_workgroup() to this function. domain_list
542 * may modify it's value, and free that pointer. Instead, our local
543 * domain may be found by calling find_our_domain().
544 * directly.
547 * @return The domain structure for the named domain, if it is working.
550 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
552 struct winbindd_domain *domain;
554 /* Search through list */
556 for (domain = domain_list(); domain != NULL; domain = domain->next) {
557 if (strequal(domain_name, domain->name) ||
558 (domain->alt_name[0] &&
559 strequal(domain_name, domain->alt_name))) {
560 return domain;
564 /* Not found */
566 return NULL;
569 struct winbindd_domain *find_domain_from_name(const char *domain_name)
571 struct winbindd_domain *domain;
573 domain = find_domain_from_name_noinit(domain_name);
575 if (domain == NULL)
576 return NULL;
578 if (!domain->initialized)
579 init_dc_connection(domain);
581 return domain;
584 /* Given a domain sid, return the struct winbindd domain info for it */
586 struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
588 struct winbindd_domain *domain;
590 /* Search through list */
592 for (domain = domain_list(); domain != NULL; domain = domain->next) {
593 if (sid_compare_domain(sid, &domain->sid) == 0)
594 return domain;
597 /* Not found */
599 return NULL;
602 /* Given a domain sid, return the struct winbindd domain info for it */
604 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
606 struct winbindd_domain *domain;
608 domain = find_domain_from_sid_noinit(sid);
610 if (domain == NULL)
611 return NULL;
613 if (!domain->initialized)
614 init_dc_connection(domain);
616 return domain;
619 struct winbindd_domain *find_our_domain(void)
621 struct winbindd_domain *domain;
623 /* Search through list */
625 for (domain = domain_list(); domain != NULL; domain = domain->next) {
626 if (domain->primary)
627 return domain;
630 smb_panic("Could not find our domain\n");
631 return NULL;
634 struct winbindd_domain *find_builtin_domain(void)
636 DOM_SID sid;
637 struct winbindd_domain *domain;
639 string_to_sid(&sid, "S-1-5-32");
640 domain = find_domain_from_sid(&sid);
642 if (domain == NULL)
643 smb_panic("Could not find BUILTIN domain\n");
645 return domain;
648 /* Find the appropriate domain to lookup a name or SID */
650 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
652 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
653 * one to contact the external DC's. On member servers the internal
654 * domains are different: These are part of the local SAM. */
656 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n",
657 sid_string_static(sid)));
659 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
660 DEBUG(10, ("calling find_domain_from_sid\n"));
661 return find_domain_from_sid(sid);
664 /* On a member server a query for SID or name can always go to our
665 * primary DC. */
667 DEBUG(10, ("calling find_our_domain\n"));
668 return find_our_domain();
671 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
673 if (IS_DC || strequal(domain_name, "BUILTIN") ||
674 strequal(domain_name, get_global_sam_name()))
675 return find_domain_from_name_noinit(domain_name);
677 return find_our_domain();
680 /* Lookup a sid in a domain from a name */
682 BOOL winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
683 struct winbindd_domain *domain,
684 const char *domain_name,
685 const char *name, DOM_SID *sid,
686 enum lsa_SidType *type)
688 NTSTATUS result;
690 /* Lookup name */
691 result = domain->methods->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
693 /* Return rid and type if lookup successful */
694 if (!NT_STATUS_IS_OK(result)) {
695 *type = SID_NAME_UNKNOWN;
698 return NT_STATUS_IS_OK(result);
702 * @brief Lookup a name in a domain from a sid.
704 * @param sid Security ID you want to look up.
705 * @param name On success, set to the name corresponding to @p sid.
706 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
707 * @param type On success, contains the type of name: alias, group or
708 * user.
709 * @retval True if the name exists, in which case @p name and @p type
710 * are set, otherwise False.
712 BOOL winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
713 DOM_SID *sid,
714 fstring dom_name,
715 fstring name,
716 enum lsa_SidType *type)
718 char *names;
719 char *dom_names;
720 NTSTATUS result;
721 BOOL rv = False;
722 struct winbindd_domain *domain;
724 domain = find_lookup_domain_from_sid(sid);
726 if (!domain) {
727 DEBUG(1,("Can't find domain from sid\n"));
728 return False;
731 /* Lookup name */
733 result = domain->methods->sid_to_name(domain, mem_ctx, sid, &dom_names, &names, type);
735 /* Return name and type if successful */
737 if ((rv = NT_STATUS_IS_OK(result))) {
738 fstrcpy(dom_name, dom_names);
739 fstrcpy(name, names);
740 } else {
741 *type = SID_NAME_UNKNOWN;
742 fstrcpy(name, name_deadbeef);
745 return rv;
748 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
750 void free_getent_state(struct getent_state *state)
752 struct getent_state *temp;
754 /* Iterate over state list */
756 temp = state;
758 while(temp != NULL) {
759 struct getent_state *next;
761 /* Free sam entries then list entry */
763 SAFE_FREE(state->sam_entries);
764 DLIST_REMOVE(state, state);
765 next = temp->next;
767 SAFE_FREE(temp);
768 temp = next;
772 /* Parse winbindd related parameters */
774 BOOL winbindd_param_init(void)
776 /* Parse winbind uid and winbind_gid parameters */
778 if (!lp_idmap_uid(&server_state.uid_low, &server_state.uid_high)) {
779 DEBUG(0, ("winbindd: idmap uid range missing or invalid\n"));
780 DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
781 return False;
784 if (!lp_idmap_gid(&server_state.gid_low, &server_state.gid_high)) {
785 DEBUG(0, ("winbindd: idmap gid range missing or invalid\n"));
786 DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
787 return False;
790 return True;
793 BOOL is_in_uid_range(uid_t uid)
795 return ((uid >= server_state.uid_low) &&
796 (uid <= server_state.uid_high));
799 BOOL is_in_gid_range(gid_t gid)
801 return ((gid >= server_state.gid_low) &&
802 (gid <= server_state.gid_high));
805 /* Is this a domain which we may assume no DOMAIN\ prefix? */
807 static BOOL assume_domain(const char *domain)
809 /* never assume the domain on a standalone server */
811 if ( lp_server_role() == ROLE_STANDALONE )
812 return False;
814 /* domain member servers may possibly assume for the domain name */
816 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
817 if ( !strequal(lp_workgroup(), domain) )
818 return False;
820 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
821 return True;
824 /* only left with a domain controller */
826 if ( strequal(get_global_sam_name(), domain) ) {
827 return True;
830 return False;
833 /* Parse a string of the form DOMAIN\user into a domain and a user */
835 BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
837 char *p = strchr(domuser,*lp_winbind_separator());
839 if ( !p ) {
840 fstrcpy(user, domuser);
842 if ( assume_domain(lp_workgroup())) {
843 fstrcpy(domain, lp_workgroup());
844 } else {
845 return False;
847 } else {
848 fstrcpy(user, p+1);
849 fstrcpy(domain, domuser);
850 domain[PTR_DIFF(p, domuser)] = 0;
853 strupper_m(domain);
855 return True;
858 BOOL parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
859 char **domain, char **user)
861 fstring fstr_domain, fstr_user;
862 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
863 return False;
865 *domain = talloc_strdup(mem_ctx, fstr_domain);
866 *user = talloc_strdup(mem_ctx, fstr_user);
867 return ((*domain != NULL) && (*user != NULL));
870 /* Ensure an incoming username from NSS is fully qualified. Replace the
871 incoming fstring with DOMAIN <separator> user. Returns the same
872 values as parse_domain_user() but also replaces the incoming username.
873 Used to ensure all names are fully qualified within winbindd.
874 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
875 The protocol definitions of auth_crap, chng_pswd_auth_crap
876 really should be changed to use this instead of doing things
877 by hand. JRA. */
879 BOOL canonicalize_username(fstring username_inout, fstring domain, fstring user)
881 if (!parse_domain_user(username_inout, domain, user)) {
882 return False;
884 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
885 domain, *lp_winbind_separator(),
886 user);
887 return True;
891 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
892 'winbind separator' options.
893 This means:
894 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
895 lp_workgroup()
897 If we are a PDC or BDC, and this is for our domain, do likewise.
899 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
900 username is then unqualified in unix
902 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
904 void fill_domain_username(fstring name, const char *domain, const char *user, BOOL can_assume)
906 fstring tmp_user;
908 fstrcpy(tmp_user, user);
909 strlower_m(tmp_user);
911 if (can_assume && assume_domain(domain)) {
912 strlcpy(name, tmp_user, sizeof(fstring));
913 } else {
914 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
915 domain, *lp_winbind_separator(),
916 tmp_user);
921 * Winbindd socket accessor functions
924 char *get_winbind_priv_pipe_dir(void)
926 return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
929 /* Open the winbindd socket */
931 static int _winbindd_socket = -1;
932 static int _winbindd_priv_socket = -1;
934 int open_winbindd_socket(void)
936 if (_winbindd_socket == -1) {
937 _winbindd_socket = create_pipe_sock(
938 WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME, 0755);
939 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
940 _winbindd_socket));
943 return _winbindd_socket;
946 int open_winbindd_priv_socket(void)
948 if (_winbindd_priv_socket == -1) {
949 _winbindd_priv_socket = create_pipe_sock(
950 get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
951 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
952 _winbindd_priv_socket));
955 return _winbindd_priv_socket;
958 /* Close the winbindd socket */
960 void close_winbindd_socket(void)
962 if (_winbindd_socket != -1) {
963 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
964 _winbindd_socket));
965 close(_winbindd_socket);
966 _winbindd_socket = -1;
968 if (_winbindd_priv_socket != -1) {
969 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
970 _winbindd_priv_socket));
971 close(_winbindd_priv_socket);
972 _winbindd_priv_socket = -1;
977 * Client list accessor functions
980 static struct winbindd_cli_state *_client_list;
981 static int _num_clients;
983 /* Return list of all connected clients */
985 struct winbindd_cli_state *winbindd_client_list(void)
987 return _client_list;
990 /* Add a connection to the list */
992 void winbindd_add_client(struct winbindd_cli_state *cli)
994 DLIST_ADD(_client_list, cli);
995 _num_clients++;
998 /* Remove a client from the list */
1000 void winbindd_remove_client(struct winbindd_cli_state *cli)
1002 DLIST_REMOVE(_client_list, cli);
1003 _num_clients--;
1006 /* Close all open clients */
1008 void winbindd_kill_all_clients(void)
1010 struct winbindd_cli_state *cl = winbindd_client_list();
1012 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1014 while (cl) {
1015 struct winbindd_cli_state *next;
1017 next = cl->next;
1018 winbindd_remove_client(cl);
1019 cl = next;
1023 /* Return number of open clients */
1025 int winbindd_num_clients(void)
1027 return _num_clients;
1030 /*****************************************************************************
1031 For idmap conversion: convert one record to new format
1032 Ancient versions (eg 2.2.3a) of winbindd_idmap.tdb mapped DOMAINNAME/rid
1033 instead of the SID.
1034 *****************************************************************************/
1035 static int convert_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA data, void *state)
1037 struct winbindd_domain *domain;
1038 char *p;
1039 DOM_SID sid;
1040 uint32 rid;
1041 fstring keystr;
1042 fstring dom_name;
1043 TDB_DATA key2;
1044 BOOL *failed = (BOOL *)state;
1046 DEBUG(10,("Converting %s\n", key.dptr));
1048 p = strchr(key.dptr, '/');
1049 if (!p)
1050 return 0;
1052 *p = 0;
1053 fstrcpy(dom_name, key.dptr);
1054 *p++ = '/';
1056 domain = find_domain_from_name(dom_name);
1057 if (domain == NULL) {
1058 /* We must delete the old record. */
1059 DEBUG(0,("Unable to find domain %s\n", dom_name ));
1060 DEBUG(0,("deleting record %s\n", key.dptr ));
1062 if (tdb_delete(tdb, key) != 0) {
1063 DEBUG(0, ("Unable to delete record %s\n", key.dptr));
1064 *failed = True;
1065 return -1;
1068 return 0;
1071 rid = atoi(p);
1073 sid_copy(&sid, &domain->sid);
1074 sid_append_rid(&sid, rid);
1076 sid_to_string(keystr, &sid);
1077 key2.dptr = keystr;
1078 key2.dsize = strlen(keystr) + 1;
1080 if (tdb_store(tdb, key2, data, TDB_INSERT) != 0) {
1081 DEBUG(0,("Unable to add record %s\n", key2.dptr ));
1082 *failed = True;
1083 return -1;
1086 if (tdb_store(tdb, data, key2, TDB_REPLACE) != 0) {
1087 DEBUG(0,("Unable to update record %s\n", data.dptr ));
1088 *failed = True;
1089 return -1;
1092 if (tdb_delete(tdb, key) != 0) {
1093 DEBUG(0,("Unable to delete record %s\n", key.dptr ));
1094 *failed = True;
1095 return -1;
1098 return 0;
1101 /* These definitions are from sam/idmap_tdb.c. Replicated here just
1102 out of laziness.... :-( */
1104 /* High water mark keys */
1105 #define HWM_GROUP "GROUP HWM"
1106 #define HWM_USER "USER HWM"
1108 /*****************************************************************************
1109 Convert the idmap database from an older version.
1110 *****************************************************************************/
1112 static BOOL idmap_convert(const char *idmap_name)
1114 int32 vers;
1115 BOOL bigendianheader;
1116 BOOL failed = False;
1117 TDB_CONTEXT *idmap_tdb;
1119 if (!(idmap_tdb = tdb_open_log(idmap_name, 0,
1120 TDB_DEFAULT, O_RDWR,
1121 0600))) {
1122 DEBUG(0, ("idmap_convert: Unable to open idmap database\n"));
1123 return False;
1126 bigendianheader = (tdb_get_flags(idmap_tdb) & TDB_BIGENDIAN) ? True : False;
1128 vers = tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION");
1130 if (((vers == -1) && bigendianheader) || (IREV(vers) == IDMAP_VERSION)) {
1131 /* Arrggghh ! Bytereversed or old big-endian - make order independent ! */
1133 * high and low records were created on a
1134 * big endian machine and will need byte-reversing.
1137 int32 wm;
1139 wm = tdb_fetch_int32(idmap_tdb, HWM_USER);
1141 if (wm != -1) {
1142 wm = IREV(wm);
1143 } else {
1144 wm = server_state.uid_low;
1147 if (tdb_store_int32(idmap_tdb, HWM_USER, wm) == -1) {
1148 DEBUG(0, ("idmap_convert: Unable to byteswap user hwm in idmap database\n"));
1149 tdb_close(idmap_tdb);
1150 return False;
1153 wm = tdb_fetch_int32(idmap_tdb, HWM_GROUP);
1154 if (wm != -1) {
1155 wm = IREV(wm);
1156 } else {
1157 wm = server_state.gid_low;
1160 if (tdb_store_int32(idmap_tdb, HWM_GROUP, wm) == -1) {
1161 DEBUG(0, ("idmap_convert: Unable to byteswap group hwm in idmap database\n"));
1162 tdb_close(idmap_tdb);
1163 return False;
1167 /* the old format stored as DOMAIN/rid - now we store the SID direct */
1168 tdb_traverse(idmap_tdb, convert_fn, &failed);
1170 if (failed) {
1171 DEBUG(0, ("Problem during conversion\n"));
1172 tdb_close(idmap_tdb);
1173 return False;
1176 if (tdb_store_int32(idmap_tdb, "IDMAP_VERSION", IDMAP_VERSION) == -1) {
1177 DEBUG(0, ("idmap_convert: Unable to dtore idmap version in databse\n"));
1178 tdb_close(idmap_tdb);
1179 return False;
1182 tdb_close(idmap_tdb);
1183 return True;
1186 /*****************************************************************************
1187 Convert the idmap database from an older version if necessary
1188 *****************************************************************************/
1190 BOOL winbindd_upgrade_idmap(void)
1192 pstring idmap_name;
1193 pstring backup_name;
1194 SMB_STRUCT_STAT stbuf;
1195 TDB_CONTEXT *idmap_tdb;
1197 pstrcpy(idmap_name, lock_path("winbindd_idmap.tdb"));
1199 if (!file_exist(idmap_name, &stbuf)) {
1200 /* nothing to convert return */
1201 return True;
1204 if (!(idmap_tdb = tdb_open_log(idmap_name, 0,
1205 TDB_DEFAULT, O_RDWR,
1206 0600))) {
1207 DEBUG(0, ("idmap_convert: Unable to open idmap database\n"));
1208 return False;
1211 if (tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION") == IDMAP_VERSION) {
1212 /* nothing to convert return */
1213 tdb_close(idmap_tdb);
1214 return True;
1217 /* backup_tdb expects the tdb not to be open */
1218 tdb_close(idmap_tdb);
1220 DEBUG(0, ("Upgrading winbindd_idmap.tdb from an old version\n"));
1222 pstrcpy(backup_name, idmap_name);
1223 pstrcat(backup_name, ".bak");
1225 if (backup_tdb(idmap_name, backup_name, 0) != 0) {
1226 DEBUG(0, ("Could not backup idmap database\n"));
1227 return False;
1230 return idmap_convert(idmap_name);
1233 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1234 TALLOC_CTX *mem_ctx,
1235 const DOM_SID *user_sid,
1236 uint32 *p_num_groups, DOM_SID **user_sids)
1238 NET_USER_INFO_3 *info3 = NULL;
1239 NTSTATUS status = NT_STATUS_NO_MEMORY;
1240 int i;
1241 size_t num_groups = 0;
1242 DOM_SID group_sid, primary_group;
1244 DEBUG(3,(": lookup_usergroups_cached\n"));
1246 *user_sids = NULL;
1247 num_groups = 0;
1248 *p_num_groups = 0;
1250 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1252 if (info3 == NULL) {
1253 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1256 if (info3->num_groups == 0) {
1257 SAFE_FREE(info3);
1258 return NT_STATUS_UNSUCCESSFUL;
1261 /* always add the primary group to the sid array */
1262 sid_compose(&primary_group, &info3->dom_sid.sid, info3->user_rid);
1264 add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups);
1266 for (i=0; i<info3->num_groups; i++) {
1267 sid_copy(&group_sid, &info3->dom_sid.sid);
1268 sid_append_rid(&group_sid, info3->gids[i].g_rid);
1270 add_sid_to_array(mem_ctx, &group_sid, user_sids,
1271 &num_groups);
1274 SAFE_FREE(info3);
1275 *p_num_groups = num_groups;
1276 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1278 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1280 return status;