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
30 extern struct winbindd_methods cache_methods;
31 extern struct winbindd_methods passdb_methods;
34 * @file winbindd_util.c
36 * Winbind daemon for NT domain authentication nss module.
41 * Used to clobber name fields that have an undefined value.
43 * Correct code should never look at a field that has this value.
46 static const fstring name_deadbeef = "<deadbeef>";
48 /* The list of trusted domains. Note that the list can be deleted and
49 recreated using the init_domain_list() function so pointers to
50 individual winbindd_domain structures cannot be made. Keep a copy of
51 the domain name instead. */
53 static struct winbindd_domain *_domain_list;
56 When was the last scan of trusted domains done?
61 static time_t last_trustdom_scan;
63 struct winbindd_domain *domain_list(void)
67 if ((!_domain_list) && (!init_domain_list())) {
68 smb_panic("Init_domain_list failed\n");
74 /* Free all entries in the trusted domain list */
76 void free_domain_list(void)
78 struct winbindd_domain *domain = _domain_list;
81 struct winbindd_domain *next = domain->next;
83 DLIST_REMOVE(_domain_list, domain);
89 static BOOL is_internal_domain(const DOM_SID *sid)
94 return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
97 static BOOL is_in_internal_domain(const DOM_SID *sid)
102 return (sid_check_is_in_our_domain(sid) || sid_check_is_in_builtin(sid));
106 /* Add a trusted domain to our list of domains */
107 static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
108 struct winbindd_methods *methods,
111 struct winbindd_domain *domain;
112 const char *alternative_name = NULL;
114 /* ignore alt_name if we are not in an AD domain */
116 if ( (lp_security() == SEC_ADS) && alt_name && *alt_name) {
117 alternative_name = alt_name;
120 /* We can't call domain_list() as this function is called from
121 init_domain_list() and we'll get stuck in a loop. */
122 for (domain = _domain_list; domain; domain = domain->next) {
123 if (strequal(domain_name, domain->name) ||
124 strequal(domain_name, domain->alt_name)) {
127 if (alternative_name && *alternative_name) {
128 if (strequal(alternative_name, domain->name) ||
129 strequal(alternative_name, domain->alt_name)) {
134 if (is_null_sid(sid)) {
136 } else if (sid_equal(sid, &domain->sid)) {
142 /* Create new domain entry */
144 if ((domain = SMB_MALLOC_P(struct winbindd_domain)) == NULL)
149 ZERO_STRUCTP(domain);
151 /* prioritise the short name */
152 if (strchr_m(domain_name, '.') && alternative_name && *alternative_name) {
153 fstrcpy(domain->name, alternative_name);
154 fstrcpy(domain->alt_name, domain_name);
156 fstrcpy(domain->name, domain_name);
157 if (alternative_name) {
158 fstrcpy(domain->alt_name, alternative_name);
162 domain->methods = methods;
163 domain->backend = NULL;
164 domain->internal = is_internal_domain(sid);
165 domain->sequence_number = DOM_SEQUENCE_NONE;
166 domain->last_seq_check = 0;
167 domain->initialized = False;
168 domain->online = is_internal_domain(sid);
169 domain->check_online_timeout = 0;
171 sid_copy(&domain->sid, sid);
174 /* Link to domain list */
175 DLIST_ADD(_domain_list, domain);
177 DEBUG(2,("Added domain %s %s %s\n",
178 domain->name, domain->alt_name,
179 &domain->sid?sid_string_static(&domain->sid):""));
184 /********************************************************************
185 rescan our domains looking for new trusted domains
186 ********************************************************************/
188 struct trustdom_state {
190 struct winbindd_response *response;
193 static void trustdom_recv(void *private_data, BOOL success);
195 static void add_trusted_domains( struct winbindd_domain *domain )
198 struct winbindd_request *request;
199 struct winbindd_response *response;
201 struct trustdom_state *state;
203 mem_ctx = talloc_init("add_trusted_domains");
204 if (mem_ctx == NULL) {
205 DEBUG(0, ("talloc_init failed\n"));
209 request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
210 response = TALLOC_P(mem_ctx, struct winbindd_response);
211 state = TALLOC_P(mem_ctx, struct trustdom_state);
213 if ((request == NULL) || (response == NULL) || (state == NULL)) {
214 DEBUG(0, ("talloc failed\n"));
215 talloc_destroy(mem_ctx);
219 state->mem_ctx = mem_ctx;
220 state->response = response;
222 request->length = sizeof(*request);
223 request->cmd = WINBINDD_LIST_TRUSTDOM;
225 async_domain_request(mem_ctx, domain, request, response,
226 trustdom_recv, state);
229 static void trustdom_recv(void *private_data, BOOL success)
231 struct trustdom_state *state =
232 talloc_get_type_abort(private_data, struct trustdom_state);
233 struct winbindd_response *response = state->response;
236 if ((!success) || (response->result != WINBINDD_OK)) {
237 DEBUG(1, ("Could not receive trustdoms\n"));
238 talloc_destroy(state->mem_ctx);
242 p = (char *)response->extra_data.data;
244 while ((p != NULL) && (*p != '\0')) {
245 char *q, *sidstr, *alt_name;
248 alt_name = strchr(p, '\\');
249 if (alt_name == NULL) {
250 DEBUG(0, ("Got invalid trustdom response\n"));
257 sidstr = strchr(alt_name, '\\');
258 if (sidstr == NULL) {
259 DEBUG(0, ("Got invalid trustdom response\n"));
266 q = strchr(sidstr, '\n');
270 if (!string_to_sid(&sid, sidstr)) {
271 /* Allow NULL sid for sibling domains */
272 if ( strcmp(sidstr,"S-0-0") == 0) {
273 sid_copy( &sid, &global_sid_NULL);
275 DEBUG(0, ("Got invalid trustdom response\n"));
280 if (find_domain_from_name_noinit(p) == NULL) {
281 struct winbindd_domain *domain;
282 char *alternate_name = NULL;
284 /* use the real alt_name if we have one, else pass in NULL */
286 if ( !strequal( alt_name, "(null)" ) )
287 alternate_name = alt_name;
289 domain = add_trusted_domain(p, alternate_name,
292 setup_domain_child(domain, &domain->child, NULL);
299 SAFE_FREE(response->extra_data.data);
300 talloc_destroy(state->mem_ctx);
303 /********************************************************************
304 Periodically we need to refresh the trusted domain cache for smbd
305 ********************************************************************/
307 void rescan_trusted_domains( void )
309 time_t now = time(NULL);
311 /* see if the time has come... */
313 if ((now >= last_trustdom_scan) &&
314 ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
317 /* this will only add new domains we didn't already know about */
319 add_trusted_domains( find_our_domain() );
321 last_trustdom_scan = now;
326 struct init_child_state {
328 struct winbindd_domain *domain;
329 struct winbindd_request *request;
330 struct winbindd_response *response;
331 void (*continuation)(void *private_data, BOOL success);
335 static void init_child_recv(void *private_data, BOOL success);
336 static void init_child_getdc_recv(void *private_data, BOOL success);
338 enum winbindd_result init_child_connection(struct winbindd_domain *domain,
339 void (*continuation)(void *private_data,
344 struct winbindd_request *request;
345 struct winbindd_response *response;
346 struct init_child_state *state;
347 struct winbindd_domain *request_domain;
349 mem_ctx = talloc_init("init_child_connection");
350 if (mem_ctx == NULL) {
351 DEBUG(0, ("talloc_init failed\n"));
352 return WINBINDD_ERROR;
355 request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
356 response = TALLOC_P(mem_ctx, struct winbindd_response);
357 state = TALLOC_P(mem_ctx, struct init_child_state);
359 if ((request == NULL) || (response == NULL) || (state == NULL)) {
360 DEBUG(0, ("talloc failed\n"));
361 TALLOC_FREE(mem_ctx);
362 continuation(private_data, False);
363 return WINBINDD_ERROR;
366 request->length = sizeof(*request);
368 state->mem_ctx = mem_ctx;
369 state->domain = domain;
370 state->request = request;
371 state->response = response;
372 state->continuation = continuation;
373 state->private_data = private_data;
375 if (IS_DC || domain->primary) {
376 /* The primary domain has to find the DC name itself */
377 request->cmd = WINBINDD_INIT_CONNECTION;
378 fstrcpy(request->domain_name, domain->name);
379 request->data.init_conn.is_primary = True;
380 fstrcpy(request->data.init_conn.dcname, "");
381 async_request(mem_ctx, &domain->child, request, response,
382 init_child_recv, state);
383 return WINBINDD_PENDING;
386 /* This is *not* the primary domain, let's ask our DC about a DC
389 request->cmd = WINBINDD_GETDCNAME;
390 fstrcpy(request->domain_name, domain->name);
392 /* save online flag */
393 request_domain = find_our_domain();
394 request_domain->online = domain->online;
396 async_domain_request(mem_ctx, request_domain, request, response,
397 init_child_getdc_recv, state);
398 return WINBINDD_PENDING;
401 static void init_child_getdc_recv(void *private_data, BOOL success)
403 struct init_child_state *state =
404 talloc_get_type_abort(private_data, struct init_child_state);
405 const char *dcname = "";
407 DEBUG(10, ("Received getdcname response\n"));
409 if (success && (state->response->result == WINBINDD_OK)) {
410 dcname = state->response->data.dc_name;
413 state->request->cmd = WINBINDD_INIT_CONNECTION;
414 fstrcpy(state->request->domain_name, state->domain->name);
415 state->request->data.init_conn.is_primary = False;
416 fstrcpy(state->request->data.init_conn.dcname, dcname);
418 async_request(state->mem_ctx, &state->domain->child,
419 state->request, state->response,
420 init_child_recv, state);
423 static void init_child_recv(void *private_data, BOOL success)
425 struct init_child_state *state =
426 talloc_get_type_abort(private_data, struct init_child_state);
428 DEBUG(5, ("Received child initialization response for domain %s\n",
429 state->domain->name));
431 if ((!success) || (state->response->result != WINBINDD_OK)) {
432 DEBUG(3, ("Could not init child\n"));
433 state->continuation(state->private_data, False);
434 talloc_destroy(state->mem_ctx);
438 fstrcpy(state->domain->name,
439 state->response->data.domain_info.name);
440 fstrcpy(state->domain->alt_name,
441 state->response->data.domain_info.alt_name);
442 string_to_sid(&state->domain->sid,
443 state->response->data.domain_info.sid);
444 state->domain->native_mode =
445 state->response->data.domain_info.native_mode;
446 state->domain->active_directory =
447 state->response->data.domain_info.active_directory;
448 state->domain->sequence_number =
449 state->response->data.domain_info.sequence_number;
451 init_dc_connection(state->domain);
453 if (state->continuation != NULL)
454 state->continuation(state->private_data, True);
455 talloc_destroy(state->mem_ctx);
458 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
459 struct winbindd_cli_state *state)
461 /* Ensure null termination */
462 state->request.domain_name
463 [sizeof(state->request.domain_name)-1]='\0';
464 state->request.data.init_conn.dcname
465 [sizeof(state->request.data.init_conn.dcname)-1]='\0';
467 if (strlen(state->request.data.init_conn.dcname) > 0) {
468 fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
471 init_dc_connection(domain);
473 if (!domain->initialized) {
474 /* If we return error here we can't do any cached authentication,
475 but we may be in disconnected mode and can't initialize correctly.
476 Do what the previous code did and just return without initialization,
477 once we go online we'll re-initialize.
479 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
480 "online = %d\n", domain->name, (int)domain->online ));
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
494 state->response.data.domain_info.sequence_number =
495 domain->sequence_number;
500 /* Look up global info for the winbind daemon */
501 BOOL init_domain_list(void)
503 struct winbindd_domain *domain;
504 int role = lp_server_role();
506 /* Free existing list */
509 /* Add ourselves as the first entry. */
511 if ( role == ROLE_DOMAIN_MEMBER ) {
514 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
515 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
519 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
520 &cache_methods, &our_sid);
521 domain->primary = True;
522 setup_domain_child(domain, &domain->child, NULL);
524 /* Even in the parent winbindd we'll need to
525 talk to the DC, so try and see if we can
526 contact it. Theoretically this isn't neccessary
527 as the init_dc_connection() in init_child_recv()
528 will do this, but we can start detecting the DC
530 set_domain_online_request(domain);
535 domain = add_trusted_domain(get_global_sam_name(), NULL,
536 &passdb_methods, get_global_sam_sid());
537 if ( role != ROLE_DOMAIN_MEMBER ) {
538 domain->primary = True;
540 setup_domain_child(domain, &domain->child, NULL);
544 domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
545 &global_sid_Builtin);
546 setup_domain_child(domain, &domain->child, NULL);
552 * Given a domain name, return the struct winbindd domain info for it
554 * @note Do *not* pass lp_workgroup() to this function. domain_list
555 * may modify it's value, and free that pointer. Instead, our local
556 * domain may be found by calling find_our_domain().
560 * @return The domain structure for the named domain, if it is working.
563 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
565 struct winbindd_domain *domain;
567 /* Search through list */
569 for (domain = domain_list(); domain != NULL; domain = domain->next) {
570 if (strequal(domain_name, domain->name) ||
571 (domain->alt_name[0] &&
572 strequal(domain_name, domain->alt_name))) {
582 struct winbindd_domain *find_domain_from_name(const char *domain_name)
584 struct winbindd_domain *domain;
586 domain = find_domain_from_name_noinit(domain_name);
591 if (!domain->initialized)
592 init_dc_connection(domain);
597 /* Given a domain sid, return the struct winbindd domain info for it */
599 struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
601 struct winbindd_domain *domain;
603 /* Search through list */
605 for (domain = domain_list(); domain != NULL; domain = domain->next) {
606 if (sid_compare_domain(sid, &domain->sid) == 0)
615 /* Given a domain sid, return the struct winbindd domain info for it */
617 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
619 struct winbindd_domain *domain;
621 domain = find_domain_from_sid_noinit(sid);
626 if (!domain->initialized)
627 init_dc_connection(domain);
632 struct winbindd_domain *find_our_domain(void)
634 struct winbindd_domain *domain;
636 /* Search through list */
638 for (domain = domain_list(); domain != NULL; domain = domain->next) {
643 smb_panic("Could not find our domain\n");
647 struct winbindd_domain *find_root_domain(void)
649 struct winbindd_domain *ours = find_our_domain();
654 if ( strlen(ours->forest_name) == 0 )
657 return find_domain_from_name( ours->forest_name );
660 struct winbindd_domain *find_builtin_domain(void)
663 struct winbindd_domain *domain;
665 string_to_sid(&sid, "S-1-5-32");
666 domain = find_domain_from_sid(&sid);
669 smb_panic("Could not find BUILTIN domain\n");
674 /* Find the appropriate domain to lookup a name or SID */
676 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
678 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
679 * one to contact the external DC's. On member servers the internal
680 * domains are different: These are part of the local SAM. */
682 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n",
683 sid_string_static(sid)));
685 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
686 DEBUG(10, ("calling find_domain_from_sid\n"));
687 return find_domain_from_sid(sid);
690 /* On a member server a query for SID or name can always go to our
693 DEBUG(10, ("calling find_our_domain\n"));
694 return find_our_domain();
697 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
699 if (IS_DC || strequal(domain_name, "BUILTIN") ||
700 strequal(domain_name, get_global_sam_name()))
701 return find_domain_from_name_noinit(domain_name);
703 return find_our_domain();
706 /* Lookup a sid in a domain from a name */
708 BOOL winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
709 struct winbindd_domain *domain,
710 const char *domain_name,
711 const char *name, DOM_SID *sid,
712 enum lsa_SidType *type)
717 result = domain->methods->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
719 /* Return sid and type if lookup successful */
720 if (!NT_STATUS_IS_OK(result)) {
721 *type = SID_NAME_UNKNOWN;
724 return NT_STATUS_IS_OK(result);
728 * @brief Lookup a name in a domain from a sid.
730 * @param sid Security ID you want to look up.
731 * @param name On success, set to the name corresponding to @p sid.
732 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
733 * @param type On success, contains the type of name: alias, group or
735 * @retval True if the name exists, in which case @p name and @p type
736 * are set, otherwise False.
738 BOOL winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
742 enum lsa_SidType *type)
745 struct winbindd_domain *domain;
750 domain = find_lookup_domain_from_sid(sid);
753 DEBUG(1,("Can't find domain from sid\n"));
759 result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
761 /* Return name and type if successful */
763 if (NT_STATUS_IS_OK(result)) {
767 *type = SID_NAME_UNKNOWN;
772 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
774 void free_getent_state(struct getent_state *state)
776 struct getent_state *temp;
778 /* Iterate over state list */
782 while(temp != NULL) {
783 struct getent_state *next;
785 /* Free sam entries then list entry */
787 SAFE_FREE(state->sam_entries);
788 DLIST_REMOVE(state, state);
796 /* Is this a domain which we may assume no DOMAIN\ prefix? */
798 static BOOL assume_domain(const char *domain)
800 /* never assume the domain on a standalone server */
802 if ( lp_server_role() == ROLE_STANDALONE )
805 /* domain member servers may possibly assume for the domain name */
807 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
808 if ( !strequal(lp_workgroup(), domain) )
811 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
815 /* only left with a domain controller */
817 if ( strequal(get_global_sam_name(), domain) ) {
824 /* Parse a string of the form DOMAIN\user into a domain and a user */
826 BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
828 char *p = strchr(domuser,*lp_winbind_separator());
831 fstrcpy(user, domuser);
833 if ( assume_domain(lp_workgroup())) {
834 fstrcpy(domain, lp_workgroup());
840 fstrcpy(domain, domuser);
841 domain[PTR_DIFF(p, domuser)] = 0;
849 BOOL parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
850 char **domain, char **user)
852 fstring fstr_domain, fstr_user;
853 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
856 *domain = talloc_strdup(mem_ctx, fstr_domain);
857 *user = talloc_strdup(mem_ctx, fstr_user);
858 return ((*domain != NULL) && (*user != NULL));
861 /* Ensure an incoming username from NSS is fully qualified. Replace the
862 incoming fstring with DOMAIN <separator> user. Returns the same
863 values as parse_domain_user() but also replaces the incoming username.
864 Used to ensure all names are fully qualified within winbindd.
865 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
866 The protocol definitions of auth_crap, chng_pswd_auth_crap
867 really should be changed to use this instead of doing things
870 BOOL canonicalize_username(fstring username_inout, fstring domain, fstring user)
872 if (!parse_domain_user(username_inout, domain, user)) {
875 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
876 domain, *lp_winbind_separator(),
882 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
883 'winbind separator' options.
885 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
888 If we are a PDC or BDC, and this is for our domain, do likewise.
890 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
891 username is then unqualified in unix
893 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
895 void fill_domain_username(fstring name, const char *domain, const char *user, BOOL can_assume)
899 fstrcpy(tmp_user, user);
900 strlower_m(tmp_user);
902 if (can_assume && assume_domain(domain)) {
903 strlcpy(name, tmp_user, sizeof(fstring));
905 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
906 domain, *lp_winbind_separator(),
912 * Winbindd socket accessor functions
915 char *get_winbind_priv_pipe_dir(void)
917 return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
920 /* Open the winbindd socket */
922 static int _winbindd_socket = -1;
923 static int _winbindd_priv_socket = -1;
925 int open_winbindd_socket(void)
927 if (_winbindd_socket == -1) {
928 _winbindd_socket = create_pipe_sock(
929 WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME, 0755);
930 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
934 return _winbindd_socket;
937 int open_winbindd_priv_socket(void)
939 if (_winbindd_priv_socket == -1) {
940 _winbindd_priv_socket = create_pipe_sock(
941 get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
942 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
943 _winbindd_priv_socket));
946 return _winbindd_priv_socket;
949 /* Close the winbindd socket */
951 void close_winbindd_socket(void)
953 if (_winbindd_socket != -1) {
954 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
956 close(_winbindd_socket);
957 _winbindd_socket = -1;
959 if (_winbindd_priv_socket != -1) {
960 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
961 _winbindd_priv_socket));
962 close(_winbindd_priv_socket);
963 _winbindd_priv_socket = -1;
968 * Client list accessor functions
971 static struct winbindd_cli_state *_client_list;
972 static int _num_clients;
974 /* Return list of all connected clients */
976 struct winbindd_cli_state *winbindd_client_list(void)
981 /* Add a connection to the list */
983 void winbindd_add_client(struct winbindd_cli_state *cli)
985 DLIST_ADD(_client_list, cli);
989 /* Remove a client from the list */
991 void winbindd_remove_client(struct winbindd_cli_state *cli)
993 DLIST_REMOVE(_client_list, cli);
997 /* Close all open clients */
999 void winbindd_kill_all_clients(void)
1001 struct winbindd_cli_state *cl = winbindd_client_list();
1003 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1006 struct winbindd_cli_state *next;
1009 winbindd_remove_client(cl);
1014 /* Return number of open clients */
1016 int winbindd_num_clients(void)
1018 return _num_clients;
1021 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1022 TALLOC_CTX *mem_ctx,
1023 const DOM_SID *user_sid,
1024 uint32 *p_num_groups, DOM_SID **user_sids)
1026 NET_USER_INFO_3 *info3 = NULL;
1027 NTSTATUS status = NT_STATUS_NO_MEMORY;
1029 size_t num_groups = 0;
1030 DOM_SID group_sid, primary_group;
1032 DEBUG(3,(": lookup_usergroups_cached\n"));
1038 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1040 if (info3 == NULL) {
1041 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1044 if (info3->num_groups == 0) {
1046 return NT_STATUS_UNSUCCESSFUL;
1049 /* always add the primary group to the sid array */
1050 sid_compose(&primary_group, &info3->dom_sid.sid, info3->user_rid);
1052 if (!add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups)) {
1054 return NT_STATUS_NO_MEMORY;
1057 for (i=0; i<info3->num_groups; i++) {
1058 sid_copy(&group_sid, &info3->dom_sid.sid);
1059 sid_append_rid(&group_sid, info3->gids[i].g_rid);
1061 if (!add_sid_to_array(mem_ctx, &group_sid, user_sids,
1064 return NT_STATUS_NO_MEMORY;
1069 *p_num_groups = num_groups;
1070 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1072 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1077 /*********************************************************************
1078 We use this to remove spaces from user and group names
1079 ********************************************************************/
1081 void ws_name_replace( char *name, char replace )
1083 char replace_char[2] = { 0x0, 0x0 };
1085 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1088 replace_char[0] = replace;
1089 all_string_sub( name, " ", replace_char, 0 );
1094 /*********************************************************************
1095 We use this to do the inverse of ws_name_replace()
1096 ********************************************************************/
1098 void ws_name_return( char *name, char replace )
1100 char replace_char[2] = { 0x0, 0x0 };
1102 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1105 replace_char[0] = replace;
1106 all_string_sub( name, replace_char, " ", 0 );