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.
28 #define DBGC_CLASS DBGC_WINBIND
31 * @file winbindd_util.c
33 * Winbind daemon for NT domain authentication nss module.
38 * Used to clobber name fields that have an undefined value.
40 * Correct code should never look at a field that has this value.
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;
53 When was the last scan of trusted domains done?
58 static time_t last_trustdom_scan;
60 struct winbindd_domain *domain_list(void)
64 if ((!_domain_list) && (!init_domain_list())) {
65 smb_panic("Init_domain_list failed\n");
71 /* Free all entries in the trusted domain list */
73 void free_domain_list(void)
75 struct winbindd_domain *domain = _domain_list;
78 struct winbindd_domain *next = domain->next;
80 DLIST_REMOVE(_domain_list, domain);
86 static BOOL is_internal_domain(const DOM_SID *sid)
91 return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
94 static BOOL is_in_internal_domain(const DOM_SID *sid)
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,
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)) {
124 if (alternative_name && *alternative_name) {
125 if (strequal(alternative_name, domain->name) ||
126 strequal(alternative_name, domain->alt_name)) {
131 if (is_null_sid(sid)) {
133 } else if (sid_equal(sid, &domain->sid)) {
139 /* Create new domain entry */
141 if ((domain = SMB_MALLOC_P(struct winbindd_domain)) == NULL)
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);
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);
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):""));
180 /********************************************************************
181 rescan our domains looking for new trusted domains
182 ********************************************************************/
184 struct trustdom_state {
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 )
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"));
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);
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;
233 if ((!success) || (response->result != WINBINDD_OK)) {
234 DEBUG(1, ("Could not receive trustdoms\n"));
235 talloc_destroy(state->mem_ctx);
239 p = (char *)response->extra_data.data;
241 while ((p != NULL) && (*p != '\0')) {
242 char *q, *sidstr, *alt_name;
245 alt_name = strchr(p, '\\');
246 if (alt_name == NULL) {
247 DEBUG(0, ("Got invalid trustdom response\n"));
254 sidstr = strchr(alt_name, '\\');
255 if (sidstr == NULL) {
256 DEBUG(0, ("Got invalid trustdom response\n"));
263 q = strchr(sidstr, '\n');
267 if (!string_to_sid(&sid, sidstr)) {
268 DEBUG(0, ("Got invalid trustdom response\n"));
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,
284 setup_domain_child(domain, &domain->child, NULL);
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) )
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;
318 struct init_child_state {
320 struct winbindd_domain *domain;
321 struct winbindd_request *request;
322 struct winbindd_response *response;
323 void (*continuation)(void *private_data, BOOL success);
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,
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
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);
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);
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 ));
490 if (!domain->initialized) {
491 DEBUG(1, ("Could not initialize domain %s\n",
492 state->request.domain_name));
493 return WINBINDD_ERROR;
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
508 state->response.data.domain_info.sequence_number =
509 domain->sequence_number;
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 */
525 /* Add ourselves as the first entry. */
527 if ( role == ROLE_DOMAIN_MEMBER ) {
530 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
531 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
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);
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);
552 domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
553 &global_sid_Builtin);
554 setup_domain_child(domain, &domain->child, NULL);
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().
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))) {
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);
599 if (!domain->initialized)
600 init_dc_connection(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)
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);
634 if (!domain->initialized)
635 init_dc_connection(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) {
651 smb_panic("Could not find our domain\n");
655 struct winbindd_domain *find_builtin_domain(void)
658 struct winbindd_domain *domain;
660 string_to_sid(&sid, "S-1-5-32");
661 domain = find_domain_from_sid(&sid);
664 smb_panic("Could not find BUILTIN domain\n");
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
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)
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
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,
737 enum lsa_SidType *type)
743 struct winbindd_domain *domain;
745 domain = find_lookup_domain_from_sid(sid);
748 DEBUG(1,("Can't find domain from sid\n"));
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);
762 *type = SID_NAME_UNKNOWN;
763 fstrcpy(name, name_deadbeef);
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 */
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);
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"));
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"));
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 )
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) )
841 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
845 /* only left with a domain controller */
847 if ( strequal(get_global_sam_name(), domain) ) {
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());
861 fstrcpy(user, domuser);
863 if ( assume_domain(lp_workgroup())) {
864 fstrcpy(domain, lp_workgroup());
870 fstrcpy(domain, domuser);
871 domain[PTR_DIFF(p, domuser)] = 0;
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)) {
886 *domain = talloc_strdup(mem_ctx, fstr_domain);
887 *user = talloc_strdup(mem_ctx, fstr_user);
888 return ((*domain != NULL) && (*user != NULL));
891 /* Ensure an incoming username from NSS is fully qualified. Replace the
892 incoming fstring with DOMAIN <separator> user. Returns the same
893 values as parse_domain_user() but also replaces the incoming username.
894 Used to ensure all names are fully qualified within winbindd.
895 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
896 The protocol definitions of auth_crap, chng_pswd_auth_crap
897 really should be changed to use this instead of doing things
900 BOOL canonicalize_username(fstring username_inout, fstring domain, fstring user)
902 if (!parse_domain_user(username_inout, domain, user)) {
905 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
906 domain, *lp_winbind_separator(),
912 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
913 'winbind separator' options.
915 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
918 If we are a PDC or BDC, and this is for our domain, do likewise.
920 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
921 username is then unqualified in unix
923 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
925 void fill_domain_username(fstring name, const char *domain, const char *user, BOOL can_assume)
929 fstrcpy(tmp_user, user);
930 strlower_m(tmp_user);
932 if (can_assume && assume_domain(domain)) {
933 strlcpy(name, tmp_user, sizeof(fstring));
935 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
936 domain, *lp_winbind_separator(),
942 * Winbindd socket accessor functions
945 char *get_winbind_priv_pipe_dir(void)
947 return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
950 /* Open the winbindd socket */
952 static int _winbindd_socket = -1;
953 static int _winbindd_priv_socket = -1;
955 int open_winbindd_socket(void)
957 if (_winbindd_socket == -1) {
958 _winbindd_socket = create_pipe_sock(
959 WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME, 0755);
960 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
964 return _winbindd_socket;
967 int open_winbindd_priv_socket(void)
969 if (_winbindd_priv_socket == -1) {
970 _winbindd_priv_socket = create_pipe_sock(
971 get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
972 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
973 _winbindd_priv_socket));
976 return _winbindd_priv_socket;
979 /* Close the winbindd socket */
981 void close_winbindd_socket(void)
983 if (_winbindd_socket != -1) {
984 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
986 close(_winbindd_socket);
987 _winbindd_socket = -1;
989 if (_winbindd_priv_socket != -1) {
990 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
991 _winbindd_priv_socket));
992 close(_winbindd_priv_socket);
993 _winbindd_priv_socket = -1;
998 * Client list accessor functions
1001 static struct winbindd_cli_state *_client_list;
1002 static int _num_clients;
1004 /* Return list of all connected clients */
1006 struct winbindd_cli_state *winbindd_client_list(void)
1008 return _client_list;
1011 /* Add a connection to the list */
1013 void winbindd_add_client(struct winbindd_cli_state *cli)
1015 DLIST_ADD(_client_list, cli);
1019 /* Remove a client from the list */
1021 void winbindd_remove_client(struct winbindd_cli_state *cli)
1023 DLIST_REMOVE(_client_list, cli);
1027 /* Close all open clients */
1029 void winbindd_kill_all_clients(void)
1031 struct winbindd_cli_state *cl = winbindd_client_list();
1033 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1036 struct winbindd_cli_state *next;
1039 winbindd_remove_client(cl);
1044 /* Return number of open clients */
1046 int winbindd_num_clients(void)
1048 return _num_clients;
1051 /*****************************************************************************
1052 For idmap conversion: convert one record to new format
1053 Ancient versions (eg 2.2.3a) of winbindd_idmap.tdb mapped DOMAINNAME/rid
1055 *****************************************************************************/
1056 static int convert_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA data, void *state)
1058 struct winbindd_domain *domain;
1065 BOOL *failed = (BOOL *)state;
1067 DEBUG(10,("Converting %s\n", key.dptr));
1069 p = strchr(key.dptr, '/');
1074 fstrcpy(dom_name, key.dptr);
1077 domain = find_domain_from_name(dom_name);
1078 if (domain == NULL) {
1079 /* We must delete the old record. */
1080 DEBUG(0,("Unable to find domain %s\n", dom_name ));
1081 DEBUG(0,("deleting record %s\n", key.dptr ));
1083 if (tdb_delete(tdb, key) != 0) {
1084 DEBUG(0, ("Unable to delete record %s\n", key.dptr));
1094 sid_copy(&sid, &domain->sid);
1095 sid_append_rid(&sid, rid);
1097 sid_to_string(keystr, &sid);
1099 key2.dsize = strlen(keystr) + 1;
1101 if (tdb_store(tdb, key2, data, TDB_INSERT) != 0) {
1102 DEBUG(0,("Unable to add record %s\n", key2.dptr ));
1107 if (tdb_store(tdb, data, key2, TDB_REPLACE) != 0) {
1108 DEBUG(0,("Unable to update record %s\n", data.dptr ));
1113 if (tdb_delete(tdb, key) != 0) {
1114 DEBUG(0,("Unable to delete record %s\n", key.dptr ));
1122 /* These definitions are from sam/idmap_tdb.c. Replicated here just
1123 out of laziness.... :-( */
1125 /* High water mark keys */
1126 #define HWM_GROUP "GROUP HWM"
1127 #define HWM_USER "USER HWM"
1129 /*****************************************************************************
1130 Convert the idmap database from an older version.
1131 *****************************************************************************/
1133 static BOOL idmap_convert(const char *idmap_name)
1136 BOOL bigendianheader;
1137 BOOL failed = False;
1138 TDB_CONTEXT *idmap_tdb;
1140 if (!(idmap_tdb = tdb_open_log(idmap_name, 0,
1141 TDB_DEFAULT, O_RDWR,
1143 DEBUG(0, ("idmap_convert: Unable to open idmap database\n"));
1147 bigendianheader = (tdb_get_flags(idmap_tdb) & TDB_BIGENDIAN) ? True : False;
1149 vers = tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION");
1151 if (((vers == -1) && bigendianheader) || (IREV(vers) == IDMAP_VERSION)) {
1152 /* Arrggghh ! Bytereversed or old big-endian - make order independent ! */
1154 * high and low records were created on a
1155 * big endian machine and will need byte-reversing.
1160 wm = tdb_fetch_int32(idmap_tdb, HWM_USER);
1165 wm = server_state.uid_low;
1168 if (tdb_store_int32(idmap_tdb, HWM_USER, wm) == -1) {
1169 DEBUG(0, ("idmap_convert: Unable to byteswap user hwm in idmap database\n"));
1170 tdb_close(idmap_tdb);
1174 wm = tdb_fetch_int32(idmap_tdb, HWM_GROUP);
1178 wm = server_state.gid_low;
1181 if (tdb_store_int32(idmap_tdb, HWM_GROUP, wm) == -1) {
1182 DEBUG(0, ("idmap_convert: Unable to byteswap group hwm in idmap database\n"));
1183 tdb_close(idmap_tdb);
1188 /* the old format stored as DOMAIN/rid - now we store the SID direct */
1189 tdb_traverse(idmap_tdb, convert_fn, &failed);
1192 DEBUG(0, ("Problem during conversion\n"));
1193 tdb_close(idmap_tdb);
1197 if (tdb_store_int32(idmap_tdb, "IDMAP_VERSION", IDMAP_VERSION) == -1) {
1198 DEBUG(0, ("idmap_convert: Unable to dtore idmap version in databse\n"));
1199 tdb_close(idmap_tdb);
1203 tdb_close(idmap_tdb);
1207 /*****************************************************************************
1208 Convert the idmap database from an older version if necessary
1209 *****************************************************************************/
1211 BOOL winbindd_upgrade_idmap(void)
1214 pstring backup_name;
1215 SMB_STRUCT_STAT stbuf;
1216 TDB_CONTEXT *idmap_tdb;
1218 pstrcpy(idmap_name, lock_path("winbindd_idmap.tdb"));
1220 if (!file_exist(idmap_name, &stbuf)) {
1221 /* nothing to convert return */
1225 if (!(idmap_tdb = tdb_open_log(idmap_name, 0,
1226 TDB_DEFAULT, O_RDWR,
1228 DEBUG(0, ("idmap_convert: Unable to open idmap database\n"));
1232 if (tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION") == IDMAP_VERSION) {
1233 /* nothing to convert return */
1234 tdb_close(idmap_tdb);
1238 /* backup_tdb expects the tdb not to be open */
1239 tdb_close(idmap_tdb);
1241 DEBUG(0, ("Upgrading winbindd_idmap.tdb from an old version\n"));
1243 pstrcpy(backup_name, idmap_name);
1244 pstrcat(backup_name, ".bak");
1246 if (backup_tdb(idmap_name, backup_name) != 0) {
1247 DEBUG(0, ("Could not backup idmap database\n"));
1251 return idmap_convert(idmap_name);
1254 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1255 TALLOC_CTX *mem_ctx,
1256 const DOM_SID *user_sid,
1257 uint32 *p_num_groups, DOM_SID **user_sids)
1259 NET_USER_INFO_3 *info3 = NULL;
1260 NTSTATUS status = NT_STATUS_NO_MEMORY;
1262 size_t num_groups = 0;
1263 DOM_SID group_sid, primary_group;
1265 DEBUG(3,(": lookup_usergroups_cached\n"));
1271 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1273 if (info3 == NULL) {
1274 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1277 if (info3->num_groups == 0) {
1279 return NT_STATUS_UNSUCCESSFUL;
1282 /* always add the primary group to the sid array */
1283 sid_compose(&primary_group, &info3->dom_sid.sid, info3->user_rid);
1285 add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups);
1287 for (i=0; i<info3->num_groups; i++) {
1288 sid_copy(&group_sid, &info3->dom_sid.sid);
1289 sid_append_rid(&group_sid, info3->gids[i].g_rid);
1291 add_sid_to_array(mem_ctx, &group_sid, user_sids,
1296 *p_num_groups = num_groups;
1297 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1299 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));