r19787: get winbindd compiling
[Samba.git] / source / nsswitch / winbindd_util.c
blobd94202666c346d3b3f9f783b497e9937e1942aec
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 /* Ensure null termination */
454 state->request.domain_name
455 [sizeof(state->request.domain_name)-1]='\0';
456 state->request.data.init_conn.dcname
457 [sizeof(state->request.data.init_conn.dcname)-1]='\0';
459 if (strlen(state->request.data.init_conn.dcname) > 0) {
460 fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
463 init_dc_connection(domain);
465 #if 1
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 ));
475 #else
476 if (!domain->initialized) {
477 DEBUG(1, ("Could not initialize domain %s\n",
478 state->request.domain_name));
479 return WINBINDD_ERROR;
481 #endif
483 fstrcpy(state->response.data.domain_info.name, domain->name);
484 fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
485 fstrcpy(state->response.data.domain_info.sid,
486 sid_string_static(&domain->sid));
488 state->response.data.domain_info.native_mode
489 = domain->native_mode;
490 state->response.data.domain_info.active_directory
491 = domain->active_directory;
492 state->response.data.domain_info.primary
493 = domain->primary;
494 state->response.data.domain_info.sequence_number =
495 domain->sequence_number;
497 return WINBINDD_OK;
500 /* Look up global info for the winbind daemon */
501 BOOL init_domain_list(void)
503 extern struct winbindd_methods cache_methods;
504 extern struct winbindd_methods passdb_methods;
505 struct winbindd_domain *domain;
506 int role = lp_server_role();
508 /* Free existing list */
509 free_domain_list();
511 /* Add ourselves as the first entry. */
513 if ( role == ROLE_DOMAIN_MEMBER ) {
514 DOM_SID our_sid;
516 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
517 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
518 return False;
521 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
522 &cache_methods, &our_sid);
523 domain->primary = True;
524 setup_domain_child(domain, &domain->child, NULL);
527 /* Local SAM */
529 domain = add_trusted_domain(get_global_sam_name(), NULL,
530 &passdb_methods, get_global_sam_sid());
531 if ( role != ROLE_DOMAIN_MEMBER ) {
532 domain->primary = True;
534 setup_domain_child(domain, &domain->child, NULL);
536 /* BUILTIN domain */
538 domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
539 &global_sid_Builtin);
540 setup_domain_child(domain, &domain->child, NULL);
542 return True;
545 /**
546 * Given a domain name, return the struct winbindd domain info for it
548 * @note Do *not* pass lp_workgroup() to this function. domain_list
549 * may modify it's value, and free that pointer. Instead, our local
550 * domain may be found by calling find_our_domain().
551 * directly.
554 * @return The domain structure for the named domain, if it is working.
557 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
559 struct winbindd_domain *domain;
561 /* Search through list */
563 for (domain = domain_list(); domain != NULL; domain = domain->next) {
564 if (strequal(domain_name, domain->name) ||
565 (domain->alt_name[0] &&
566 strequal(domain_name, domain->alt_name))) {
567 return domain;
571 /* Not found */
573 return NULL;
576 struct winbindd_domain *find_domain_from_name(const char *domain_name)
578 struct winbindd_domain *domain;
580 domain = find_domain_from_name_noinit(domain_name);
582 if (domain == NULL)
583 return NULL;
585 if (!domain->initialized)
586 init_dc_connection(domain);
588 return domain;
591 /* Given a domain sid, return the struct winbindd domain info for it */
593 struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
595 struct winbindd_domain *domain;
597 /* Search through list */
599 for (domain = domain_list(); domain != NULL; domain = domain->next) {
600 if (sid_compare_domain(sid, &domain->sid) == 0)
601 return domain;
604 /* Not found */
606 return NULL;
609 /* Given a domain sid, return the struct winbindd domain info for it */
611 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
613 struct winbindd_domain *domain;
615 domain = find_domain_from_sid_noinit(sid);
617 if (domain == NULL)
618 return NULL;
620 if (!domain->initialized)
621 init_dc_connection(domain);
623 return domain;
626 struct winbindd_domain *find_our_domain(void)
628 struct winbindd_domain *domain;
630 /* Search through list */
632 for (domain = domain_list(); domain != NULL; domain = domain->next) {
633 if (domain->primary)
634 return domain;
637 smb_panic("Could not find our domain\n");
638 return NULL;
641 struct winbindd_domain *find_builtin_domain(void)
643 DOM_SID sid;
644 struct winbindd_domain *domain;
646 string_to_sid(&sid, "S-1-5-32");
647 domain = find_domain_from_sid(&sid);
649 if (domain == NULL)
650 smb_panic("Could not find BUILTIN domain\n");
652 return domain;
655 /* Find the appropriate domain to lookup a name or SID */
657 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
659 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
660 * one to contact the external DC's. On member servers the internal
661 * domains are different: These are part of the local SAM. */
663 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n",
664 sid_string_static(sid)));
666 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
667 DEBUG(10, ("calling find_domain_from_sid\n"));
668 return find_domain_from_sid(sid);
671 /* On a member server a query for SID or name can always go to our
672 * primary DC. */
674 DEBUG(10, ("calling find_our_domain\n"));
675 return find_our_domain();
678 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
680 if (IS_DC || strequal(domain_name, "BUILTIN") ||
681 strequal(domain_name, get_global_sam_name()))
682 return find_domain_from_name_noinit(domain_name);
684 return find_our_domain();
687 /* Lookup a sid in a domain from a name */
689 BOOL winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
690 struct winbindd_domain *domain,
691 const char *domain_name,
692 const char *name, DOM_SID *sid,
693 enum SID_NAME_USE *type)
695 NTSTATUS result;
697 /* Lookup name */
698 result = domain->methods->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
700 /* Return rid and type if lookup successful */
701 if (!NT_STATUS_IS_OK(result)) {
702 *type = SID_NAME_UNKNOWN;
705 return NT_STATUS_IS_OK(result);
709 * @brief Lookup a name in a domain from a sid.
711 * @param sid Security ID you want to look up.
712 * @param name On success, set to the name corresponding to @p sid.
713 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
714 * @param type On success, contains the type of name: alias, group or
715 * user.
716 * @retval True if the name exists, in which case @p name and @p type
717 * are set, otherwise False.
719 BOOL winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
720 DOM_SID *sid,
721 fstring dom_name,
722 fstring name,
723 enum SID_NAME_USE *type)
725 char *names;
726 char *dom_names;
727 NTSTATUS result;
728 BOOL rv = False;
729 struct winbindd_domain *domain;
731 domain = find_lookup_domain_from_sid(sid);
733 if (!domain) {
734 DEBUG(1,("Can't find domain from sid\n"));
735 return False;
738 /* Lookup name */
740 result = domain->methods->sid_to_name(domain, mem_ctx, sid, &dom_names, &names, type);
742 /* Return name and type if successful */
744 if ((rv = NT_STATUS_IS_OK(result))) {
745 fstrcpy(dom_name, dom_names);
746 fstrcpy(name, names);
747 } else {
748 *type = SID_NAME_UNKNOWN;
749 fstrcpy(name, name_deadbeef);
752 return rv;
755 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
757 void free_getent_state(struct getent_state *state)
759 struct getent_state *temp;
761 /* Iterate over state list */
763 temp = state;
765 while(temp != NULL) {
766 struct getent_state *next;
768 /* Free sam entries then list entry */
770 SAFE_FREE(state->sam_entries);
771 DLIST_REMOVE(state, state);
772 next = temp->next;
774 SAFE_FREE(temp);
775 temp = next;
779 /* Parse winbindd related parameters */
781 BOOL winbindd_param_init(void)
783 /* Parse winbind uid and winbind_gid parameters */
785 if (!lp_idmap_uid(&server_state.uid_low, &server_state.uid_high)) {
786 DEBUG(0, ("winbindd: idmap uid range missing or invalid\n"));
787 DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
788 return False;
791 if (!lp_idmap_gid(&server_state.gid_low, &server_state.gid_high)) {
792 DEBUG(0, ("winbindd: idmap gid range missing or invalid\n"));
793 DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
794 return False;
797 return True;
800 BOOL is_in_uid_range(uid_t uid)
802 return ((uid >= server_state.uid_low) &&
803 (uid <= server_state.uid_high));
806 BOOL is_in_gid_range(gid_t gid)
808 return ((gid >= server_state.gid_low) &&
809 (gid <= server_state.gid_high));
812 /* Is this a domain which we may assume no DOMAIN\ prefix? */
814 static BOOL assume_domain(const char *domain)
816 /* never assume the domain on a standalone server */
818 if ( lp_server_role() == ROLE_STANDALONE )
819 return False;
821 /* domain member servers may possibly assume for the domain name */
823 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
824 if ( !strequal(lp_workgroup(), domain) )
825 return False;
827 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
828 return True;
831 /* only left with a domain controller */
833 if ( strequal(get_global_sam_name(), domain) ) {
834 return True;
837 return False;
840 /* Parse a string of the form DOMAIN\user into a domain and a user */
842 BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
844 char *p = strchr(domuser,*lp_winbind_separator());
846 if ( !p ) {
847 fstrcpy(user, domuser);
849 if ( assume_domain(lp_workgroup())) {
850 fstrcpy(domain, lp_workgroup());
851 } else {
852 return False;
854 } else {
855 fstrcpy(user, p+1);
856 fstrcpy(domain, domuser);
857 domain[PTR_DIFF(p, domuser)] = 0;
860 strupper_m(domain);
862 return True;
865 BOOL parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
866 char **domain, char **user)
868 fstring fstr_domain, fstr_user;
869 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
870 return False;
872 *domain = talloc_strdup(mem_ctx, fstr_domain);
873 *user = talloc_strdup(mem_ctx, fstr_user);
874 return ((*domain != NULL) && (*user != NULL));
877 /* Ensure an incoming username from NSS is fully qualified. Replace the
878 incoming fstring with DOMAIN <separator> user. Returns the same
879 values as parse_domain_user() but also replaces the incoming username.
880 Used to ensure all names are fully qualified within winbindd.
881 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
882 The protocol definitions of auth_crap, chng_pswd_auth_crap
883 really should be changed to use this instead of doing things
884 by hand. JRA. */
886 BOOL canonicalize_username(fstring username_inout, fstring domain, fstring user)
888 if (!parse_domain_user(username_inout, domain, user)) {
889 return False;
891 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
892 domain, *lp_winbind_separator(),
893 user);
894 return True;
898 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
899 'winbind separator' options.
900 This means:
901 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
902 lp_workgroup()
904 If we are a PDC or BDC, and this is for our domain, do likewise.
906 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
907 username is then unqualified in unix
909 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
911 void fill_domain_username(fstring name, const char *domain, const char *user, BOOL can_assume)
913 fstring tmp_user;
915 fstrcpy(tmp_user, user);
916 strlower_m(tmp_user);
918 if (can_assume && assume_domain(domain)) {
919 strlcpy(name, tmp_user, sizeof(fstring));
920 } else {
921 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
922 domain, *lp_winbind_separator(),
923 tmp_user);
928 * Winbindd socket accessor functions
931 char *get_winbind_priv_pipe_dir(void)
933 return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
936 /* Open the winbindd socket */
938 static int _winbindd_socket = -1;
939 static int _winbindd_priv_socket = -1;
941 int open_winbindd_socket(void)
943 if (_winbindd_socket == -1) {
944 _winbindd_socket = create_pipe_sock(
945 WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME, 0755);
946 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
947 _winbindd_socket));
950 return _winbindd_socket;
953 int open_winbindd_priv_socket(void)
955 if (_winbindd_priv_socket == -1) {
956 _winbindd_priv_socket = create_pipe_sock(
957 get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
958 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
959 _winbindd_priv_socket));
962 return _winbindd_priv_socket;
965 /* Close the winbindd socket */
967 void close_winbindd_socket(void)
969 if (_winbindd_socket != -1) {
970 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
971 _winbindd_socket));
972 close(_winbindd_socket);
973 _winbindd_socket = -1;
975 if (_winbindd_priv_socket != -1) {
976 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
977 _winbindd_priv_socket));
978 close(_winbindd_priv_socket);
979 _winbindd_priv_socket = -1;
984 * Client list accessor functions
987 static struct winbindd_cli_state *_client_list;
988 static int _num_clients;
990 /* Return list of all connected clients */
992 struct winbindd_cli_state *winbindd_client_list(void)
994 return _client_list;
997 /* Add a connection to the list */
999 void winbindd_add_client(struct winbindd_cli_state *cli)
1001 DLIST_ADD(_client_list, cli);
1002 _num_clients++;
1005 /* Remove a client from the list */
1007 void winbindd_remove_client(struct winbindd_cli_state *cli)
1009 DLIST_REMOVE(_client_list, cli);
1010 _num_clients--;
1013 /* Close all open clients */
1015 void winbindd_kill_all_clients(void)
1017 struct winbindd_cli_state *cl = winbindd_client_list();
1019 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1021 while (cl) {
1022 struct winbindd_cli_state *next;
1024 next = cl->next;
1025 winbindd_remove_client(cl);
1026 cl = next;
1030 /* Return number of open clients */
1032 int winbindd_num_clients(void)
1034 return _num_clients;
1037 /*****************************************************************************
1038 For idmap conversion: convert one record to new format
1039 Ancient versions (eg 2.2.3a) of winbindd_idmap.tdb mapped DOMAINNAME/rid
1040 instead of the SID.
1041 *****************************************************************************/
1042 static int convert_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA data, void *state)
1044 struct winbindd_domain *domain;
1045 char *p;
1046 DOM_SID sid;
1047 uint32 rid;
1048 fstring keystr;
1049 fstring dom_name;
1050 TDB_DATA key2;
1051 BOOL *failed = (BOOL *)state;
1053 DEBUG(10,("Converting %s\n", key.dptr));
1055 p = strchr(key.dptr, '/');
1056 if (!p)
1057 return 0;
1059 *p = 0;
1060 fstrcpy(dom_name, key.dptr);
1061 *p++ = '/';
1063 domain = find_domain_from_name(dom_name);
1064 if (domain == NULL) {
1065 /* We must delete the old record. */
1066 DEBUG(0,("Unable to find domain %s\n", dom_name ));
1067 DEBUG(0,("deleting record %s\n", key.dptr ));
1069 if (tdb_delete(tdb, key) != 0) {
1070 DEBUG(0, ("Unable to delete record %s\n", key.dptr));
1071 *failed = True;
1072 return -1;
1075 return 0;
1078 rid = atoi(p);
1080 sid_copy(&sid, &domain->sid);
1081 sid_append_rid(&sid, rid);
1083 sid_to_string(keystr, &sid);
1084 key2.dptr = keystr;
1085 key2.dsize = strlen(keystr) + 1;
1087 if (tdb_store(tdb, key2, data, TDB_INSERT) != 0) {
1088 DEBUG(0,("Unable to add record %s\n", key2.dptr ));
1089 *failed = True;
1090 return -1;
1093 if (tdb_store(tdb, data, key2, TDB_REPLACE) != 0) {
1094 DEBUG(0,("Unable to update record %s\n", data.dptr ));
1095 *failed = True;
1096 return -1;
1099 if (tdb_delete(tdb, key) != 0) {
1100 DEBUG(0,("Unable to delete record %s\n", key.dptr ));
1101 *failed = True;
1102 return -1;
1105 return 0;
1108 /* These definitions are from sam/idmap_tdb.c. Replicated here just
1109 out of laziness.... :-( */
1111 /* High water mark keys */
1112 #define HWM_GROUP "GROUP HWM"
1113 #define HWM_USER "USER HWM"
1115 /*****************************************************************************
1116 Convert the idmap database from an older version.
1117 *****************************************************************************/
1119 static BOOL idmap_convert(const char *idmap_name)
1121 int32 vers;
1122 BOOL bigendianheader;
1123 BOOL failed = False;
1124 TDB_CONTEXT *idmap_tdb;
1126 if (!(idmap_tdb = tdb_open_log(idmap_name, 0,
1127 TDB_DEFAULT, O_RDWR,
1128 0600))) {
1129 DEBUG(0, ("idmap_convert: Unable to open idmap database\n"));
1130 return False;
1133 bigendianheader = (tdb_get_flags(idmap_tdb) & TDB_BIGENDIAN) ? True : False;
1135 vers = tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION");
1137 if (((vers == -1) && bigendianheader) || (IREV(vers) == IDMAP_VERSION)) {
1138 /* Arrggghh ! Bytereversed or old big-endian - make order independent ! */
1140 * high and low records were created on a
1141 * big endian machine and will need byte-reversing.
1144 int32 wm;
1146 wm = tdb_fetch_int32(idmap_tdb, HWM_USER);
1148 if (wm != -1) {
1149 wm = IREV(wm);
1150 } else {
1151 wm = server_state.uid_low;
1154 if (tdb_store_int32(idmap_tdb, HWM_USER, wm) == -1) {
1155 DEBUG(0, ("idmap_convert: Unable to byteswap user hwm in idmap database\n"));
1156 tdb_close(idmap_tdb);
1157 return False;
1160 wm = tdb_fetch_int32(idmap_tdb, HWM_GROUP);
1161 if (wm != -1) {
1162 wm = IREV(wm);
1163 } else {
1164 wm = server_state.gid_low;
1167 if (tdb_store_int32(idmap_tdb, HWM_GROUP, wm) == -1) {
1168 DEBUG(0, ("idmap_convert: Unable to byteswap group hwm in idmap database\n"));
1169 tdb_close(idmap_tdb);
1170 return False;
1174 /* the old format stored as DOMAIN/rid - now we store the SID direct */
1175 tdb_traverse(idmap_tdb, convert_fn, &failed);
1177 if (failed) {
1178 DEBUG(0, ("Problem during conversion\n"));
1179 tdb_close(idmap_tdb);
1180 return False;
1183 if (tdb_store_int32(idmap_tdb, "IDMAP_VERSION", IDMAP_VERSION) == -1) {
1184 DEBUG(0, ("idmap_convert: Unable to dtore idmap version in databse\n"));
1185 tdb_close(idmap_tdb);
1186 return False;
1189 tdb_close(idmap_tdb);
1190 return True;
1193 /*****************************************************************************
1194 Convert the idmap database from an older version if necessary
1195 *****************************************************************************/
1197 BOOL winbindd_upgrade_idmap(void)
1199 pstring idmap_name;
1200 pstring backup_name;
1201 SMB_STRUCT_STAT stbuf;
1202 TDB_CONTEXT *idmap_tdb;
1204 pstrcpy(idmap_name, lock_path("winbindd_idmap.tdb"));
1206 if (!file_exist(idmap_name, &stbuf)) {
1207 /* nothing to convert return */
1208 return True;
1211 if (!(idmap_tdb = tdb_open_log(idmap_name, 0,
1212 TDB_DEFAULT, O_RDWR,
1213 0600))) {
1214 DEBUG(0, ("idmap_convert: Unable to open idmap database\n"));
1215 return False;
1218 if (tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION") == IDMAP_VERSION) {
1219 /* nothing to convert return */
1220 tdb_close(idmap_tdb);
1221 return True;
1224 /* backup_tdb expects the tdb not to be open */
1225 tdb_close(idmap_tdb);
1227 DEBUG(0, ("Upgrading winbindd_idmap.tdb from an old version\n"));
1229 pstrcpy(backup_name, idmap_name);
1230 pstrcat(backup_name, ".bak");
1232 if (backup_tdb(idmap_name, backup_name, 0) != 0) {
1233 DEBUG(0, ("Could not backup idmap database\n"));
1234 return False;
1237 return idmap_convert(idmap_name);
1240 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1241 TALLOC_CTX *mem_ctx,
1242 const DOM_SID *user_sid,
1243 uint32 *p_num_groups, DOM_SID **user_sids)
1245 NET_USER_INFO_3 *info3 = NULL;
1246 NTSTATUS status = NT_STATUS_NO_MEMORY;
1247 int i;
1248 size_t num_groups = 0;
1249 DOM_SID group_sid, primary_group;
1251 DEBUG(3,(": lookup_usergroups_cached\n"));
1253 *user_sids = NULL;
1254 num_groups = 0;
1255 *p_num_groups = 0;
1257 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1259 if (info3 == NULL) {
1260 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1263 if (info3->num_groups == 0) {
1264 SAFE_FREE(info3);
1265 return NT_STATUS_UNSUCCESSFUL;
1268 /* always add the primary group to the sid array */
1269 sid_compose(&primary_group, &info3->dom_sid.sid, info3->user_rid);
1271 add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups);
1273 for (i=0; i<info3->num_groups; i++) {
1274 sid_copy(&group_sid, &info3->dom_sid.sid);
1275 sid_append_rid(&group_sid, info3->gids[i].g_rid);
1277 add_sid_to_array(mem_ctx, &group_sid, user_sids,
1278 &num_groups);
1281 SAFE_FREE(info3);
1282 *p_num_groups = num_groups;
1283 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1285 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1287 return status;