r19148: Finish last nights patch - make offline
[Samba.git] / source / nsswitch / winbindd_util.c
bloba6d6959446d8db4bb6ec047665b10f1146c77a39
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 if (sid) {
167 sid_copy(&domain->sid, sid);
170 /* Link to domain list */
171 DLIST_ADD(_domain_list, domain);
173 DEBUG(2,("Added domain %s %s %s\n",
174 domain->name, domain->alt_name,
175 &domain->sid?sid_string_static(&domain->sid):""));
177 return domain;
180 /********************************************************************
181 rescan our domains looking for new trusted domains
182 ********************************************************************/
184 struct trustdom_state {
185 TALLOC_CTX *mem_ctx;
186 struct winbindd_response *response;
189 static void trustdom_recv(void *private_data, BOOL success);
191 static void add_trusted_domains( struct winbindd_domain *domain )
193 TALLOC_CTX *mem_ctx;
194 struct winbindd_request *request;
195 struct winbindd_response *response;
197 struct trustdom_state *state;
199 mem_ctx = talloc_init("add_trusted_domains");
200 if (mem_ctx == NULL) {
201 DEBUG(0, ("talloc_init failed\n"));
202 return;
205 request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
206 response = TALLOC_P(mem_ctx, struct winbindd_response);
207 state = TALLOC_P(mem_ctx, struct trustdom_state);
209 if ((request == NULL) || (response == NULL) || (state == NULL)) {
210 DEBUG(0, ("talloc failed\n"));
211 talloc_destroy(mem_ctx);
212 return;
215 state->mem_ctx = mem_ctx;
216 state->response = response;
218 request->length = sizeof(*request);
219 request->cmd = WINBINDD_LIST_TRUSTDOM;
221 async_domain_request(mem_ctx, domain, request, response,
222 trustdom_recv, state);
225 static void trustdom_recv(void *private_data, BOOL success)
227 extern struct winbindd_methods cache_methods;
228 struct trustdom_state *state =
229 talloc_get_type_abort(private_data, struct trustdom_state);
230 struct winbindd_response *response = state->response;
231 char *p;
233 if ((!success) || (response->result != WINBINDD_OK)) {
234 DEBUG(1, ("Could not receive trustdoms\n"));
235 talloc_destroy(state->mem_ctx);
236 return;
239 p = (char *)response->extra_data.data;
241 while ((p != NULL) && (*p != '\0')) {
242 char *q, *sidstr, *alt_name;
243 DOM_SID sid;
245 alt_name = strchr(p, '\\');
246 if (alt_name == NULL) {
247 DEBUG(0, ("Got invalid trustdom response\n"));
248 break;
251 *alt_name = '\0';
252 alt_name += 1;
254 sidstr = strchr(alt_name, '\\');
255 if (sidstr == NULL) {
256 DEBUG(0, ("Got invalid trustdom response\n"));
257 break;
260 *sidstr = '\0';
261 sidstr += 1;
263 q = strchr(sidstr, '\n');
264 if (q != NULL)
265 *q = '\0';
267 if (!string_to_sid(&sid, sidstr)) {
268 DEBUG(0, ("Got invalid trustdom response\n"));
269 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 /* save online flag */
385 request_domain = find_our_domain();
386 request_domain->online = domain->online;
388 async_domain_request(mem_ctx, request_domain, request, response,
389 init_child_getdc_recv, state);
390 return WINBINDD_PENDING;
393 static void init_child_getdc_recv(void *private_data, BOOL success)
395 struct init_child_state *state =
396 talloc_get_type_abort(private_data, struct init_child_state);
397 const char *dcname = "";
399 DEBUG(10, ("Received getdcname response\n"));
401 if (success && (state->response->result == WINBINDD_OK)) {
402 dcname = state->response->data.dc_name;
405 state->request->cmd = WINBINDD_INIT_CONNECTION;
406 fstrcpy(state->request->domain_name, state->domain->name);
407 state->request->data.init_conn.is_primary = False;
408 fstrcpy(state->request->data.init_conn.dcname, dcname);
410 async_request(state->mem_ctx, &state->domain->child,
411 state->request, state->response,
412 init_child_recv, state);
415 static void init_child_recv(void *private_data, BOOL success)
417 struct init_child_state *state =
418 talloc_get_type_abort(private_data, struct init_child_state);
420 DEBUG(5, ("Received child initialization response for domain %s\n",
421 state->domain->name));
423 if ((!success) || (state->response->result != WINBINDD_OK)) {
424 DEBUG(3, ("Could not init child\n"));
425 state->continuation(state->private_data, False);
426 talloc_destroy(state->mem_ctx);
427 return;
430 fstrcpy(state->domain->name,
431 state->response->data.domain_info.name);
432 fstrcpy(state->domain->alt_name,
433 state->response->data.domain_info.alt_name);
434 string_to_sid(&state->domain->sid,
435 state->response->data.domain_info.sid);
436 state->domain->native_mode =
437 state->response->data.domain_info.native_mode;
438 state->domain->active_directory =
439 state->response->data.domain_info.active_directory;
440 state->domain->sequence_number =
441 state->response->data.domain_info.sequence_number;
443 state->domain->initialized = 1;
445 if (state->continuation != NULL)
446 state->continuation(state->private_data, True);
447 talloc_destroy(state->mem_ctx);
450 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
451 struct winbindd_cli_state *state)
453 struct in_addr ipaddr;
455 /* Ensure null termination */
456 state->request.domain_name
457 [sizeof(state->request.domain_name)-1]='\0';
458 state->request.data.init_conn.dcname
459 [sizeof(state->request.data.init_conn.dcname)-1]='\0';
461 if (strlen(state->request.data.init_conn.dcname) > 0) {
462 fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
465 if (strlen(domain->dcname) > 0) {
466 if (!resolve_name(domain->dcname, &ipaddr, 0x20)) {
467 DEBUG(2, ("Could not resolve DC name %s for domain %s\n",
468 domain->dcname, domain->name));
469 return WINBINDD_ERROR;
472 domain->dcaddr.sin_family = PF_INET;
473 putip((char *)&(domain->dcaddr.sin_addr), (char *)&ipaddr);
474 domain->dcaddr.sin_port = 0;
477 init_dc_connection(domain);
479 #if 1
480 if (!domain->initialized) {
481 /* If we return error here we can't do any cached authentication,
482 but we may be in disconnected mode and can't initialize correctly.
483 Do what the previous code did and just return without initialization,
484 once we go online we'll re-initialize.
486 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
487 "online = %d\n", domain->name, (int)domain->online ));
489 #else
490 if (!domain->initialized) {
491 DEBUG(1, ("Could not initialize domain %s\n",
492 state->request.domain_name));
493 return WINBINDD_ERROR;
495 #endif
497 fstrcpy(state->response.data.domain_info.name, domain->name);
498 fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
499 fstrcpy(state->response.data.domain_info.sid,
500 sid_string_static(&domain->sid));
502 state->response.data.domain_info.native_mode
503 = domain->native_mode;
504 state->response.data.domain_info.active_directory
505 = domain->active_directory;
506 state->response.data.domain_info.primary
507 = domain->primary;
508 state->response.data.domain_info.sequence_number =
509 domain->sequence_number;
511 return WINBINDD_OK;
514 /* Look up global info for the winbind daemon */
515 BOOL init_domain_list(void)
517 extern struct winbindd_methods cache_methods;
518 extern struct winbindd_methods passdb_methods;
519 struct winbindd_domain *domain;
520 int role = lp_server_role();
522 /* Free existing list */
523 free_domain_list();
525 /* Add ourselves as the first entry. */
527 if ( role == ROLE_DOMAIN_MEMBER ) {
528 DOM_SID our_sid;
530 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
531 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
532 return False;
535 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
536 &cache_methods, &our_sid);
537 domain->primary = True;
538 setup_domain_child(domain, &domain->child, NULL);
541 /* Local SAM */
543 domain = add_trusted_domain(get_global_sam_name(), NULL,
544 &passdb_methods, get_global_sam_sid());
545 if ( role != ROLE_DOMAIN_MEMBER ) {
546 domain->primary = True;
548 setup_domain_child(domain, &domain->child, NULL);
550 /* BUILTIN domain */
552 domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
553 &global_sid_Builtin);
554 setup_domain_child(domain, &domain->child, NULL);
556 return True;
559 /**
560 * Given a domain name, return the struct winbindd domain info for it
562 * @note Do *not* pass lp_workgroup() to this function. domain_list
563 * may modify it's value, and free that pointer. Instead, our local
564 * domain may be found by calling find_our_domain().
565 * directly.
568 * @return The domain structure for the named domain, if it is working.
571 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
573 struct winbindd_domain *domain;
575 /* Search through list */
577 for (domain = domain_list(); domain != NULL; domain = domain->next) {
578 if (strequal(domain_name, domain->name) ||
579 (domain->alt_name[0] &&
580 strequal(domain_name, domain->alt_name))) {
581 return domain;
585 /* Not found */
587 return NULL;
590 struct winbindd_domain *find_domain_from_name(const char *domain_name)
592 struct winbindd_domain *domain;
594 domain = find_domain_from_name_noinit(domain_name);
596 if (domain == NULL)
597 return NULL;
599 if (!domain->initialized)
600 init_dc_connection(domain);
602 return domain;
605 /* Given a domain sid, return the struct winbindd domain info for it */
607 struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
609 struct winbindd_domain *domain;
611 /* Search through list */
613 for (domain = domain_list(); domain != NULL; domain = domain->next) {
614 if (sid_compare_domain(sid, &domain->sid) == 0)
615 return domain;
618 /* Not found */
620 return NULL;
623 /* Given a domain sid, return the struct winbindd domain info for it */
625 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
627 struct winbindd_domain *domain;
629 domain = find_domain_from_sid_noinit(sid);
631 if (domain == NULL)
632 return NULL;
634 if (!domain->initialized)
635 init_dc_connection(domain);
637 return domain;
640 struct winbindd_domain *find_our_domain(void)
642 struct winbindd_domain *domain;
644 /* Search through list */
646 for (domain = domain_list(); domain != NULL; domain = domain->next) {
647 if (domain->primary)
648 return domain;
651 smb_panic("Could not find our domain\n");
652 return NULL;
655 struct winbindd_domain *find_builtin_domain(void)
657 DOM_SID sid;
658 struct winbindd_domain *domain;
660 string_to_sid(&sid, "S-1-5-32");
661 domain = find_domain_from_sid(&sid);
663 if (domain == NULL)
664 smb_panic("Could not find BUILTIN domain\n");
666 return domain;
669 /* Find the appropriate domain to lookup a name or SID */
671 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
673 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
674 * one to contact the external DC's. On member servers the internal
675 * domains are different: These are part of the local SAM. */
677 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n",
678 sid_string_static(sid)));
680 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
681 DEBUG(10, ("calling find_domain_from_sid\n"));
682 return find_domain_from_sid(sid);
685 /* On a member server a query for SID or name can always go to our
686 * primary DC. */
688 DEBUG(10, ("calling find_our_domain\n"));
689 return find_our_domain();
692 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
694 if (IS_DC || strequal(domain_name, "BUILTIN") ||
695 strequal(domain_name, get_global_sam_name()))
696 return find_domain_from_name_noinit(domain_name);
698 return find_our_domain();
701 /* Lookup a sid in a domain from a name */
703 BOOL winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
704 struct winbindd_domain *domain,
705 const char *domain_name,
706 const char *name, DOM_SID *sid,
707 enum lsa_SidType *type)
709 NTSTATUS result;
711 /* Lookup name */
712 result = domain->methods->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
714 /* Return rid and type if lookup successful */
715 if (!NT_STATUS_IS_OK(result)) {
716 *type = SID_NAME_UNKNOWN;
719 return NT_STATUS_IS_OK(result);
723 * @brief Lookup a name in a domain from a sid.
725 * @param sid Security ID you want to look up.
726 * @param name On success, set to the name corresponding to @p sid.
727 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
728 * @param type On success, contains the type of name: alias, group or
729 * user.
730 * @retval True if the name exists, in which case @p name and @p type
731 * are set, otherwise False.
733 BOOL winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
734 DOM_SID *sid,
735 fstring dom_name,
736 fstring name,
737 enum lsa_SidType *type)
739 char *names;
740 char *dom_names;
741 NTSTATUS result;
742 BOOL rv = False;
743 struct winbindd_domain *domain;
745 domain = find_lookup_domain_from_sid(sid);
747 if (!domain) {
748 DEBUG(1,("Can't find domain from sid\n"));
749 return False;
752 /* Lookup name */
754 result = domain->methods->sid_to_name(domain, mem_ctx, sid, &dom_names, &names, type);
756 /* Return name and type if successful */
758 if ((rv = NT_STATUS_IS_OK(result))) {
759 fstrcpy(dom_name, dom_names);
760 fstrcpy(name, names);
761 } else {
762 *type = SID_NAME_UNKNOWN;
763 fstrcpy(name, name_deadbeef);
766 return rv;
769 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
771 void free_getent_state(struct getent_state *state)
773 struct getent_state *temp;
775 /* Iterate over state list */
777 temp = state;
779 while(temp != NULL) {
780 struct getent_state *next;
782 /* Free sam entries then list entry */
784 SAFE_FREE(state->sam_entries);
785 DLIST_REMOVE(state, state);
786 next = temp->next;
788 SAFE_FREE(temp);
789 temp = next;
793 /* Parse winbindd related parameters */
795 BOOL winbindd_param_init(void)
797 /* Parse winbind uid and winbind_gid parameters */
799 if (!lp_idmap_uid(&server_state.uid_low, &server_state.uid_high)) {
800 DEBUG(0, ("winbindd: idmap uid range missing or invalid\n"));
801 DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
802 return False;
805 if (!lp_idmap_gid(&server_state.gid_low, &server_state.gid_high)) {
806 DEBUG(0, ("winbindd: idmap gid range missing or invalid\n"));
807 DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
808 return False;
811 return True;
814 BOOL is_in_uid_range(uid_t uid)
816 return ((uid >= server_state.uid_low) &&
817 (uid <= server_state.uid_high));
820 BOOL is_in_gid_range(gid_t gid)
822 return ((gid >= server_state.gid_low) &&
823 (gid <= server_state.gid_high));
826 /* Is this a domain which we may assume no DOMAIN\ prefix? */
828 static BOOL assume_domain(const char *domain)
830 /* never assume the domain on a standalone server */
832 if ( lp_server_role() == ROLE_STANDALONE )
833 return False;
835 /* domain member servers may possibly assume for the domain name */
837 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
838 if ( !strequal(lp_workgroup(), domain) )
839 return False;
841 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
842 return True;
845 /* only left with a domain controller */
847 if ( strequal(get_global_sam_name(), domain) ) {
848 return True;
851 return False;
854 /* Parse a string of the form DOMAIN\user into a domain and a user */
856 BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
858 char *p = strchr(domuser,*lp_winbind_separator());
860 if ( !p ) {
861 fstrcpy(user, domuser);
863 if ( assume_domain(lp_workgroup())) {
864 fstrcpy(domain, lp_workgroup());
865 } else {
866 return False;
868 } else {
869 fstrcpy(user, p+1);
870 fstrcpy(domain, domuser);
871 domain[PTR_DIFF(p, domuser)] = 0;
874 strupper_m(domain);
876 return True;
879 BOOL parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
880 char **domain, char **user)
882 fstring fstr_domain, fstr_user;
883 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
884 return False;
886 *domain = talloc_strdup(mem_ctx, fstr_domain);
887 *user = talloc_strdup(mem_ctx, fstr_user);
888 return ((*domain != NULL) && (*user != NULL));
892 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
893 'winbind separator' options.
894 This means:
895 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
896 lp_workgroup()
898 If we are a PDC or BDC, and this is for our domain, do likewise.
900 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
901 username is then unqualified in unix
903 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
905 void fill_domain_username(fstring name, const char *domain, const char *user, BOOL can_assume)
907 fstring tmp_user;
909 fstrcpy(tmp_user, user);
910 strlower_m(tmp_user);
912 if (can_assume && assume_domain(domain)) {
913 strlcpy(name, tmp_user, sizeof(fstring));
914 } else {
915 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
916 domain, *lp_winbind_separator(),
917 tmp_user);
922 * Winbindd socket accessor functions
925 char *get_winbind_priv_pipe_dir(void)
927 return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
930 /* Open the winbindd socket */
932 static int _winbindd_socket = -1;
933 static int _winbindd_priv_socket = -1;
935 int open_winbindd_socket(void)
937 if (_winbindd_socket == -1) {
938 _winbindd_socket = create_pipe_sock(
939 WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME, 0755);
940 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
941 _winbindd_socket));
944 return _winbindd_socket;
947 int open_winbindd_priv_socket(void)
949 if (_winbindd_priv_socket == -1) {
950 _winbindd_priv_socket = create_pipe_sock(
951 get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
952 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
953 _winbindd_priv_socket));
956 return _winbindd_priv_socket;
959 /* Close the winbindd socket */
961 void close_winbindd_socket(void)
963 if (_winbindd_socket != -1) {
964 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
965 _winbindd_socket));
966 close(_winbindd_socket);
967 _winbindd_socket = -1;
969 if (_winbindd_priv_socket != -1) {
970 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
971 _winbindd_priv_socket));
972 close(_winbindd_priv_socket);
973 _winbindd_priv_socket = -1;
978 * Client list accessor functions
981 static struct winbindd_cli_state *_client_list;
982 static int _num_clients;
984 /* Return list of all connected clients */
986 struct winbindd_cli_state *winbindd_client_list(void)
988 return _client_list;
991 /* Add a connection to the list */
993 void winbindd_add_client(struct winbindd_cli_state *cli)
995 DLIST_ADD(_client_list, cli);
996 _num_clients++;
999 /* Remove a client from the list */
1001 void winbindd_remove_client(struct winbindd_cli_state *cli)
1003 DLIST_REMOVE(_client_list, cli);
1004 _num_clients--;
1007 /* Close all open clients */
1009 void winbindd_kill_all_clients(void)
1011 struct winbindd_cli_state *cl = winbindd_client_list();
1013 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1015 while (cl) {
1016 struct winbindd_cli_state *next;
1018 next = cl->next;
1019 winbindd_remove_client(cl);
1020 cl = next;
1024 /* Return number of open clients */
1026 int winbindd_num_clients(void)
1028 return _num_clients;
1031 /*****************************************************************************
1032 For idmap conversion: convert one record to new format
1033 Ancient versions (eg 2.2.3a) of winbindd_idmap.tdb mapped DOMAINNAME/rid
1034 instead of the SID.
1035 *****************************************************************************/
1036 static int convert_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA data, void *state)
1038 struct winbindd_domain *domain;
1039 char *p;
1040 DOM_SID sid;
1041 uint32 rid;
1042 fstring keystr;
1043 fstring dom_name;
1044 TDB_DATA key2;
1045 BOOL *failed = (BOOL *)state;
1047 DEBUG(10,("Converting %s\n", key.dptr));
1049 p = strchr(key.dptr, '/');
1050 if (!p)
1051 return 0;
1053 *p = 0;
1054 fstrcpy(dom_name, key.dptr);
1055 *p++ = '/';
1057 domain = find_domain_from_name(dom_name);
1058 if (domain == NULL) {
1059 /* We must delete the old record. */
1060 DEBUG(0,("Unable to find domain %s\n", dom_name ));
1061 DEBUG(0,("deleting record %s\n", key.dptr ));
1063 if (tdb_delete(tdb, key) != 0) {
1064 DEBUG(0, ("Unable to delete record %s\n", key.dptr));
1065 *failed = True;
1066 return -1;
1069 return 0;
1072 rid = atoi(p);
1074 sid_copy(&sid, &domain->sid);
1075 sid_append_rid(&sid, rid);
1077 sid_to_string(keystr, &sid);
1078 key2.dptr = keystr;
1079 key2.dsize = strlen(keystr) + 1;
1081 if (tdb_store(tdb, key2, data, TDB_INSERT) != 0) {
1082 DEBUG(0,("Unable to add record %s\n", key2.dptr ));
1083 *failed = True;
1084 return -1;
1087 if (tdb_store(tdb, data, key2, TDB_REPLACE) != 0) {
1088 DEBUG(0,("Unable to update record %s\n", data.dptr ));
1089 *failed = True;
1090 return -1;
1093 if (tdb_delete(tdb, key) != 0) {
1094 DEBUG(0,("Unable to delete record %s\n", key.dptr ));
1095 *failed = True;
1096 return -1;
1099 return 0;
1102 /* These definitions are from sam/idmap_tdb.c. Replicated here just
1103 out of laziness.... :-( */
1105 /* High water mark keys */
1106 #define HWM_GROUP "GROUP HWM"
1107 #define HWM_USER "USER HWM"
1109 /*****************************************************************************
1110 Convert the idmap database from an older version.
1111 *****************************************************************************/
1113 static BOOL idmap_convert(const char *idmap_name)
1115 int32 vers;
1116 BOOL bigendianheader;
1117 BOOL failed = False;
1118 TDB_CONTEXT *idmap_tdb;
1120 if (!(idmap_tdb = tdb_open_log(idmap_name, 0,
1121 TDB_DEFAULT, O_RDWR,
1122 0600))) {
1123 DEBUG(0, ("idmap_convert: Unable to open idmap database\n"));
1124 return False;
1127 bigendianheader = (tdb_get_flags(idmap_tdb) & TDB_BIGENDIAN) ? True : False;
1129 vers = tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION");
1131 if (((vers == -1) && bigendianheader) || (IREV(vers) == IDMAP_VERSION)) {
1132 /* Arrggghh ! Bytereversed or old big-endian - make order independent ! */
1134 * high and low records were created on a
1135 * big endian machine and will need byte-reversing.
1138 int32 wm;
1140 wm = tdb_fetch_int32(idmap_tdb, HWM_USER);
1142 if (wm != -1) {
1143 wm = IREV(wm);
1144 } else {
1145 wm = server_state.uid_low;
1148 if (tdb_store_int32(idmap_tdb, HWM_USER, wm) == -1) {
1149 DEBUG(0, ("idmap_convert: Unable to byteswap user hwm in idmap database\n"));
1150 tdb_close(idmap_tdb);
1151 return False;
1154 wm = tdb_fetch_int32(idmap_tdb, HWM_GROUP);
1155 if (wm != -1) {
1156 wm = IREV(wm);
1157 } else {
1158 wm = server_state.gid_low;
1161 if (tdb_store_int32(idmap_tdb, HWM_GROUP, wm) == -1) {
1162 DEBUG(0, ("idmap_convert: Unable to byteswap group hwm in idmap database\n"));
1163 tdb_close(idmap_tdb);
1164 return False;
1168 /* the old format stored as DOMAIN/rid - now we store the SID direct */
1169 tdb_traverse(idmap_tdb, convert_fn, &failed);
1171 if (failed) {
1172 DEBUG(0, ("Problem during conversion\n"));
1173 tdb_close(idmap_tdb);
1174 return False;
1177 if (tdb_store_int32(idmap_tdb, "IDMAP_VERSION", IDMAP_VERSION) == -1) {
1178 DEBUG(0, ("idmap_convert: Unable to dtore idmap version in databse\n"));
1179 tdb_close(idmap_tdb);
1180 return False;
1183 tdb_close(idmap_tdb);
1184 return True;
1187 /*****************************************************************************
1188 Convert the idmap database from an older version if necessary
1189 *****************************************************************************/
1191 BOOL winbindd_upgrade_idmap(void)
1193 pstring idmap_name;
1194 pstring backup_name;
1195 SMB_STRUCT_STAT stbuf;
1196 TDB_CONTEXT *idmap_tdb;
1198 pstrcpy(idmap_name, lock_path("winbindd_idmap.tdb"));
1200 if (!file_exist(idmap_name, &stbuf)) {
1201 /* nothing to convert return */
1202 return True;
1205 if (!(idmap_tdb = tdb_open_log(idmap_name, 0,
1206 TDB_DEFAULT, O_RDWR,
1207 0600))) {
1208 DEBUG(0, ("idmap_convert: Unable to open idmap database\n"));
1209 return False;
1212 if (tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION") == IDMAP_VERSION) {
1213 /* nothing to convert return */
1214 tdb_close(idmap_tdb);
1215 return True;
1218 /* backup_tdb expects the tdb not to be open */
1219 tdb_close(idmap_tdb);
1221 DEBUG(0, ("Upgrading winbindd_idmap.tdb from an old version\n"));
1223 pstrcpy(backup_name, idmap_name);
1224 pstrcat(backup_name, ".bak");
1226 if (backup_tdb(idmap_name, backup_name) != 0) {
1227 DEBUG(0, ("Could not backup idmap database\n"));
1228 return False;
1231 return idmap_convert(idmap_name);
1234 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1235 TALLOC_CTX *mem_ctx,
1236 const DOM_SID *user_sid,
1237 uint32 *p_num_groups, DOM_SID **user_sids)
1239 NET_USER_INFO_3 *info3 = NULL;
1240 NTSTATUS status = NT_STATUS_NO_MEMORY;
1241 int i;
1242 size_t num_groups = 0;
1243 DOM_SID group_sid, primary_group;
1245 DEBUG(3,(": lookup_usergroups_cached\n"));
1247 *user_sids = NULL;
1248 num_groups = 0;
1249 *p_num_groups = 0;
1251 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1253 if (info3 == NULL) {
1254 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1257 if (info3->num_groups == 0) {
1258 SAFE_FREE(info3);
1259 return NT_STATUS_UNSUCCESSFUL;
1262 /* always add the primary group to the sid array */
1263 sid_compose(&primary_group, &info3->dom_sid.sid, info3->user_rid);
1265 add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups);
1267 for (i=0; i<info3->num_groups; i++) {
1268 sid_copy(&group_sid, &info3->dom_sid.sid);
1269 sid_append_rid(&group_sid, info3->gids[i].g_rid);
1271 add_sid_to_array(mem_ctx, &group_sid, user_sids,
1272 &num_groups);
1275 SAFE_FREE(info3);
1276 *p_num_groups = num_groups;
1277 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1279 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1281 return status;