source: trunk-3.0/source/nsswitch/winbindd_util.c@ 102

Last change on this file since 102 was 62, checked in by Paul Smedley, 18 years ago

Update source to 3.0.25c level

File size: 28.4 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 Winbind daemon for ntdom nss module
5
6 Copyright (C) Tim Potter 2000-2001
7 Copyright (C) 2001 by Martin Pool <mbp@samba.org>
8
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.
13
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.
18
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.
22*/
23
24#include "includes.h"
25#include "winbindd.h"
26
27#undef DBGC_CLASS
28#define DBGC_CLASS DBGC_WINBIND
29
30extern struct winbindd_methods cache_methods;
31extern struct winbindd_methods passdb_methods;
32
33/**
34 * @file winbindd_util.c
35 *
36 * Winbind daemon for NT domain authentication nss module.
37 **/
38
39
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. */
44
45static struct winbindd_domain *_domain_list;
46
47/**
48 When was the last scan of trusted domains done?
49
50 0 == not ever
51*/
52
53static time_t last_trustdom_scan;
54
55struct winbindd_domain *domain_list(void)
56{
57 /* Initialise list */
58
59 if ((!_domain_list) && (!init_domain_list())) {
60 smb_panic("Init_domain_list failed\n");
61 }
62
63 return _domain_list;
64}
65
66/* Free all entries in the trusted domain list */
67
68void free_domain_list(void)
69{
70 struct winbindd_domain *domain = _domain_list;
71
72 while(domain) {
73 struct winbindd_domain *next = domain->next;
74
75 DLIST_REMOVE(_domain_list, domain);
76 SAFE_FREE(domain);
77 domain = next;
78 }
79}
80
81static BOOL is_internal_domain(const DOM_SID *sid)
82{
83 if (sid == NULL)
84 return False;
85
86 if ( IS_DC )
87 return sid_check_is_builtin(sid);
88
89 return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
90}
91
92static BOOL is_in_internal_domain(const DOM_SID *sid)
93{
94 if (sid == NULL)
95 return False;
96
97 if ( IS_DC )
98 return sid_check_is_in_builtin(sid);
99
100 return (sid_check_is_in_our_domain(sid) || sid_check_is_in_builtin(sid));
101}
102
103
104/* Add a trusted domain to our list of domains */
105static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
106 struct winbindd_methods *methods,
107 const DOM_SID *sid)
108{
109 struct winbindd_domain *domain;
110 const char *alternative_name = NULL;
111
112 /* ignore alt_name if we are not in an AD domain */
113
114 if ( (lp_security() == SEC_ADS) && alt_name && *alt_name) {
115 alternative_name = alt_name;
116 }
117
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;
124 }
125 if (alternative_name && *alternative_name) {
126 if (strequal(alternative_name, domain->name) ||
127 strequal(alternative_name, domain->alt_name)) {
128 return domain;
129 }
130 }
131 if (sid) {
132 if (is_null_sid(sid)) {
133
134 } else if (sid_equal(sid, &domain->sid)) {
135 return domain;
136 }
137 }
138 }
139
140 /* Create new domain entry */
141
142 if ((domain = SMB_MALLOC_P(struct winbindd_domain)) == NULL)
143 return NULL;
144
145 /* Fill in fields */
146
147 ZERO_STRUCTP(domain);
148
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);
157 }
158 }
159
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);
170 }
171
172 /* Link to domain list */
173 DLIST_ADD(_domain_list, domain);
174
175 DEBUG(2,("Added domain %s %s %s\n",
176 domain->name, domain->alt_name,
177 &domain->sid?sid_string_static(&domain->sid):""));
178
179 return domain;
180}
181
182/********************************************************************
183 rescan our domains looking for new trusted domains
184********************************************************************/
185
186struct trustdom_state {
187 TALLOC_CTX *mem_ctx;
188 struct winbindd_response *response;
189};
190
191static void trustdom_recv(void *private_data, BOOL success);
192
193static void add_trusted_domains( struct winbindd_domain *domain )
194{
195 TALLOC_CTX *mem_ctx;
196 struct winbindd_request *request;
197 struct winbindd_response *response;
198
199 struct trustdom_state *state;
200
201 mem_ctx = talloc_init("add_trusted_domains");
202 if (mem_ctx == NULL) {
203 DEBUG(0, ("talloc_init failed\n"));
204 return;
205 }
206
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);
210
211 if ((request == NULL) || (response == NULL) || (state == NULL)) {
212 DEBUG(0, ("talloc failed\n"));
213 talloc_destroy(mem_ctx);
214 return;
215 }
216
217 state->mem_ctx = mem_ctx;
218 state->response = response;
219
220 request->length = sizeof(*request);
221 request->cmd = WINBINDD_LIST_TRUSTDOM;
222
223 async_domain_request(mem_ctx, domain, request, response,
224 trustdom_recv, state);
225}
226
227static void trustdom_recv(void *private_data, BOOL success)
228{
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;
233
234 if ((!success) || (response->result != WINBINDD_OK)) {
235 DEBUG(1, ("Could not receive trustdoms\n"));
236 talloc_destroy(state->mem_ctx);
237 return;
238 }
239
240 p = (char *)response->extra_data.data;
241
242 while ((p != NULL) && (*p != '\0')) {
243 char *q, *sidstr, *alt_name;
244 DOM_SID sid;
245
246 alt_name = strchr(p, '\\');
247 if (alt_name == NULL) {
248 DEBUG(0, ("Got invalid trustdom response\n"));
249 break;
250 }
251
252 *alt_name = '\0';
253 alt_name += 1;
254
255 sidstr = strchr(alt_name, '\\');
256 if (sidstr == NULL) {
257 DEBUG(0, ("Got invalid trustdom response\n"));
258 break;
259 }
260
261 *sidstr = '\0';
262 sidstr += 1;
263
264 q = strchr(sidstr, '\n');
265 if (q != NULL)
266 *q = '\0';
267
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;
275 }
276 }
277
278 if (find_domain_from_name_noinit(p) == NULL) {
279 struct winbindd_domain *domain;
280 char *alternate_name = NULL;
281
282 /* use the real alt_name if we have one, else pass in NULL */
283
284 if ( !strequal( alt_name, "(null)" ) )
285 alternate_name = alt_name;
286
287 domain = add_trusted_domain(p, alternate_name,
288 &cache_methods,
289 &sid);
290 setup_domain_child(domain, &domain->child, NULL);
291 }
292 p=q;
293 if (p != NULL)
294 p += 1;
295 }
296
297 SAFE_FREE(response->extra_data.data);
298 talloc_destroy(state->mem_ctx);
299}
300
301/********************************************************************
302 Periodically we need to refresh the trusted domain cache for smbd
303********************************************************************/
304
305void rescan_trusted_domains( void )
306{
307 time_t now = time(NULL);
308
309 /* see if the time has come... */
310
311 if ((now >= last_trustdom_scan) &&
312 ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
313 return;
314
315 /* this will only add new domains we didn't already know about */
316
317 add_trusted_domains( find_our_domain() );
318
319 last_trustdom_scan = now;
320
321 return;
322}
323
324struct 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;
331};
332
333static void init_child_recv(void *private_data, BOOL success);
334static void init_child_getdc_recv(void *private_data, BOOL success);
335
336enum winbindd_result init_child_connection(struct winbindd_domain *domain,
337 void (*continuation)(void *private_data,
338 BOOL success),
339 void *private_data)
340{
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;
346
347 mem_ctx = talloc_init("init_child_connection");
348 if (mem_ctx == NULL) {
349 DEBUG(0, ("talloc_init failed\n"));
350 return WINBINDD_ERROR;
351 }
352
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);
356
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;
362 }
363
364 request->length = sizeof(*request);
365
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;
372
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;
382 }
383
384 /* This is *not* the primary domain, let's ask our DC about a DC
385 * name */
386
387 request->cmd = WINBINDD_GETDCNAME;
388 fstrcpy(request->domain_name, domain->name);
389
390 request_domain = find_our_domain();
391
392 async_domain_request(mem_ctx, request_domain, request, response,
393 init_child_getdc_recv, state);
394 return WINBINDD_PENDING;
395}
396
397static void init_child_getdc_recv(void *private_data, BOOL success)
398{
399 struct init_child_state *state =
400 talloc_get_type_abort(private_data, struct init_child_state);
401 const char *dcname = "";
402
403 DEBUG(10, ("Received getdcname response\n"));
404
405 if (success && (state->response->result == WINBINDD_OK)) {
406 dcname = state->response->data.dc_name;
407 }
408
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);
413
414 async_request(state->mem_ctx, &state->domain->child,
415 state->request, state->response,
416 init_child_recv, state);
417}
418
419static void init_child_recv(void *private_data, BOOL success)
420{
421 struct init_child_state *state =
422 talloc_get_type_abort(private_data, struct init_child_state);
423
424 DEBUG(5, ("Received child initialization response for domain %s\n",
425 state->domain->name));
426
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;
432 }
433
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;
446
447 init_dc_connection(state->domain);
448
449 if (state->continuation != NULL)
450 state->continuation(state->private_data, True);
451 talloc_destroy(state->mem_ctx);
452}
453
454enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
455 struct winbindd_cli_state *state)
456{
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';
462
463 if (strlen(state->request.data.init_conn.dcname) > 0) {
464 fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
465 }
466
467 init_dc_connection(domain);
468
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.
474 */
475 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
476 "online = %d\n", domain->name, (int)domain->online ));
477 }
478
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));
483
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;
492
493 return WINBINDD_OK;
494}
495
496/* Look up global info for the winbind daemon */
497BOOL init_domain_list(void)
498{
499 struct winbindd_domain *domain;
500 int role = lp_server_role();
501
502 /* Free existing list */
503 free_domain_list();
504
505 /* Add ourselves as the first entry. */
506
507 if ( role == ROLE_DOMAIN_MEMBER ) {
508 DOM_SID our_sid;
509
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;
513 }
514
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);
519
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);
527 }
528
529 /* Local SAM */
530
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;
535 }
536 setup_domain_child(domain, &domain->child, NULL);
537
538 /* BUILTIN domain */
539
540 domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
541 &global_sid_Builtin);
542 setup_domain_child(domain, &domain->child, NULL);
543
544 return True;
545}
546
547/**
548 * Given a domain name, return the struct winbindd domain info for it
549 *
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.
554 *
555 *
556 * @return The domain structure for the named domain, if it is working.
557 */
558
559struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
560{
561 struct winbindd_domain *domain;
562
563 /* Search through list */
564
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;
570 }
571 }
572
573 /* Not found */
574
575 return NULL;
576}
577
578struct winbindd_domain *find_domain_from_name(const char *domain_name)
579{
580 struct winbindd_domain *domain;
581
582 domain = find_domain_from_name_noinit(domain_name);
583
584 if (domain == NULL)
585 return NULL;
586
587 if (!domain->initialized)
588 init_dc_connection(domain);
589
590 return domain;
591}
592
593/* Given a domain sid, return the struct winbindd domain info for it */
594
595struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
596{
597 struct winbindd_domain *domain;
598
599 /* Search through list */
600
601 for (domain = domain_list(); domain != NULL; domain = domain->next) {
602 if (sid_compare_domain(sid, &domain->sid) == 0)
603 return domain;
604 }
605
606 /* Not found */
607
608 return NULL;
609}
610
611/* Given a domain sid, return the struct winbindd domain info for it */
612
613struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
614{
615 struct winbindd_domain *domain;
616
617 domain = find_domain_from_sid_noinit(sid);
618
619 if (domain == NULL)
620 return NULL;
621
622 if (!domain->initialized)
623 init_dc_connection(domain);
624
625 return domain;
626}
627
628struct winbindd_domain *find_our_domain(void)
629{
630 struct winbindd_domain *domain;
631
632 /* Search through list */
633
634 for (domain = domain_list(); domain != NULL; domain = domain->next) {
635 if (domain->primary)
636 return domain;
637 }
638
639 smb_panic("Could not find our domain\n");
640 return NULL;
641}
642
643struct winbindd_domain *find_root_domain(void)
644{
645 struct winbindd_domain *ours = find_our_domain();
646
647 if ( !ours )
648 return NULL;
649
650 if ( strlen(ours->forest_name) == 0 )
651 return NULL;
652
653 return find_domain_from_name( ours->forest_name );
654}
655
656struct winbindd_domain *find_builtin_domain(void)
657{
658 DOM_SID sid;
659 struct winbindd_domain *domain;
660
661 string_to_sid(&sid, "S-1-5-32");
662 domain = find_domain_from_sid(&sid);
663
664 if (domain == NULL)
665 smb_panic("Could not find BUILTIN domain\n");
666
667 return domain;
668}
669
670/* Find the appropriate domain to lookup a name or SID */
671
672struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
673{
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. */
677
678 DEBUG(10, ("find_lookup_domain_from_sid(%s)\n",
679 sid_string_static(sid)));
680
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);
684 }
685
686 /* On a member server a query for SID or name can always go to our
687 * primary DC. */
688
689 DEBUG(10, ("calling find_our_domain\n"));
690 return find_our_domain();
691}
692
693struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
694{
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);
698
699 return find_our_domain();
700}
701
702/* Lookup a sid in a domain from a name */
703
704BOOL 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)
709{
710 NTSTATUS result;
711
712 /* Lookup name */
713 result = domain->methods->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
714
715 /* Return sid and type if lookup successful */
716 if (!NT_STATUS_IS_OK(result)) {
717 *type = SID_NAME_UNKNOWN;
718 }
719
720 return NT_STATUS_IS_OK(result);
721}
722
723/**
724 * @brief Lookup a name in a domain from a sid.
725 *
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.
733 **/
734BOOL 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)
739{
740 NTSTATUS result;
741 struct winbindd_domain *domain;
742
743 *dom_name = NULL;
744 *name = NULL;
745
746 domain = find_lookup_domain_from_sid(sid);
747
748 if (!domain) {
749 DEBUG(1,("Can't find domain from sid\n"));
750 return False;
751 }
752
753 /* Lookup name */
754
755 result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
756
757 /* Return name and type if successful */
758
759 if (NT_STATUS_IS_OK(result)) {
760 return True;
761 }
762
763 *type = SID_NAME_UNKNOWN;
764
765 return False;
766}
767
768/* Free state information held for {set,get,end}{pw,gr}ent() functions */
769
770void free_getent_state(struct getent_state *state)
771{
772 struct getent_state *temp;
773
774 /* Iterate over state list */
775
776 temp = state;
777
778 while(temp != NULL) {
779 struct getent_state *next;
780
781 /* Free sam entries then list entry */
782
783 SAFE_FREE(state->sam_entries);
784 DLIST_REMOVE(state, state);
785 next = temp->next;
786
787 SAFE_FREE(temp);
788 temp = next;
789 }
790}
791
792/* Is this a domain which we may assume no DOMAIN\ prefix? */
793
794static BOOL assume_domain(const char *domain)
795{
796 /* never assume the domain on a standalone server */
797
798 if ( lp_server_role() == ROLE_STANDALONE )
799 return False;
800
801 /* domain member servers may possibly assume for the domain name */
802
803 if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
804 if ( !strequal(lp_workgroup(), domain) )
805 return False;
806
807 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
808 return True;
809 }
810
811 /* only left with a domain controller */
812
813 if ( strequal(get_global_sam_name(), domain) ) {
814 return True;
815 }
816
817 return False;
818}
819
820/* Parse a string of the form DOMAIN\user into a domain and a user */
821
822BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
823{
824 char *p = strchr(domuser,*lp_winbind_separator());
825
826 if ( !p ) {
827 fstrcpy(user, domuser);
828
829 if ( assume_domain(lp_workgroup())) {
830 fstrcpy(domain, lp_workgroup());
831 } else {
832 return False;
833 }
834 } else {
835 fstrcpy(user, p+1);
836 fstrcpy(domain, domuser);
837 domain[PTR_DIFF(p, domuser)] = 0;
838 }
839
840 strupper_m(domain);
841
842 return True;
843}
844
845BOOL parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
846 char **domain, char **user)
847{
848 fstring fstr_domain, fstr_user;
849 if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
850 return False;
851 }
852 *domain = talloc_strdup(mem_ctx, fstr_domain);
853 *user = talloc_strdup(mem_ctx, fstr_user);
854 return ((*domain != NULL) && (*user != NULL));
855}
856
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. */
865
866BOOL canonicalize_username(fstring username_inout, fstring domain, fstring user)
867{
868 if (!parse_domain_user(username_inout, domain, user)) {
869 return False;
870 }
871 slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
872 domain, *lp_winbind_separator(),
873 user);
874 return True;
875}
876
877/*
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()
883
884 If we are a PDC or BDC, and this is for our domain, do likewise.
885
886 Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
887 username is then unqualified in unix
888
889 We always canonicalize as UPPERCASE DOMAIN, lowercase username.
890*/
891void fill_domain_username(fstring name, const char *domain, const char *user, BOOL can_assume)
892{
893 fstring tmp_user;
894
895 fstrcpy(tmp_user, user);
896 strlower_m(tmp_user);
897
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);
904 }
905}
906
907/*
908 * Winbindd socket accessor functions
909 */
910
911char *get_winbind_priv_pipe_dir(void)
912{
913 return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
914}
915
916/* Open the winbindd socket */
917
918static int _winbindd_socket = -1;
919static int _winbindd_priv_socket = -1;
920
921int open_winbindd_socket(void)
922{
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));
928 }
929
930 return _winbindd_socket;
931}
932
933int open_winbindd_priv_socket(void)
934{
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));
940 }
941
942 return _winbindd_priv_socket;
943}
944
945/* Close the winbindd socket */
946
947void close_winbindd_socket(void)
948{
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;
954 }
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;
960 }
961}
962
963/*
964 * Client list accessor functions
965 */
966
967static struct winbindd_cli_state *_client_list;
968static int _num_clients;
969
970/* Return list of all connected clients */
971
972struct winbindd_cli_state *winbindd_client_list(void)
973{
974 return _client_list;
975}
976
977/* Add a connection to the list */
978
979void winbindd_add_client(struct winbindd_cli_state *cli)
980{
981 DLIST_ADD(_client_list, cli);
982 _num_clients++;
983}
984
985/* Remove a client from the list */
986
987void winbindd_remove_client(struct winbindd_cli_state *cli)
988{
989 DLIST_REMOVE(_client_list, cli);
990 _num_clients--;
991}
992
993/* Close all open clients */
994
995void winbindd_kill_all_clients(void)
996{
997 struct winbindd_cli_state *cl = winbindd_client_list();
998
999 DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1000
1001 while (cl) {
1002 struct winbindd_cli_state *next;
1003
1004 next = cl->next;
1005 winbindd_remove_client(cl);
1006 cl = next;
1007 }
1008}
1009
1010/* Return number of open clients */
1011
1012int winbindd_num_clients(void)
1013{
1014 return _num_clients;
1015}
1016
1017NTSTATUS 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)
1021{
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;
1027
1028 DEBUG(3,(": lookup_usergroups_cached\n"));
1029
1030 *user_sids = NULL;
1031 num_groups = 0;
1032 *p_num_groups = 0;
1033
1034 info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1035
1036 if (info3 == NULL) {
1037 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1038 }
1039
1040 if (info3->num_groups == 0) {
1041 TALLOC_FREE(info3);
1042 return NT_STATUS_UNSUCCESSFUL;
1043 }
1044
1045 /* always add the primary group to the sid array */
1046 sid_compose(&primary_group, &info3->dom_sid.sid, info3->user_rid);
1047
1048 if (!add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups)) {
1049 TALLOC_FREE(info3);
1050 return NT_STATUS_NO_MEMORY;
1051 }
1052
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);
1056
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;
1061 }
1062 }
1063
1064 TALLOC_FREE(info3);
1065 *p_num_groups = num_groups;
1066 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1067
1068 DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1069
1070 return status;
1071}
1072
1073/*********************************************************************
1074 We use this to remove spaces from user and group names
1075********************************************************************/
1076
1077void ws_name_replace( char *name, char replace )
1078{
1079 char replace_char[2] = { 0x0, 0x0 };
1080
1081 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1082 return;
1083
1084 replace_char[0] = replace;
1085 all_string_sub( name, " ", replace_char, 0 );
1086
1087 return;
1088}
1089
1090/*********************************************************************
1091 We use this to do the inverse of ws_name_replace()
1092********************************************************************/
1093
1094void ws_name_return( char *name, char replace )
1095{
1096 char replace_char[2] = { 0x0, 0x0 };
1097
1098 if ( !lp_winbind_normalize_names() || (replace == '\0') )
1099 return;
1100
1101 replace_char[0] = replace;
1102 all_string_sub( name, replace_char, " ", 0 );
1103
1104 return;
1105}
Note: See TracBrowser for help on using the repository browser.