[GLUE] Rsync SAMBA_3_0 SVN r25598 in order to create the v3-0-test branch.
[Samba.git] / source / nsswitch / winbindd_util.c
blobd2daf7830dba66ff7c4b98c719cfa12f38a2e9f6
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 extern struct winbindd_methods cache_methods;
31 extern struct winbindd_methods passdb_methods;
33 /**
34 * @file winbindd_util.c
36 * Winbind daemon for NT domain authentication nss module.
37 **/
40 /* The list of trusted domains. Note that the list can be deleted and
41 recreated using the init_domain_list() function so pointers to
42 individual winbindd_domain structures cannot be made. Keep a copy of
43 the domain name instead. */
45 static struct winbindd_domain *_domain_list;
47 /**
48 When was the last scan of trusted domains done?
50 0 == not ever
53 static time_t last_trustdom_scan;
55 struct winbindd_domain *domain_list(void)
57 /* Initialise list */
59 if ((!_domain_list) && (!init_domain_list())) {
60 smb_panic("Init_domain_list failed\n");
63 return _domain_list;
66 /* Free all entries in the trusted domain list */
68 void free_domain_list(void)
70 struct winbindd_domain *domain = _domain_list;
72 while(domain) {
73 struct winbindd_domain *next = domain->next;
75 DLIST_REMOVE(_domain_list, domain);
76 SAFE_FREE(domain);
77 domain = next;
81 static BOOL is_internal_domain(const DOM_SID *sid)
83 if (sid == NULL)
84 return False;
86 if ( IS_DC )
87 return sid_check_is_builtin(sid);
89 return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
92 static BOOL is_in_internal_domain(const DOM_SID *sid)
94 if (sid == NULL)
95 return False;
97 if ( IS_DC )
98 return sid_check_is_in_builtin(sid);
100 return (sid_check_is_in_our_domain(sid) || sid_check_is_in_builtin(sid));
104 /* Add a trusted domain to our list of domains */
105 static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
106 struct winbindd_methods *methods,
107 const DOM_SID *sid)
109 struct winbindd_domain *domain;
110 const char *alternative_name = NULL;
112 /* ignore alt_name if we are not in an AD domain */
114 if ( (lp_security() == SEC_ADS) && alt_name && *alt_name) {
115 alternative_name = alt_name;
118 /* We can't call domain_list() as this function is called from
119 init_domain_list() and we'll get stuck in a loop. */
120 for (domain = _domain_list; domain; domain = domain->next) {
121 if (strequal(domain_name, domain->name) ||
122 strequal(domain_name, domain->alt_name)) {
123 return domain;
125 if (alternative_name && *alternative_name) {
126 if (strequal(alternative_name, domain->name) ||
127 strequal(alternative_name, domain->alt_name)) {
128 return domain;
131 if (sid) {
132 if (is_null_sid(sid)) {
134 } else if (sid_equal(sid, &domain->sid)) {
135 return domain;
140 /* Create new domain entry */
142 if ((domain = SMB_MALLOC_P(struct winbindd_domain)) == NULL)
143 return NULL;
145 /* Fill in fields */
147 ZERO_STRUCTP(domain);
149 /* prioritise the short name */
150 if (strchr_m(domain_name, '.') && alternative_name && *alternative_name) {
151 fstrcpy(domain->name, alternative_name);
152 fstrcpy(domain->alt_name, domain_name);
153 } else {
154 fstrcpy(domain->name, domain_name);
155 if (alternative_name) {
156 fstrcpy(domain->alt_name, alternative_name);
160 domain->methods = methods;
161 domain->backend = NULL;
162 domain->internal = is_internal_domain(sid);
163 domain->sequence_number = DOM_SEQUENCE_NONE;
164 domain->last_seq_check = 0;
165 domain->initialized = False;
166 domain->online = is_internal_domain(sid);
167 domain->check_online_timeout = 0;
168 if (sid) {
169 sid_copy(&domain->sid, sid);
172 /* Link to domain list */
173 DLIST_ADD(_domain_list, domain);
175 DEBUG(2,("Added domain %s %s %s\n",
176 domain->name, domain->alt_name,
177 &domain->sid?sid_string_static(&domain->sid):""));
179 return domain;
182 /********************************************************************
183 rescan our domains looking for new trusted domains
184 ********************************************************************/
186 struct trustdom_state {
187 TALLOC_CTX *mem_ctx;
188 struct winbindd_response *response;
191 static void trustdom_recv(void *private_data, BOOL success);
193 static void add_trusted_domains( struct winbindd_domain *domain )
195 TALLOC_CTX *mem_ctx;
196 struct winbindd_request *request;
197 struct winbindd_response *response;
199 struct trustdom_state *state;
201 mem_ctx = talloc_init("add_trusted_domains");
202 if (mem_ctx == NULL) {
203 DEBUG(0, ("talloc_init failed\n"));
204 return;
207 request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
208 response = TALLOC_P(mem_ctx, struct winbindd_response);
209 state = TALLOC_P(mem_ctx, struct trustdom_state);
211 if ((request == NULL) || (response == NULL) || (state == NULL)) {
212 DEBUG(0, ("talloc failed\n"));
213 talloc_destroy(mem_ctx);
214 return;
217 state->mem_ctx = mem_ctx;
218 state->response = response;
220 request->length = sizeof(*request);
221 request->cmd = WINBINDD_LIST_TRUSTDOM;
223 async_domain_request(mem_ctx, domain, request, response,
224 trustdom_recv, state);
227 static void trustdom_recv(void *private_data, BOOL success)
229 struct trustdom_state *state =
230 talloc_get_type_abort(private_data, struct trustdom_state);
231 struct winbindd_response *response = state->response;
232 char *p;
234 if ((!success) || (response->result != WINBINDD_OK)) {
235 DEBUG(1, ("Could not receive trustdoms\n"));
236 talloc_destroy(state->mem_ctx);
237 return;
240 p = (char *)response->extra_data.data;
242 while ((p != NULL) && (*p != '\0')) {
243 char *q, *sidstr, *alt_name;
244 DOM_SID sid;
246 alt_name = strchr(p, '\\');
247 if (alt_name == NULL) {
248 DEBUG(0, ("Got invalid trustdom response\n"));
249 break;
252 *alt_name = '\0';
253 alt_name += 1;
255 sidstr = strchr(alt_name, '\\');
256 if (sidstr == NULL) {
257 DEBUG(0, ("Got invalid trustdom response\n"));
258 break;
261 *sidstr = '\0';
262 sidstr += 1;
264 q = strchr(sidstr, '\n');
265 if (q != NULL)
266 *q = '\0';
268 if (!string_to_sid(&sid, sidstr)) {
269 /* Allow NULL sid for sibling domains */
270 if ( strcmp(sidstr,"S-0-0") == 0) {
271 sid_copy( &sid, &global_sid_NULL);
272 } else {
273 DEBUG(0, ("Got invalid trustdom response\n"));
274 break;
278 if (find_domain_from_name_noinit(p) == NULL) {
279 struct winbindd_domain *domain;
280 char *alternate_name = NULL;
282 /* use the real alt_name if we have one, else pass in NULL */
284 if ( !strequal( alt_name, "(null)" ) )
285 alternate_name = alt_name;
287 domain = add_trusted_domain(p, alternate_name,
288 &cache_methods,
289 &sid);
290 setup_domain_child(domain, &domain->child, NULL);
292 p=q;
293 if (p != NULL)
294 p += 1;
297 SAFE_FREE(response->extra_data.data);
298 talloc_destroy(state->mem_ctx);
301 /********************************************************************
302 Periodically we need to refresh the trusted domain cache for smbd
303 ********************************************************************/
305 void rescan_trusted_domains( void )
307 time_t now = time(NULL);
309 /* see if the time has come... */
311 if ((now >= last_trustdom_scan) &&
312 ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
313 return;
315 /* this will only add new domains we didn't already know about */
317 add_trusted_domains( find_our_domain() );
319 last_trustdom_scan = now;
321 return;
324 struct init_child_state {
325 TALLOC_CTX *mem_ctx;
326 struct winbindd_domain *domain;
327 struct winbindd_request *request;
328 struct winbindd_response *response;
329 void (*continuation)(void *private_data, BOOL success);
330 void *private_data;
333 static void init_child_recv(void *private_data, BOOL success);
334 static void init_child_getdc_recv(void *private_data, BOOL success);
336 enum winbindd_result init_child_connection(struct winbindd_domain *domain,
337 void (*continuation)(void *private_data,
338 BOOL success),
339 void *private_data)
341 TALLOC_CTX *mem_ctx;
342 struct winbindd_request *request;
343 struct winbindd_response *response;
344 struct init_child_state *state;
345 struct winbindd_domain *request_domain;
347 mem_ctx = talloc_init("init_child_connection");
348 if (mem_ctx == NULL) {
349 DEBUG(0, ("talloc_init failed\n"));
350 return WINBINDD_ERROR;
353 request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
354 response = TALLOC_P(mem_ctx, struct winbindd_response);
355 state = TALLOC_P(mem_ctx, struct init_child_state);
357 if ((request == NULL) || (response == NULL) || (state == NULL)) {
358 DEBUG(0, ("talloc failed\n"));
359 TALLOC_FREE(mem_ctx);
360 continuation(private_data, False);
361 return WINBINDD_ERROR;
364 request->length = sizeof(*request);
366 state->mem_ctx = mem_ctx;
367 state->domain = domain;
368 state->request = request;
369 state->response = response;
370 state->continuation = continuation;
371 state->private_data = private_data;
373 if (IS_DC || domain->primary) {
374 /* The primary domain has to find the DC name itself */
375 request->cmd = WINBINDD_INIT_CONNECTION;
376 fstrcpy(request->domain_name, domain->name);
377 request->data.init_conn.is_primary = True;
378 fstrcpy(request->data.init_conn.dcname, "");
379 async_request(mem_ctx, &domain->child, request, response,
380 init_child_recv, state);
381 return WINBINDD_PENDING;
384 /* This is *not* the primary domain, let's ask our DC about a DC
385 * name */
387 request->cmd = WINBINDD_GETDCNAME;
388 fstrcpy(request->domain_name, domain->name);
390 request_domain = find_our_domain();
392 async_domain_request(mem_ctx, request_domain, request, response,
393 init_child_getdc_recv, state);
394 return WINBINDD_PENDING;
397 static void init_child_getdc_recv(void *private_data, BOOL success)
399 struct init_child_state *state =
400 talloc_get_type_abort(private_data, struct init_child_state);
401 const char *dcname = "";
403 DEBUG(10, ("Received getdcname response\n"));
405 if (success && (state->response->result == WINBINDD_OK)) {
406 dcname = state->response->data.dc_name;
409 state->request->cmd = WINBINDD_INIT_CONNECTION;
410 fstrcpy(state->request->domain_name, state->domain->name);
411 state->request->data.init_conn.is_primary = False;
412 fstrcpy(state->request->data.init_conn.dcname, dcname);
414 async_request(state->mem_ctx, &state->domain->child,
415 state->request, state->response,
416 init_child_recv, state);
419 static void init_child_recv(void *private_data, BOOL success)
421 struct init_child_state *state =
422 talloc_get_type_abort(private_data, struct init_child_state);
424 DEBUG(5, ("Received child initialization response for domain %s\n",
425 state->domain->name));
427 if ((!success) || (state->response->result != WINBINDD_OK)) {
428 DEBUG(3, ("Could not init child\n"));
429 state->continuation(state->private_data, False);
430 talloc_destroy(state->mem_ctx);
431 return;
434 fstrcpy(state->domain->name,
435 state->response->data.domain_info.name);
436 fstrcpy(state->domain->alt_name,
437 state->response->data.domain_info.alt_name);
438 string_to_sid(&state->domain->sid,
439 state->response->data.domain_info.sid);
440 state->domain->native_mode =
441 state->response->data.domain_info.native_mode;
442 state->domain->active_directory =
443 state->response->data.domain_info.active_directory;
444 state->domain->sequence_number =
445 state->response->data.domain_info.sequence_number;
447 init_dc_connection(state->domain);
449 if (state->continuation != NULL)
450 state->continuation(state->private_data, True);
451 talloc_destroy(state->mem_ctx);
454 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
455 struct winbindd_cli_state *state)
457 /* Ensure null termination */
458 state->request.domain_name
459 [sizeof(state->request.domain_name)-1]='\0';
460 state->request.data.init_conn.dcname
461 [sizeof(state->request.data.init_conn.dcname)-1]='\0';
463 if (strlen(state->request.data.init_conn.dcname) > 0) {
464 fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
467 init_dc_connection(domain);
469 if (!domain->initialized) {
470 /* If we return error here we can't do any cached authentication,
471 but we may be in disconnected mode and can't initialize correctly.
472 Do what the previous code did and just return without initialization,
473 once we go online we'll re-initialize.
475 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
476 "online = %d\n", domain->name, (int)domain->online ));
479 fstrcpy(state->response.data.domain_info.name, domain->name);
480 fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
481 fstrcpy(state->response.data.domain_info.sid,
482 sid_string_static(&domain->sid));
484 state->response.data.domain_info.native_mode
485 = domain->native_mode;
486 state->response.data.domain_info.active_directory
487 = domain->active_directory;
488 state->response.data.domain_info.primary
489 = domain->primary;
490 state->response.data.domain_info.sequence_number =
491 domain->sequence_number;
493 return WINBINDD_OK;
496 /* Look up global info for the winbind daemon */
497 BOOL init_domain_list(void)
499 struct winbindd_domain *domain;
500 int role = lp_server_role();
502 /* Free existing list */
503 free_domain_list();
505 /* Add ourselves as the first entry. */
507 if ( role == ROLE_DOMAIN_MEMBER ) {
508 DOM_SID our_sid;
510 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
511 DEBUG(0, ("Could not fetch our SID - did we join?\n"));
512 return False;
515 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
516 &cache_methods, &our_sid);
517 domain->primary = True;
518 setup_domain_child(domain, &domain->child, NULL);
520 /* Even in the parent winbindd we'll need to
521 talk to the DC, so try and see if we can
522 contact it. Theoretically this isn't neccessary
523 as the init_dc_connection() in init_child_recv()
524 will do this, but we can start detecting the DC
525 early here. */
526 set_domain_online_request(domain);
529 /* Local SAM */
531 domain = add_trusted_domain(get_global_sam_name(), NULL,
532 &passdb_methods, get_global_sam_sid());
533 if ( role != ROLE_DOMAIN_MEMBER ) {
534 domain->primary = True;
536 setup_domain_child(domain, &domain->child, NULL);
538 /* BUILTIN domain */
540 domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
541 &global_sid_Builtin);
542 setup_domain_child(domain, &domain->child, NULL);
544 return True;
547 /**
548 * Given a domain name, return the struct winbindd domain info for it
550 * @note Do *not* pass lp_workgroup() to this function. domain_list
551 * may modify it's value, and free that pointer. Instead, our local
552 * domain may be found by calling find_our_domain().
553 * directly.
556 * @return The domain structure for the named domain, if it is working.
559 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
561 struct winbindd_domain *domain;
563 /* Search through list */
565 for (domain = domain_list(); domain != NULL; domain = domain->next) {
566 if (strequal(domain_name, domain->name) ||
567 (domain->alt_name[0] &&
568 strequal(domain_name, domain->alt_name))) {
569 return domain;
573 /* Not found */
575 return NULL;
578 struct winbindd_domain *find_domain_from_name(const char *domain_name)
580 struct winbindd_domain *domain;
582 domain = find_domain_from_name_noinit(domain_name);
584 if (domain == NULL)
585 return NULL;
587 if (!domain->initialized)
588 init_dc_connection(domain);
590 return domain;
593 /* Given a domain sid, return the struct winbindd domain info for it */
595 struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
597 struct winbindd_domain *domain;
599 /* Search through list */
601 for (domain = domain_list(); domain != NULL; domain = domain->next) {
602 if (sid_compare_domain(sid, &domain->sid) == 0)
603 return domain;
606 /* Not found */
608 return NULL;
611 /* Given a domain sid, return the struct winbindd domain info for it */
613 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
615 struct winbindd_domain *domain;
617 domain = find_domain_from_sid_noinit(sid);
619 if (domain == NULL)
620 return NULL;
622 if (!domain->initialized)
623 init_dc_connection(domain);
625 return domain;
628 struct winbindd_domain *find_our_domain(void)
630 struct winbindd_domain *domain;
632 /* Search through list */
634 for (domain = domain_list(); domain != NULL; domain = domain->next) {
635 if (domain->primary)
636 return domain;
639 smb_panic("Could not find our domain\n");
640 return NULL;
643 struct winbindd_domain *find_root_domain(void)
645 struct winbindd_domain *ours = find_our_domain();
647 if ( !ours )
648 return NULL;
650 if ( strlen(ours->forest_name) == 0 )
651 return NULL;
653 return find_domain_from_name( ours->forest_name );
656 struct winbindd_domain *find_builtin_domain(void)
658 DOM_SID sid;
659 struct winbindd_domain *domain;
661 string_to_sid(&sid, "S-1-5-32");
662 domain = find_domain_from_sid(&sid);
664 if (domain == NULL)
665 smb_panic("Could not find BUILTIN domain\n");
667 return domain;
670 /* Find the appropriate domain to lookup a name or SID */
672 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
674 /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
675 * one to contact the external DC's. On member servers the internal
676 * domains are different: These are part of the local SAM. */
678 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n",
679 sid_string_static(sid)));
681 if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
682 DEBUG(10, ("calling find_domain_from_sid\n"));
683 return find_domain_from_sid(sid);
686 /* On a member server a query for SID or name can always go to our
687 * primary DC. */
689 DEBUG(10, ("calling find_our_domain\n"));
690 return find_our_domain();
693 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
695 if (IS_DC || strequal(domain_name, "BUILTIN") ||
696 strequal(domain_name, get_global_sam_name()))
697 return find_domain_from_name_noinit(domain_name);
699 return find_our_domain();
702 /* Lookup a sid in a domain from a name */
704 BOOL winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
705 struct winbindd_domain *domain,
706 const char *domain_name,
707 const char *name, DOM_SID *sid,
708 enum lsa_SidType *type)
710 NTSTATUS result;
712 /* Lookup name */
713 result = domain->methods->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
715 /* Return sid and type if lookup successful */
716 if (!NT_STATUS_IS_OK(result)) {
717 *type = SID_NAME_UNKNOWN;
720 return NT_STATUS_IS_OK(result);
724 * @brief Lookup a name in a domain from a sid.
726 * @param sid Security ID you want to look up.
727 * @param name On success, set to the name corresponding to @p sid.
728 * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
729 * @param type On success, contains the type of name: alias, group or
730 * user.
731 * @retval True if the name exists, in which case @p name and @p type
732 * are set, otherwise False.
734 BOOL winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
735 DOM_SID *sid,
736 char **dom_name,
737 char **name,
738 enum lsa_SidType *type)
740 NTSTATUS result;
741 struct winbindd_domain *domain;
743 *dom_name = NULL;
744 *name = NULL;
746 domain = find_lookup_domain_from_sid(sid);
748 if (!domain) {
749 DEBUG(1,("Can't find domain from sid\n"));
750 return False;
753 /* Lookup name */
755 result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
757 /* Return name and type if successful */
759 if (NT_STATUS_IS_OK(result)) {
760 return True;
763 *type = SID_NAME_UNKNOWN;
765 return False;
768 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
770 void free_getent_state(struct getent_state *state)
772 struct getent_state *temp;
774 /* Iterate over state list */
776 temp = state;
778 while(temp != NULL) {
779 struct getent_state *next;
781 /* Free sam entries then list entry */
783 SAFE_FREE(state->sam_entries);
784 DLIST_REMOVE(state, state);
785 next = temp->next;
787 SAFE_FREE(temp);
788 temp = next;
792 /* Is this a domain which we may assume no DOMAIN\ prefix? */
794 static BOOL assume_domain(const char *domain)
796 /* never assume the domain on a standalone server */
798 if ( lp_server_role() == ROLE_STANDALONE )
799 return False;
801 /* domain member servers may possibly assume for the domain name */
803 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
804 if ( !strequal(lp_workgroup(), domain) )
805 return False;
807 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
808 return True;
811 /* only left with a domain controller */
813 if ( strequal(get_global_sam_name(), domain) ) {
814 return True;
817 return False;
820 /* Parse a string of the form DOMAIN\user into a domain and a user */
822 BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
824 char *p = strchr(domuser,*lp_winbind_separator());
826 if ( !p ) {
827 fstrcpy(user, domuser);
829 if ( assume_domain(lp_workgroup())) {
830 fstrcpy(domain, lp_workgroup());
831 } else {
832 return False;
834 } else {
835 fstrcpy(user, p+1);
836 fstrcpy(domain, domuser);
837 domain[PTR_DIFF(p, domuser)] = 0;
840 strupper_m(domain);
842 return True;
845 BOOL parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
846 char **domain, char **user)
848 fstring fstr_domain, fstr_user;
849 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
850 return False;
852 *domain = talloc_strdup(mem_ctx, fstr_domain);
853 *user = talloc_strdup(mem_ctx, fstr_user);
854 return ((*domain != NULL) && (*user != NULL));
857 /* Ensure an incoming username from NSS is fully qualified. Replace the
858 incoming fstring with DOMAIN <separator> user. Returns the same
859 values as parse_domain_user() but also replaces the incoming username.
860 Used to ensure all names are fully qualified within winbindd.
861 Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
862 The protocol definitions of auth_crap, chng_pswd_auth_crap
863 really should be changed to use this instead of doing things
864 by hand. JRA. */
866 BOOL canonicalize_username(fstring username_inout, fstring domain, fstring user)
868 if (!parse_domain_user(username_inout, domain, user)) {
869 return False;
871 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
872 domain, *lp_winbind_separator(),
873 user);
874 return True;
878 Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
879 'winbind separator' options.
880 This means:
881 - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
882 lp_workgroup()
884 If we are a PDC or BDC, and this is for our domain, do likewise.
886 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
887 username is then unqualified in unix
889 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
891 void fill_domain_username(fstring name, const char *domain, const char *user, BOOL can_assume)
893 fstring tmp_user;
895 fstrcpy(tmp_user, user);
896 strlower_m(tmp_user);
898 if (can_assume && assume_domain(domain)) {
899 strlcpy(name, tmp_user, sizeof(fstring));
900 } else {
901 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
902 domain, *lp_winbind_separator(),
903 tmp_user);
908 * Winbindd socket accessor functions
911 char *get_winbind_priv_pipe_dir(void)
913 return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
916 /* Open the winbindd socket */
918 static int _winbindd_socket = -1;
919 static int _winbindd_priv_socket = -1;
921 int open_winbindd_socket(void)
923 if (_winbindd_socket == -1) {
924 _winbindd_socket = create_pipe_sock(
925 WINBINDD_SOCKET_DIR, WINBINDD_SOCKET_NAME, 0755);
926 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
927 _winbindd_socket));
930 return _winbindd_socket;
933 int open_winbindd_priv_socket(void)
935 if (_winbindd_priv_socket == -1) {
936 _winbindd_priv_socket = create_pipe_sock(
937 get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
938 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
939 _winbindd_priv_socket));
942 return _winbindd_priv_socket;
945 /* Close the winbindd socket */
947 void close_winbindd_socket(void)
949 if (_winbindd_socket != -1) {
950 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
951 _winbindd_socket));
952 close(_winbindd_socket);
953 _winbindd_socket = -1;
955 if (_winbindd_priv_socket != -1) {
956 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
957 _winbindd_priv_socket));
958 close(_winbindd_priv_socket);
959 _winbindd_priv_socket = -1;
964 * Client list accessor functions
967 static struct winbindd_cli_state *_client_list;
968 static int _num_clients;
970 /* Return list of all connected clients */
972 struct winbindd_cli_state *winbindd_client_list(void)
974 return _client_list;
977 /* Add a connection to the list */
979 void winbindd_add_client(struct winbindd_cli_state *cli)
981 DLIST_ADD(_client_list, cli);
982 _num_clients++;
985 /* Remove a client from the list */
987 void winbindd_remove_client(struct winbindd_cli_state *cli)
989 DLIST_REMOVE(_client_list, cli);
990 _num_clients--;
993 /* Close all open clients */
995 void winbindd_kill_all_clients(void)
997 struct winbindd_cli_state *cl = winbindd_client_list();
999 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1001 while (cl) {
1002 struct winbindd_cli_state *next;
1004 next = cl->next;
1005 winbindd_remove_client(cl);
1006 cl = next;
1010 /* Return number of open clients */
1012 int winbindd_num_clients(void)
1014 return _num_clients;
1017 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1018 TALLOC_CTX *mem_ctx,
1019 const DOM_SID *user_sid,
1020 uint32 *p_num_groups, DOM_SID **user_sids)
1022 NET_USER_INFO_3 *info3 = NULL;
1023 NTSTATUS status = NT_STATUS_NO_MEMORY;
1024 int i;
1025 size_t num_groups = 0;
1026 DOM_SID group_sid, primary_group;
1028 DEBUG(3,(": lookup_usergroups_cached\n"));
1030 *user_sids = NULL;
1031 num_groups = 0;
1032 *p_num_groups = 0;
1034 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1036 if (info3 == NULL) {
1037 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1040 if (info3->num_groups == 0) {
1041 TALLOC_FREE(info3);
1042 return NT_STATUS_UNSUCCESSFUL;
1045 /* always add the primary group to the sid array */
1046 sid_compose(&primary_group, &info3->dom_sid.sid, info3->user_rid);
1048 if (!add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups)) {
1049 TALLOC_FREE(info3);
1050 return NT_STATUS_NO_MEMORY;
1053 for (i=0; i<info3->num_groups; i++) {
1054 sid_copy(&group_sid, &info3->dom_sid.sid);
1055 sid_append_rid(&group_sid, info3->gids[i].g_rid);
1057 if (!add_sid_to_array(mem_ctx, &group_sid, user_sids,
1058 &num_groups)) {
1059 TALLOC_FREE(info3);
1060 return NT_STATUS_NO_MEMORY;
1064 TALLOC_FREE(info3);
1065 *p_num_groups = num_groups;
1066 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1068 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1070 return status;
1073 /*********************************************************************
1074 We use this to remove spaces from user and group names
1075 ********************************************************************/
1077 void ws_name_replace( char *name, char replace )
1079 char replace_char[2] = { 0x0, 0x0 };
1081 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1082 return;
1084 replace_char[0] = replace;
1085 all_string_sub( name, " ", replace_char, 0 );
1087 return;
1090 /*********************************************************************
1091 We use this to do the inverse of ws_name_replace()
1092 ********************************************************************/
1094 void ws_name_return( char *name, char replace )
1096 char replace_char[2] = { 0x0, 0x0 };
1098 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1099 return;
1101 replace_char[0] = replace;
1102 all_string_sub( name, replace_char, " ", 0 );
1104 return;