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 (!domain->internal) {
466 if (strlen(domain->dcname) > 0) {
467 if (!resolve_name(domain->dcname, &ipaddr, 0x20)) {
468 DEBUG(2, ("Could not resolve DC name %s for domain %s\n",
469 domain->dcname, domain->name));
470 return WINBINDD_ERROR;
473 domain->dcaddr.sin_family = PF_INET;
474 putip((char *)&(domain->dcaddr.sin_addr), (char *)&ipaddr);
475 domain->dcaddr.sin_port = 0;
479 init_dc_connection(domain);
482 if (!domain->initialized) {
483 /* If we return error here we can't do any cached authentication,
484 but we may be in disconnected mode and can't initialize correctly.
485 Do what the previous code did and just return without initialization,
486 once we go online we'll re-initialize.
488 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
489 "online = %d\n", domain->name, (int)domain->online ));
492 if (!domain->initialized) {
493 DEBUG(1, ("Could not initialize domain %s\n",
494 state->request.domain_name));
495 return WINBINDD_ERROR;
499 fstrcpy(state->response.data.domain_info.name, domain->name);
500 fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
501 fstrcpy(state->response.data.domain_info.sid,
502 sid_string_static(&domain->sid));
504 state->response.data.domain_info.native_mode
505 = domain->native_mode;
506 state->response.data.domain_info.active_directory
507 = domain->active_directory;
508 state->response.data.domain_info.primary
510 state->response.data.domain_info.sequence_number =
511 domain->sequence_number;
516 /* Look up global info for the winbind daemon */
517 BOOL init_domain_list(void)
519 extern struct winbindd_methods cache_methods;
520 extern struct winbindd_methods passdb_methods;
521 struct winbindd_domain *domain;
522 int role = lp_server_role();
524 /* Free existing list */
527 /* Add ourselves as the first entry. */
529 if ( role == ROLE_DOMAIN_MEMBER ) {
532 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
533 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
537 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
538 &cache_methods, &our_sid);
539 domain->primary = True;
540 setup_domain_child(domain, &domain->child, NULL);
545 domain = add_trusted_domain(get_global_sam_name(), NULL,
546 &passdb_methods, get_global_sam_sid());
547 if ( role != ROLE_DOMAIN_MEMBER ) {
548 domain->primary = True;
550 setup_domain_child(domain, &domain->child, NULL);
554 domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
555 &global_sid_Builtin);
556 setup_domain_child(domain, &domain->child, NULL);
562 * Given a domain name, return the struct winbindd domain info for it
564 * @note Do *not* pass lp_workgroup() to this function. domain_list
565 * may modify it's value, and free that pointer. Instead, our local
566 * domain may be found by calling find_our_domain().
570 * @return The domain structure for the named domain, if it is working.
573 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
575 struct winbindd_domain *domain;
577 /* Search through list */
579 for (domain = domain_list(); domain != NULL; domain = domain->next) {
580 if (strequal(domain_name, domain->name) ||
581 (domain->alt_name[0] &&
582 strequal(domain_name, domain->alt_name))) {
592 struct winbindd_domain *find_domain_from_name(const char *domain_name)
594 struct winbindd_domain *domain;
596 domain = find_domain_from_name_noinit(domain_name);
601 if (!domain->initialized)
602 init_dc_connection(domain);
607 /* Given a domain sid, return the struct winbindd domain info for it */
609 struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
611 struct winbindd_domain *domain;
613 /* Search through list */
615 for (domain = domain_list(); domain != NULL; domain = domain->next) {
616 if (sid_compare_domain(sid, &domain->sid) == 0)
625 /* Given a domain sid, return the struct winbindd domain info for it */
627 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
629 struct winbindd_domain *domain;
631 domain = find_domain_from_sid_noinit(sid);
636 if (!domain->initialized)
637 init_dc_connection(domain);
642 struct winbindd_domain *find_our_domain(void)
644 struct winbindd_domain *domain;
646 /* Search through list */
648 for (domain = domain_list(); domain != NULL; domain = domain->next) {
653 smb_panic("Could not find our domain\n");
657 struct winbindd_domain *find_builtin_domain(void)
660 struct winbindd_domain *domain;
662 string_to_sid(&sid, "S-1-5-32");
663 domain = find_domain_from_sid(&sid);
666 smb_panic("Could not find BUILTIN domain\n");
671 /* Find the appropriate domain to lookup a name or SID */
673 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
675 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
676 * one to contact the external DC's. On member servers the internal
677 * domains are different: These are part of the local SAM. */
679 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n",
680 sid_string_static(sid)));
682 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
683 DEBUG(10, ("calling find_domain_from_sid\n"));
684 return find_domain_from_sid(sid);
687 /* On a member server a query for SID or name can always go to our
690 DEBUG(10, ("calling find_our_domain\n"));
691 return find_our_domain();
694 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
696 if (IS_DC || strequal(domain_name, "BUILTIN") ||
697 strequal(domain_name, get_global_sam_name()))
698 return find_domain_from_name_noinit(domain_name);
700 return find_our_domain();
703 /* Lookup a sid in a domain from a name */
705 BOOL winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
706 struct winbindd_domain *domain,
707 const char *domain_name,
708 const char *name, DOM_SID *sid,
709 enum lsa_SidType *type)
714 result = domain->methods->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
716 /* Return rid and type if lookup successful */
717 if (!NT_STATUS_IS_OK(result)) {
718 *type = SID_NAME_UNKNOWN;
721 return NT_STATUS_IS_OK(result);
725 * @brief Lookup a name in a domain from a sid.
727 * @param sid Security ID you want to look up.
728 * @param name On success, set to the name corresponding to @p sid.
729 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
730 * @param type On success, contains the type of name: alias, group or
732 * @retval True if the name exists, in which case @p name and @p type
733 * are set, otherwise False.
735 BOOL winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
739 enum lsa_SidType *type)
745 struct winbindd_domain *domain;
747 domain = find_lookup_domain_from_sid(sid);
750 DEBUG(1,("Can't find domain from sid\n"));
756 result = domain->methods->sid_to_name(domain, mem_ctx, sid, &dom_names, &names, type);
758 /* Return name and type if successful */
760 if ((rv = NT_STATUS_IS_OK(result))) {
761 fstrcpy(dom_name, dom_names);
762 fstrcpy(name, names);
764 *type = SID_NAME_UNKNOWN;
765 fstrcpy(name, name_deadbeef);
771 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
773 void free_getent_state(struct getent_state *state)
775 struct getent_state *temp;
777 /* Iterate over state list */
781 while(temp != NULL) {
782 struct getent_state *next;
784 /* Free sam entries then list entry */
786 SAFE_FREE(state->sam_entries);
787 DLIST_REMOVE(state, state);
795 /* Parse winbindd related parameters */
797 BOOL winbindd_param_init(void)
799 /* Parse winbind uid and winbind_gid parameters */
801 if (!lp_idmap_uid(&server_state.uid_low, &server_state.uid_high)) {
802 DEBUG(0, ("winbindd: idmap uid range missing or invalid\n"));
803 DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
807 if (!lp_idmap_gid(&server_state.gid_low, &server_state.gid_high)) {
808 DEBUG(0, ("winbindd: idmap gid range missing or invalid\n"));
809 DEBUG(0, ("winbindd: cannot continue, exiting.\n"));
816 BOOL is_in_uid_range(uid_t uid)
818 return ((uid >= server_state.uid_low) &&
819 (uid <= server_state.uid_high));
822 BOOL is_in_gid_range(gid_t gid)
824 return ((gid >= server_state.gid_low) &&
825 (gid <= server_state.gid_high));
828 /* Is this a domain which we may assume no DOMAIN\ prefix? */
830 static BOOL assume_domain(const char *domain)
832 /* never assume the domain on a standalone server */
834 if ( lp_server_role() == ROLE_STANDALONE )
837 /* domain member servers may possibly assume for the domain name */
839 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
840 if ( !strequal(lp_workgroup(), domain) )
843 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
847 /* only left with a domain controller */
849 if ( strequal(get_global_sam_name(), domain) ) {
856 /* Parse a string of the form DOMAIN\user into a domain and a user */
858 BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
860 char *p = strchr(domuser,*lp_winbind_separator());
863 fstrcpy(user, domuser);
865 if ( assume_domain(lp_workgroup())) {
866 fstrcpy(domain, lp_workgroup());
872 fstrcpy(domain, domuser);
873 domain[PTR_DIFF(p, domuser)] = 0;
881 BOOL parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
882 char **domain, char **user)
884 fstring fstr_domain, fstr_user;
885 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
888 *domain = talloc_strdup(mem_ctx, fstr_domain);
889 *user = talloc_strdup(mem_ctx, fstr_user);
890 return ((*domain != NULL) && (*user != NULL));
893 /* Ensure an incoming username from NSS is fully qualified. Replace the
894 incoming fstring with DOMAIN <separator> user. Returns the same
895 values as parse_domain_user() but also replaces the incoming username.
896 Used to ensure all names are fully qualified within winbindd.
897 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
898 The protocol definitions of auth_crap, chng_pswd_auth_crap
899 really should be changed to use this instead of doing things
902 BOOL canonicalize_username(fstring username_inout, fstring domain, fstring user)
904 if (!parse_domain_user(username_inout, domain, user)) {
907 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
908 domain, *lp_winbind_separator(),
914 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
915 'winbind separator' options.
917 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
920 If we are a PDC or BDC, and this is for our domain, do likewise.
922 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
923 username is then unqualified in unix
925 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
927 void fill_domain_username(fstring name, const char *domain, const char *user, BOOL can_assume)
931 fstrcpy(tmp_user, user);
932 strlower_m(tmp_user);
934 if (can_assume && assume_domain(domain)) {
935 strlcpy(name, tmp_user, sizeof(fstring));
937 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
938 domain, *lp_winbind_separator(),
944 * Winbindd socket accessor functions
947 char *get_winbind_priv_pipe_dir(void)
949 return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
952 /* Open the winbindd socket */
954 static int _winbindd_socket = -1;
955 static int _winbindd_priv_socket = -1;
957 int open_winbindd_socket(void)
959 if (_winbindd_socket == -1) {
960 _winbindd_socket = create_pipe_sock(
961 WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME, 0755);
962 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
966 return _winbindd_socket;
969 int open_winbindd_priv_socket(void)
971 if (_winbindd_priv_socket == -1) {
972 _winbindd_priv_socket = create_pipe_sock(
973 get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
974 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
975 _winbindd_priv_socket));
978 return _winbindd_priv_socket;
981 /* Close the winbindd socket */
983 void close_winbindd_socket(void)
985 if (_winbindd_socket != -1) {
986 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
988 close(_winbindd_socket);
989 _winbindd_socket = -1;
991 if (_winbindd_priv_socket != -1) {
992 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
993 _winbindd_priv_socket));
994 close(_winbindd_priv_socket);
995 _winbindd_priv_socket = -1;
1000 * Client list accessor functions
1003 static struct winbindd_cli_state *_client_list;
1004 static int _num_clients;
1006 /* Return list of all connected clients */
1008 struct winbindd_cli_state *winbindd_client_list(void)
1010 return _client_list;
1013 /* Add a connection to the list */
1015 void winbindd_add_client(struct winbindd_cli_state *cli)
1017 DLIST_ADD(_client_list, cli);
1021 /* Remove a client from the list */
1023 void winbindd_remove_client(struct winbindd_cli_state *cli)
1025 DLIST_REMOVE(_client_list, cli);
1029 /* Close all open clients */
1031 void winbindd_kill_all_clients(void)
1033 struct winbindd_cli_state *cl = winbindd_client_list();
1035 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1038 struct winbindd_cli_state *next;
1041 winbindd_remove_client(cl);
1046 /* Return number of open clients */
1048 int winbindd_num_clients(void)
1050 return _num_clients;
1053 /*****************************************************************************
1054 For idmap conversion: convert one record to new format
1055 Ancient versions (eg 2.2.3a) of winbindd_idmap.tdb mapped DOMAINNAME/rid
1057 *****************************************************************************/
1058 static int convert_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA data, void *state)
1060 struct winbindd_domain *domain;
1067 BOOL *failed = (BOOL *)state;
1069 DEBUG(10,("Converting %s\n", key.dptr));
1071 p = strchr(key.dptr, '/');
1076 fstrcpy(dom_name, key.dptr);
1079 domain = find_domain_from_name(dom_name);
1080 if (domain == NULL) {
1081 /* We must delete the old record. */
1082 DEBUG(0,("Unable to find domain %s\n", dom_name ));
1083 DEBUG(0,("deleting record %s\n", key.dptr ));
1085 if (tdb_delete(tdb, key) != 0) {
1086 DEBUG(0, ("Unable to delete record %s\n", key.dptr));
1096 sid_copy(&sid, &domain->sid);
1097 sid_append_rid(&sid, rid);
1099 sid_to_string(keystr, &sid);
1101 key2.dsize = strlen(keystr) + 1;
1103 if (tdb_store(tdb, key2, data, TDB_INSERT) != 0) {
1104 DEBUG(0,("Unable to add record %s\n", key2.dptr ));
1109 if (tdb_store(tdb, data, key2, TDB_REPLACE) != 0) {
1110 DEBUG(0,("Unable to update record %s\n", data.dptr ));
1115 if (tdb_delete(tdb, key) != 0) {
1116 DEBUG(0,("Unable to delete record %s\n", key.dptr ));
1124 /* These definitions are from sam/idmap_tdb.c. Replicated here just
1125 out of laziness.... :-( */
1127 /* High water mark keys */
1128 #define HWM_GROUP "GROUP HWM"
1129 #define HWM_USER "USER HWM"
1131 /*****************************************************************************
1132 Convert the idmap database from an older version.
1133 *****************************************************************************/
1135 static BOOL idmap_convert(const char *idmap_name)
1138 BOOL bigendianheader;
1139 BOOL failed = False;
1140 TDB_CONTEXT *idmap_tdb;
1142 if (!(idmap_tdb = tdb_open_log(idmap_name, 0,
1143 TDB_DEFAULT, O_RDWR,
1145 DEBUG(0, ("idmap_convert: Unable to open idmap database\n"));
1149 bigendianheader = (tdb_get_flags(idmap_tdb) & TDB_BIGENDIAN) ? True : False;
1151 vers = tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION");
1153 if (((vers == -1) && bigendianheader) || (IREV(vers) == IDMAP_VERSION)) {
1154 /* Arrggghh ! Bytereversed or old big-endian - make order independent ! */
1156 * high and low records were created on a
1157 * big endian machine and will need byte-reversing.
1162 wm = tdb_fetch_int32(idmap_tdb, HWM_USER);
1167 wm = server_state.uid_low;
1170 if (tdb_store_int32(idmap_tdb, HWM_USER, wm) == -1) {
1171 DEBUG(0, ("idmap_convert: Unable to byteswap user hwm in idmap database\n"));
1172 tdb_close(idmap_tdb);
1176 wm = tdb_fetch_int32(idmap_tdb, HWM_GROUP);
1180 wm = server_state.gid_low;
1183 if (tdb_store_int32(idmap_tdb, HWM_GROUP, wm) == -1) {
1184 DEBUG(0, ("idmap_convert: Unable to byteswap group hwm in idmap database\n"));
1185 tdb_close(idmap_tdb);
1190 /* the old format stored as DOMAIN/rid - now we store the SID direct */
1191 tdb_traverse(idmap_tdb, convert_fn, &failed);
1194 DEBUG(0, ("Problem during conversion\n"));
1195 tdb_close(idmap_tdb);
1199 if (tdb_store_int32(idmap_tdb, "IDMAP_VERSION", IDMAP_VERSION) == -1) {
1200 DEBUG(0, ("idmap_convert: Unable to dtore idmap version in databse\n"));
1201 tdb_close(idmap_tdb);
1205 tdb_close(idmap_tdb);
1209 /*****************************************************************************
1210 Convert the idmap database from an older version if necessary
1211 *****************************************************************************/
1213 BOOL winbindd_upgrade_idmap(void)
1216 pstring backup_name;
1217 SMB_STRUCT_STAT stbuf;
1218 TDB_CONTEXT *idmap_tdb;
1220 pstrcpy(idmap_name, lock_path("winbindd_idmap.tdb"));
1222 if (!file_exist(idmap_name, &stbuf)) {
1223 /* nothing to convert return */
1227 if (!(idmap_tdb = tdb_open_log(idmap_name, 0,
1228 TDB_DEFAULT, O_RDWR,
1230 DEBUG(0, ("idmap_convert: Unable to open idmap database\n"));
1234 if (tdb_fetch_int32(idmap_tdb, "IDMAP_VERSION") == IDMAP_VERSION) {
1235 /* nothing to convert return */
1236 tdb_close(idmap_tdb);
1240 /* backup_tdb expects the tdb not to be open */
1241 tdb_close(idmap_tdb);
1243 DEBUG(0, ("Upgrading winbindd_idmap.tdb from an old version\n"));
1245 pstrcpy(backup_name, idmap_name);
1246 pstrcat(backup_name, ".bak");
1248 if (backup_tdb(idmap_name, backup_name) != 0) {
1249 DEBUG(0, ("Could not backup idmap database\n"));
1253 return idmap_convert(idmap_name);
1256 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1257 TALLOC_CTX *mem_ctx,
1258 const DOM_SID *user_sid,
1259 uint32 *p_num_groups, DOM_SID **user_sids)
1261 NET_USER_INFO_3 *info3 = NULL;
1262 NTSTATUS status = NT_STATUS_NO_MEMORY;
1264 size_t num_groups = 0;
1265 DOM_SID group_sid, primary_group;
1267 DEBUG(3,(": lookup_usergroups_cached\n"));
1273 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1275 if (info3 == NULL) {
1276 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1279 if (info3->num_groups == 0) {
1281 return NT_STATUS_UNSUCCESSFUL;
1284 /* always add the primary group to the sid array */
1285 sid_compose(&primary_group, &info3->dom_sid.sid, info3->user_rid);
1287 add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups);
1289 for (i=0; i<info3->num_groups; i++) {
1290 sid_copy(&group_sid, &info3->dom_sid.sid);
1291 sid_append_rid(&group_sid, info3->gids[i].g_rid);
1293 add_sid_to_array(mem_ctx, &group_sid, user_sids,
1298 *p_num_groups = num_groups;
1299 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1301 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));