r4746: add server support for lsa_enum_acct_rights(); last checkin for the night
[metze/samba/wip.git] / source3 / nsswitch / winbindd_cm.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Winbind daemon connection manager
5
6    Copyright (C) Tim Potter 2001
7    Copyright (C) Andrew Bartlett 2002
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 /*
25    We need to manage connections to domain controllers without having to
26    mess up the main winbindd code with other issues.  The aim of the
27    connection manager is to:
28   
29        - make connections to domain controllers and cache them
30        - re-establish connections when networks or servers go down
31        - centralise the policy on connection timeouts, domain controller
32          selection etc
33        - manage re-entrancy for when winbindd becomes able to handle
34          multiple outstanding rpc requests
35   
36    Why not have connection management as part of the rpc layer like tng?
37    Good question.  This code may morph into libsmb/rpc_cache.c or something
38    like that but at the moment it's simply staying as part of winbind.  I
39    think the TNG architecture of forcing every user of the rpc layer to use
40    the connection caching system is a bad idea.  It should be an optional
41    method of using the routines.
42
43    The TNG design is quite good but I disagree with some aspects of the
44    implementation. -tpot
45
46  */
47
48 /*
49    TODO:
50
51      - I'm pretty annoyed by all the make_nmb_name() stuff.  It should be
52        moved down into another function.
53
54      - Take care when destroying cli_structs as they can be shared between
55        various sam handles.
56
57  */
58
59 #include "includes.h"
60 #include "winbindd.h"
61
62 #undef DBGC_CLASS
63 #define DBGC_CLASS DBGC_WINBIND
64
65 /* Global list of connections.  Initially a DLIST but can become a hash
66    table or whatever later. */
67
68 struct winbindd_cm_conn {
69         struct winbindd_cm_conn *prev, *next;
70         fstring domain;
71         fstring controller;
72         fstring pipe_name;
73         struct cli_state *cli;
74         POLICY_HND pol;
75 };
76
77 static struct winbindd_cm_conn *cm_conns = NULL;
78
79 static NTSTATUS get_connection_from_cache(struct winbindd_domain *domain,
80                                           const char *pipe_name,
81                                           struct winbindd_cm_conn **conn_out);
82
83 /* Choose between anonymous or authenticated connections.  We need to use
84    an authenticated connection if DCs have the RestrictAnonymous registry
85    entry set > 0, or the "Additional restrictions for anonymous
86    connections" set in the win2k Local Security Policy. 
87    
88    Caller to free() result in domain, username, password
89 */
90
91 static void cm_get_ipc_userpass(char **username, char **domain, char **password)
92 {
93         *username = secrets_fetch(SECRETS_AUTH_USER, NULL);
94         *domain = secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
95         *password = secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
96         
97         if (*username && **username) {
98
99                 if (!*domain || !**domain)
100                         *domain = smb_xstrdup(lp_workgroup());
101                 
102                 if (!*password || !**password)
103                         *password = smb_xstrdup("");
104
105                 DEBUG(3, ("IPC$ connections done by user %s\\%s\n", 
106                           *domain, *username));
107
108         } else {
109                 DEBUG(3, ("IPC$ connections done anonymously\n"));
110                 *username = smb_xstrdup("");
111                 *domain = smb_xstrdup("");
112                 *password = smb_xstrdup("");
113         }
114 }
115
116 /*
117   setup for schannel on any pipes opened on this connection
118 */
119 static NTSTATUS setup_schannel( struct cli_state *cli, const char *domain )
120 {
121         NTSTATUS ret;
122         uchar trust_password[16];
123         uint32 sec_channel_type;
124         DOM_SID sid;
125         time_t lct;
126
127         /* use the domain trust password if we're on a DC 
128            and this is not our domain */
129         
130         if ( IS_DC && !strequal(domain, lp_workgroup()) ) {
131                 char *pass = NULL;
132                 
133                 if ( !secrets_fetch_trusted_domain_password( domain, 
134                         &pass, &sid, &lct) )
135                 {
136                         return NT_STATUS_UNSUCCESSFUL;
137                 }       
138
139                 sec_channel_type = SEC_CHAN_DOMAIN;
140                 E_md4hash(pass, trust_password);
141                 SAFE_FREE( pass );
142                 
143         } else {
144                 if (!secrets_fetch_trust_account_password(lp_workgroup(),
145                         trust_password, NULL, &sec_channel_type)) 
146                 {
147                         return NT_STATUS_UNSUCCESSFUL;
148                 }
149         }
150
151         ret = cli_nt_setup_netsec(cli, sec_channel_type, 
152                 AUTH_PIPE_NETSEC | AUTH_PIPE_SIGN, trust_password);
153
154         return ret;
155 }
156
157 static BOOL get_dc_name_via_netlogon(const struct winbindd_domain *domain,
158                                      fstring dcname, struct in_addr *dc_ip)
159 {
160         struct winbindd_domain *our_domain;
161         NTSTATUS result;
162         struct winbindd_cm_conn *conn;
163         TALLOC_CTX *mem_ctx;
164
165         fstring tmp;
166         char *p;
167
168         if (IS_DC)
169                 return False;
170
171         if (domain->primary)
172                 return False;
173
174         if ((our_domain = find_our_domain()) == NULL)
175                 return False;
176
177         result = get_connection_from_cache(our_domain, PIPE_NETLOGON, &conn);
178         if (!NT_STATUS_IS_OK(result))
179                 return False;
180
181         if ((mem_ctx = talloc_init("get_dc_name_via_netlogon")) == NULL)
182                 return False;
183
184         result = cli_netlogon_getdcname(conn->cli, mem_ctx, domain->name, tmp);
185
186         talloc_destroy(mem_ctx);
187
188         if (!NT_STATUS_IS_OK(result))
189                 return False;
190
191         /* cli_netlogon_getdcname gives us a name with \\ */
192         p = tmp;
193         if (*p == '\\') p+=1;
194         if (*p == '\\') p+=1;
195
196         fstrcpy(dcname, p);
197
198         if (!resolve_name(dcname, dc_ip, 0x20))
199                 return False;
200
201         return True;
202 }
203
204 /************************************************************************
205  Given a fd with a just-connected TCP connection to a DC, open a connection
206  to the pipe.
207 ************************************************************************/
208
209 static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
210                                       const int sockfd,
211                                       const int pipe_index,
212                                       const char *controller,
213                                       struct cli_state **cli,
214                                       BOOL *retry)
215 {
216         char *machine_password, *machine_krb5_principal;
217         char *ipc_username, *ipc_domain, *ipc_password;
218         struct ntuser_creds creds;
219
220         BOOL got_mutex;
221         BOOL add_failed_connection = True;
222
223         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
224
225         struct sockaddr peeraddr;
226         socklen_t peeraddr_len;
227
228         struct sockaddr_in *peeraddr_in = (struct sockaddr_in *)&peeraddr;
229
230         machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL,
231                                                           NULL);
232         
233         if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(),
234                      lp_realm()) == -1) {
235                 SAFE_FREE(machine_password);
236                 return NT_STATUS_NO_MEMORY;
237         }
238
239         cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
240
241         *retry = True;
242
243         got_mutex = secrets_named_mutex(controller,
244                                         WINBIND_SERVER_MUTEX_WAIT_TIME);
245
246         if (!got_mutex) {
247                 DEBUG(0,("cm_open_connection: mutex grab failed for %s\n",
248                          controller));
249                 result = NT_STATUS_POSSIBLE_DEADLOCK;
250                 goto done;
251         }
252
253         if ((*cli = cli_initialise(NULL)) == NULL) {
254                 DEBUG(1, ("Could not cli_initialize\n"));
255                 result = NT_STATUS_NO_MEMORY;
256                 goto done;
257         }
258
259         (*cli)->timeout = 10000;        /* 10 seconds */
260         (*cli)->fd = sockfd;
261         fstrcpy((*cli)->desthost, controller);
262         (*cli)->use_kerberos = True;
263
264         peeraddr_len = sizeof(peeraddr);
265
266         if ((getpeername((*cli)->fd, &peeraddr, &peeraddr_len) != 0) ||
267             (peeraddr_len != sizeof(struct sockaddr_in)) ||
268             (peeraddr_in->sin_family != PF_INET))
269         {
270                 DEBUG(0,("cm_prepare_connection: %s\n", strerror(errno)));
271                 goto done;
272         }
273
274         if (ntohs(peeraddr_in->sin_port) == 139) {
275                 struct nmb_name calling;
276                 struct nmb_name called;
277
278                 make_nmb_name(&calling, global_myname(), 0x0);
279                 make_nmb_name(&called, "*SMBSERVER", 0x20);
280
281                 if (!cli_session_request(*cli, &calling, &called)) {
282                         DEBUG(8, ("cli_session_request failed for %s\n",
283                                   controller));
284                         goto done;
285                 }
286         }
287
288         cli_setup_signing_state(*cli, Undefined);
289
290         if (!cli_negprot(*cli)) {
291                 DEBUG(1, ("cli_negprot failed\n"));
292                 cli_shutdown(*cli);
293                 goto done;
294         }
295
296         /* Krb5 session */
297                         
298         if ((lp_security() == SEC_ADS) 
299             && ((*cli)->protocol >= PROTOCOL_NT1 &&
300                 (*cli)->capabilities & CAP_EXTENDED_SECURITY)) {
301
302                 ADS_STATUS ads_status;
303                 (*cli)->use_kerberos = True;
304                 DEBUG(5, ("connecting to %s from %s with kerberos principal "
305                           "[%s]\n", controller, global_myname(),
306                           machine_krb5_principal));
307
308                 ads_status = cli_session_setup_spnego(*cli,
309                                                       machine_krb5_principal, 
310                                                       machine_password, 
311                                                       lp_workgroup());
312
313                 if (!ADS_ERR_OK(ads_status))
314                         DEBUG(4,("failed kerberos session setup with %s\n",
315                                  ads_errstr(ads_status)));
316
317                 result = ads_ntstatus(ads_status);
318         }
319
320         if (NT_STATUS_IS_OK(result))
321                 goto session_setup_done;
322
323         /* Fall back to non-kerberos session setup */
324
325         (*cli)->use_kerberos = False;
326
327         if ((((*cli)->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) != 0) &&
328             (strlen(ipc_username) > 0)) {
329
330                 /* Only try authenticated if we have a username */
331
332                 DEBUG(5, ("connecting to %s from %s with username "
333                           "[%s]\\[%s]\n",  controller, global_myname(),
334                           ipc_domain, ipc_username));
335
336                 if (cli_session_setup(*cli, ipc_username,
337                                       ipc_password, strlen(ipc_password)+1,
338                                       ipc_password, strlen(ipc_password)+1,
339                                       ipc_domain)) {
340                         DEBUG(5, ("authenticated session setup failed\n"));
341                         goto session_setup_done;
342                 }
343         }
344
345         /* Fall back to anonymous connection, this might fail later */
346
347         if (cli_session_setup(*cli, "", NULL, 0, NULL, 0, "")) {
348                 DEBUG(5, ("Connected anonymously\n"));
349                 goto session_setup_done;
350         }
351
352         result = cli_nt_error(*cli);
353
354         if (NT_STATUS_IS_OK(result))
355                 result = NT_STATUS_UNSUCCESSFUL;
356
357         /* We can't session setup */
358
359         goto done;
360
361  session_setup_done:
362
363         if (!cli_send_tconX(*cli, "IPC$", "IPC", "", 0)) {
364
365                 result = cli_nt_error(*cli);
366
367                 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
368
369                 if (NT_STATUS_IS_OK(result))
370                         result = NT_STATUS_UNSUCCESSFUL;
371
372                 cli_shutdown(*cli);
373                 goto done;
374         }
375
376         init_creds(&creds, ipc_username, ipc_domain, ipc_password);
377         cli_init_creds(*cli, &creds);
378
379         secrets_named_mutex_release(controller);
380         got_mutex = False;
381         *retry = False;
382
383         if (domain->primary || IS_DC) {
384                 NTSTATUS status = setup_schannel( *cli, domain->name );
385                 if (!NT_STATUS_IS_OK(status)) {
386                         DEBUG(3,("schannel refused - continuing without "
387                                  "schannel (%s)\n", nt_errstr(status)));
388                 }
389         }
390
391         /* set the domain if empty; needed for schannel connections */
392         if ( !*(*cli)->domain )
393                 fstrcpy( (*cli)->domain, domain->name );
394
395         if ( !cli_nt_session_open (*cli, pipe_index) ) {
396
397                 result = NT_STATUS_PIPE_NOT_AVAILABLE;
398
399                 /* This might be a NT4 DC */
400                 if ( is_win2k_pipe(pipe_index) )
401                         add_failed_connection = False;
402
403                 cli_shutdown(*cli);
404                 goto done;
405         }
406
407         result = NT_STATUS_OK;
408         add_failed_connection = False;
409
410  done:
411         if (got_mutex)
412                 secrets_named_mutex_release(controller);
413
414         SAFE_FREE(machine_password);
415         SAFE_FREE(machine_krb5_principal);
416         SAFE_FREE(ipc_username);
417         SAFE_FREE(ipc_domain);
418         SAFE_FREE(ipc_password);
419
420         if (add_failed_connection)
421                 add_failed_connection_entry(domain->name, controller, result);
422
423         return result;
424 }
425
426 struct dc_name_ip {
427         fstring name;
428         struct in_addr ip;
429 };
430
431 static BOOL add_one_dc_unique(TALLOC_CTX *mem_ctx, const char *domain_name,
432                               const char *dcname, struct in_addr ip,
433                               struct dc_name_ip **dcs, int *num)
434 {
435         if (!NT_STATUS_IS_OK(check_negative_conn_cache(domain_name, dcname)))
436                 return False;
437
438         *dcs = TALLOC_REALLOC_ARRAY(mem_ctx, *dcs, struct dc_name_ip, (*num)+1);
439
440         if (*dcs == NULL)
441                 return False;
442
443         fstrcpy((*dcs)[*num].name, dcname);
444         (*dcs)[*num].ip = ip;
445         *num += 1;
446         return True;
447 }
448
449 static BOOL add_sockaddr_to_array(TALLOC_CTX *mem_ctx,
450                                   struct in_addr ip, uint16 port,
451                                   struct sockaddr_in **addrs, int *num)
452 {
453         *addrs = TALLOC_REALLOC_ARRAY(mem_ctx, *addrs, struct sockaddr_in, (*num)+1);
454
455         if (*addrs == NULL)
456                 return False;
457
458         (*addrs)[*num].sin_family = PF_INET;
459         putip((char *)&((*addrs)[*num].sin_addr), (char *)&ip);
460         (*addrs)[*num].sin_port = htons(port);
461
462         *num += 1;
463         return True;
464 }
465
466 static BOOL get_dcs_1c(TALLOC_CTX *mem_ctx,
467                        const struct winbindd_domain *domain,
468                        struct dc_name_ip **dcs, int *num_dcs)
469 {
470         struct ip_service *iplist = NULL;
471         int i, num = 0;
472
473         if (!internal_resolve_name(domain->name, 0x1c, &iplist, &num,
474                                    lp_name_resolve_order()))
475                 return False;
476
477         /* Now try to find the server names of at least one IP address, hosts
478          * not replying are cached as such */
479
480         for (i=0; i<num; i++) {
481
482                 fstring dcname;
483
484                 if (!name_status_find(domain->name, 0x1c, 0x20, iplist[i].ip,
485                                       dcname))
486                         continue;
487
488                 if (add_one_dc_unique(mem_ctx, domain->name, dcname,
489                                       iplist[i].ip, dcs, num_dcs)) {
490                         /* One DC responded, so we assume that he will also
491                            work on 139/445 */
492                         break;
493                 }
494         }
495
496         return True;
497 }
498
499 static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain,
500                     struct dc_name_ip **dcs, int *num_dcs)
501 {
502         fstring dcname;
503         struct in_addr ip;
504         BOOL is_our_domain;
505
506         const char *p;
507
508         is_our_domain = strequal(domain->name, lp_workgroup());
509
510         if (!is_our_domain && get_dc_name_via_netlogon(domain, dcname, &ip) &&
511             add_one_dc_unique(mem_ctx, domain->name, dcname, ip, dcs, num_dcs))
512                         return True;
513
514         if (!is_our_domain) {
515                 /* NETLOGON to our own domain could not give us a DC name
516                  * (which is an error), fall back to looking up domain#1c */
517                 return get_dcs_1c(mem_ctx, domain, dcs, num_dcs);
518         }
519
520         if (must_use_pdc(domain->name) && get_pdc_ip(domain->name, &ip)) {
521
522                 if (!name_status_find(domain->name, 0x1b, 0x20, ip, dcname))
523                         return False;
524
525                 if (add_one_dc_unique(mem_ctx, domain->name,
526                                       dcname, ip, dcs, num_dcs))
527                         return True;
528         }
529
530         p = lp_passwordserver();
531
532         if (*p == 0)
533                 return get_dcs_1c(mem_ctx, domain, dcs, num_dcs);
534
535         while (next_token(&p, dcname, LIST_SEP, sizeof(dcname))) {
536
537                 if (strequal(dcname, "*")) {
538                         get_dcs_1c(mem_ctx, domain, dcs, num_dcs);
539                         continue;
540                 }
541
542                 if (!resolve_name(dcname, &ip, 0x20))
543                         continue;
544
545                 /* Even if we got the dcname, double check the name to use for
546                  * the netlogon auth2 */
547
548                 if (!name_status_find(domain->name, 0x1c, 0x20, ip, dcname))
549                         continue;
550
551                 add_one_dc_unique(mem_ctx, domain->name, dcname, ip,
552                                   dcs, num_dcs);
553         }
554
555         return True;
556 }
557
558 static BOOL find_new_dc(TALLOC_CTX *mem_ctx,
559                         const struct winbindd_domain *domain,
560                         fstring dcname, struct sockaddr_in *addr, int *fd)
561 {
562         struct dc_name_ip *dcs = NULL;
563         int num_dcs = 0;
564
565         char **dcnames = NULL;
566         int num_dcnames = 0;
567
568         struct sockaddr_in *addrs = NULL;
569         int num_addrs = 0;
570
571         int i, fd_index;
572
573         if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs) || (num_dcs == 0))
574                 return False;
575
576         for (i=0; i<num_dcs; i++) {
577
578                 add_string_to_array(mem_ctx, dcs[i].name,
579                                     &dcnames, &num_dcnames);
580                 add_sockaddr_to_array(mem_ctx, dcs[i].ip, 445,
581                                       &addrs, &num_addrs);
582
583                 add_string_to_array(mem_ctx, dcs[i].name,
584                                     &dcnames, &num_dcnames);
585                 add_sockaddr_to_array(mem_ctx, dcs[i].ip, 139,
586                                       &addrs, &num_addrs);
587         }
588
589         if ((num_dcnames == 0) || (num_dcnames != num_addrs))
590                 return False;
591
592         if (!open_any_socket_out(addrs, num_addrs, 10000, &fd_index, fd)) {
593                 for (i=0; i<num_dcs; i++) {
594                         add_failed_connection_entry(domain->name,
595                                                     dcs[i].name,
596                                                     NT_STATUS_UNSUCCESSFUL);
597                 }
598                 return False;
599         }
600
601         fstrcpy(dcname, dcnames[fd_index]);
602         *addr = addrs[fd_index];
603
604         return True;
605 }
606
607 static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
608                                    const int pipe_index,
609                                    struct winbindd_cm_conn *new_conn)
610 {
611         TALLOC_CTX *mem_ctx;
612         NTSTATUS result;
613
614         int retries;
615
616         if ((mem_ctx = talloc_init("cm_open_connection")) == NULL)
617                 return NT_STATUS_NO_MEMORY;
618
619         for (retries = 0; retries < 3; retries++) {
620
621                 int fd = -1;
622                 BOOL retry;
623
624                 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
625
626                 if ((strlen(domain->dcname) > 0) &&
627                     NT_STATUS_IS_OK(check_negative_conn_cache(domain->name,
628                                                               domain->dcname))) {
629                         int dummy;
630                         if (!open_any_socket_out(&domain->dcaddr, 1, 10000,
631                                                  &dummy, &fd)) {
632                                 fd = -1;
633                         }
634                 }
635
636                 if ((fd == -1) &&
637                     !find_new_dc(mem_ctx, domain, domain->dcname,
638                                  &domain->dcaddr, &fd))
639                         break;
640
641                 new_conn->cli = NULL;
642
643                 result = cm_prepare_connection(domain, fd, pipe_index,
644                                                domain->dcname,
645                                                &new_conn->cli, &retry);
646
647                 if (NT_STATUS_IS_OK(result)) {
648                         fstrcpy(new_conn->domain, domain->name);
649                         /* Initialise SMB connection */
650                         fstrcpy(new_conn->pipe_name,
651                                 get_pipe_name_from_index(pipe_index));
652                         break;
653                 }
654
655                 if (!retry)
656                         break;
657         }
658
659         talloc_destroy(mem_ctx);
660         return result;
661 }
662
663 /************************************************************************
664  Wrapper around statuc cm_open_connection to retreive a freshly
665  setup cli_state struct
666 ************************************************************************/
667
668 NTSTATUS cm_fresh_connection(struct winbindd_domain *domain, const int pipe_index,
669                                struct cli_state **cli)
670 {
671         NTSTATUS result;
672         struct winbindd_cm_conn conn;
673         
674         result = cm_open_connection( domain, pipe_index, &conn );
675         
676         if ( NT_STATUS_IS_OK(result) ) 
677                 *cli = conn.cli;
678
679         return result;
680 }
681
682 /* Return true if a connection is still alive */
683
684 static BOOL connection_ok(struct winbindd_cm_conn *conn)
685 {
686         if (!conn) {
687                 smb_panic("Invalid parameter passed to connection_ok():  conn was NULL!\n");
688                 return False;
689         }
690
691         if (!conn->cli) {
692                 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has NULL conn->cli!\n", 
693                           conn->controller, conn->domain, conn->pipe_name));
694                 return False;
695         }
696
697         if (!conn->cli->initialised) {
698                 DEBUG(3, ("Connection to %s for domain %s (pipe %s) was never initialised!\n", 
699                           conn->controller, conn->domain, conn->pipe_name));
700                 return False;
701         }
702
703         if (conn->cli->fd == -1) {
704                 DEBUG(3, ("Connection to %s for domain %s (pipe %s) has died or was never started (fd == -1)\n", 
705                           conn->controller, conn->domain, conn->pipe_name));
706                 return False;
707         }
708         
709         return True;
710 }
711
712 /* Search the cache for a connection. If there is a broken one,
713    shut it down properly and return NULL. */
714
715 static void find_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
716                                struct winbindd_cm_conn **conn_out) 
717 {
718         struct winbindd_cm_conn *conn;
719
720         for (conn = cm_conns; conn; ) {
721                 if (strequal(conn->domain, domain->name) && 
722                     strequal(conn->pipe_name, pipe_name)) {
723                         if (!connection_ok(conn)) {
724                                 /* Dead connection - remove it. */
725                                 struct winbindd_cm_conn *conn_temp = conn->next;
726                                 if (conn->cli)
727                                         cli_shutdown(conn->cli);
728                                 DLIST_REMOVE(cm_conns, conn);
729                                 SAFE_FREE(conn);
730                                 conn = conn_temp;  /* Keep the loop moving */
731                                 continue;
732                         } else {
733                                 break;
734                         }
735                 }
736                 conn = conn->next;
737         }
738
739         *conn_out = conn;
740 }
741
742 /* Initialize a new connection up to the RPC BIND. */
743
744 static NTSTATUS new_cm_connection(struct winbindd_domain *domain, const char *pipe_name,
745                                   struct winbindd_cm_conn **conn_out)
746 {
747         struct winbindd_cm_conn *conn;
748         NTSTATUS result;
749
750         if (!(conn = SMB_MALLOC_P(struct winbindd_cm_conn)))
751                 return NT_STATUS_NO_MEMORY;
752                 
753         ZERO_STRUCTP(conn);
754                 
755         if (!NT_STATUS_IS_OK(result = cm_open_connection(domain, get_pipe_index(pipe_name), conn))) {
756                 DEBUG(3, ("Could not open a connection to %s for %s (%s)\n", 
757                           domain->name, pipe_name, nt_errstr(result)));
758                 SAFE_FREE(conn);
759                 return result;
760         }
761         DLIST_ADD(cm_conns, conn);
762
763         *conn_out = conn;
764         return NT_STATUS_OK;
765 }
766
767 /* Get a connection to the remote DC and open the pipe.  If there is already a connection, use that */
768
769 static NTSTATUS get_connection_from_cache(struct winbindd_domain *domain, const char *pipe_name,
770                                           struct winbindd_cm_conn **conn_out)
771 {
772         find_cm_connection(domain, pipe_name, conn_out);
773
774         if (*conn_out != NULL)
775                 return NT_STATUS_OK;
776
777         return new_cm_connection(domain, pipe_name, conn_out);
778 }
779
780 /**********************************************************************************
781  We can 'sense' certain things about the DC by it's replies to certain questions.
782
783  This tells us if this particular remote server is Active Directory, and if it is
784  native mode.
785 **********************************************************************************/
786
787 void set_dc_type_and_flags( struct winbindd_domain *domain )
788 {
789         NTSTATUS                result;
790         struct winbindd_cm_conn conn;
791         DS_DOMINFO_CTR          ctr;
792         TALLOC_CTX              *mem_ctx = NULL;
793         
794         ZERO_STRUCT( conn );
795         ZERO_STRUCT( ctr );
796         
797         domain->native_mode = False;
798         domain->active_directory = False;
799
800         if (domain->internal) {
801                 domain->initialized = True;
802                 return;
803         }
804         
805         if ( !NT_STATUS_IS_OK(result = cm_open_connection(domain, PI_LSARPC_DS, &conn)) ) {
806                 DEBUG(5, ("set_dc_type_and_flags: Could not open a connection to %s for PIPE_LSARPC (%s)\n", 
807                           domain->name, nt_errstr(result)));
808                 domain->initialized = True;
809                 return;
810         }
811         
812         if ( conn.cli ) {
813                 if ( !NT_STATUS_IS_OK(cli_ds_getprimarydominfo( conn.cli, 
814                                 conn.cli->mem_ctx, DsRolePrimaryDomainInfoBasic, &ctr)) ) {
815                         goto done;
816                 }
817         }
818                                 
819         if ( (ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING) 
820                         && !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE) )
821                 domain->native_mode = True;
822
823         /* Cheat - shut down the DS pipe, and open LSA */
824
825         cli_nt_session_close(conn.cli);
826
827         if ( cli_nt_session_open (conn.cli, PI_LSARPC) ) {
828                 char *domain_name = NULL;
829                 char *dns_name = NULL;
830                 DOM_SID *dom_sid = NULL;
831
832                 mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n", domain->name);
833                 if (!mem_ctx) {
834                         DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
835                         return;
836                 }
837
838                 result = cli_lsa_open_policy2(conn.cli, mem_ctx, True, 
839                                               SEC_RIGHTS_MAXIMUM_ALLOWED,
840                                               &conn.pol);
841                 
842                 if (NT_STATUS_IS_OK(result)) {
843                         /* This particular query is exactly what Win2k clients use 
844                            to determine that the DC is active directory */
845                         result = cli_lsa_query_info_policy2(conn.cli, mem_ctx, 
846                                                             &conn.pol,
847                                                             12, &domain_name,
848                                                             &dns_name, NULL,
849                                                             NULL, &dom_sid);
850                 }
851
852                 if (NT_STATUS_IS_OK(result)) {
853                         if (domain_name)
854                                 fstrcpy(domain->name, domain_name);
855                         
856                         if (dns_name)
857                                 fstrcpy(domain->alt_name, dns_name);
858
859                         if (dom_sid) 
860                                 sid_copy(&domain->sid, dom_sid);
861
862                         domain->active_directory = True;
863                 } else {
864                         
865                         result = cli_lsa_open_policy(conn.cli, mem_ctx, True, 
866                                                      SEC_RIGHTS_MAXIMUM_ALLOWED,
867                                                      &conn.pol);
868                         
869                         if (!NT_STATUS_IS_OK(result))
870                                 goto done;
871                         
872                         result = cli_lsa_query_info_policy(conn.cli, mem_ctx, 
873                                                            &conn.pol, 5, &domain_name, 
874                                                            &dom_sid);
875                         
876                         if (NT_STATUS_IS_OK(result)) {
877                                 if (domain_name)
878                                         fstrcpy(domain->name, domain_name);
879                                 
880                                 if (dom_sid) 
881                                         sid_copy(&domain->sid, dom_sid);
882                         }
883                 }
884         }
885         
886 done:
887         
888         /* close the connection;  no other calls use this pipe and it is called only
889            on reestablishing the domain list   --jerry */
890         
891         if ( conn.cli )
892                 cli_shutdown( conn.cli );
893         
894         talloc_destroy(mem_ctx);
895
896         domain->initialized = True;
897         
898         return;
899 }
900
901
902
903 /* Return a LSA policy handle on a domain */
904
905 NTSTATUS cm_get_lsa_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
906 {
907         struct winbindd_cm_conn *conn;
908         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
909         NTSTATUS result;
910         static CLI_POLICY_HND hnd;
911
912         /* Look for existing connections */
913
914         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
915                 return result;
916
917         /* This *shitty* code needs scrapping ! JRA */
918         
919         if (policy_handle_is_valid(&conn->pol)) {
920                 hnd.pol = conn->pol;
921                 hnd.cli = conn->cli;
922                 *return_hnd = &hnd;
923
924                 return NT_STATUS_OK;
925         }
926         
927         result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False, 
928                                      des_access, &conn->pol);
929
930         if (!NT_STATUS_IS_OK(result)) {
931                 /* Hit the cache code again.  This cleans out the old connection and gets a new one */
932                 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
933                         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
934                                 return result;
935
936                         result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False, 
937                                                      des_access, &conn->pol);
938                 }
939
940                 if (!NT_STATUS_IS_OK(result)) {
941                         cli_shutdown(conn->cli);
942                         DLIST_REMOVE(cm_conns, conn);
943                         SAFE_FREE(conn);
944                         return result;
945                 }
946         }       
947
948         hnd.pol = conn->pol;
949         hnd.cli = conn->cli;
950
951         *return_hnd = &hnd;
952
953         return NT_STATUS_OK;
954 }
955
956 /* Return a SAM policy handle on a domain */
957
958 NTSTATUS cm_get_sam_handle(struct winbindd_domain *domain, CLI_POLICY_HND **return_hnd)
959
960         struct winbindd_cm_conn *conn;
961         uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
962         NTSTATUS result;
963         static CLI_POLICY_HND hnd;
964
965         /* Look for existing connections */
966
967         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
968                 return result;
969         
970         /* This *shitty* code needs scrapping ! JRA */
971         
972         if (policy_handle_is_valid(&conn->pol)) {
973                 hnd.pol = conn->pol;
974                 hnd.cli = conn->cli;
975                 
976                 *return_hnd = &hnd;
977
978                 return NT_STATUS_OK;
979         }
980         
981         result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
982                                   des_access, &conn->pol);
983
984         if (!NT_STATUS_IS_OK(result)) {
985                 /* Hit the cache code again.  This cleans out the old connection and gets a new one */
986                 if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
987                 
988                         if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
989                                 return result;
990
991                         result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
992                                                   des_access, &conn->pol);
993                 }
994
995                 if (!NT_STATUS_IS_OK(result)) {
996                 
997                         cli_shutdown(conn->cli);
998                         DLIST_REMOVE(cm_conns, conn);
999                         SAFE_FREE(conn);
1000                         
1001                         return result;
1002                 }
1003         }       
1004
1005         hnd.pol = conn->pol;
1006         hnd.cli = conn->cli;
1007
1008         *return_hnd = &hnd;
1009
1010         return NT_STATUS_OK;
1011 }
1012
1013 /* Get a handle on a netlogon pipe.  This is a bit of a hack to re-use the
1014    netlogon pipe as no handle is returned. */
1015
1016 NTSTATUS cm_get_netlogon_cli(struct winbindd_domain *domain, 
1017                              const unsigned char *trust_passwd, 
1018                              uint32 sec_channel_type,
1019                              BOOL fresh,
1020                              struct cli_state **cli)
1021 {
1022         NTSTATUS result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
1023         struct winbindd_cm_conn *conn;
1024         fstring lock_name;
1025         BOOL got_mutex;
1026
1027         if (!cli)
1028                 return NT_STATUS_INVALID_PARAMETER;
1029
1030         /* Open an initial conection - keep the mutex. */
1031
1032         find_cm_connection(domain, PIPE_NETLOGON, &conn);
1033
1034         if ( fresh && (conn != NULL) ) {
1035                 cli_shutdown(conn->cli);
1036                 conn->cli = NULL;
1037
1038                 conn = NULL;
1039
1040                 /* purge connection from cache */
1041                 find_cm_connection(domain, PIPE_NETLOGON, &conn);
1042                 if (conn != NULL) {
1043                         DEBUG(0,("Could not purge connection\n"));
1044                         return NT_STATUS_UNSUCCESSFUL;
1045                 }
1046         }
1047
1048         if (conn != NULL) {
1049                 *cli = conn->cli;
1050                 return NT_STATUS_OK;
1051         }
1052
1053         result = new_cm_connection(domain, PIPE_NETLOGON, &conn);
1054
1055         if (!NT_STATUS_IS_OK(result))
1056                 return result;
1057         
1058         fstr_sprintf(lock_name, "NETLOGON\\%s", conn->controller);
1059
1060         if (!(got_mutex = secrets_named_mutex(lock_name, WINBIND_SERVER_MUTEX_WAIT_TIME))) {
1061                 DEBUG(0,("cm_get_netlogon_cli: mutex grab failed for %s\n", conn->controller));
1062         }
1063         
1064         if ( sec_channel_type == SEC_CHAN_DOMAIN )
1065                 fstr_sprintf(conn->cli->mach_acct, "%s$", lp_workgroup());
1066                         
1067         /* This must be the remote domain (not ours) for schannel */
1068
1069         fstrcpy( conn->cli->domain, domain->name);
1070         
1071         result = cli_nt_establish_netlogon(conn->cli, sec_channel_type, trust_passwd);
1072         
1073         if (got_mutex)
1074                 secrets_named_mutex_release(lock_name);
1075                                 
1076         if (!NT_STATUS_IS_OK(result)) {
1077                 cli_shutdown(conn->cli);
1078                 DLIST_REMOVE(cm_conns, conn);
1079                 SAFE_FREE(conn);
1080                 return result;
1081         }
1082
1083         *cli = conn->cli;
1084
1085         return result;
1086 }
1087
1088 /* Dump the current connection status */
1089
1090 static void dump_conn_list(void)
1091 {
1092         struct winbindd_cm_conn *con;
1093
1094         DEBUG(0, ("\tDomain          Controller      Pipe\n"));
1095
1096         for(con = cm_conns; con; con = con->next) {
1097                 char *msg;
1098
1099                 /* Display pipe info */
1100                 
1101                 if (asprintf(&msg, "\t%-15s %-15s %-16s", con->domain, con->controller, con->pipe_name) < 0) {
1102                         DEBUG(0, ("Error: not enough memory!\n"));
1103                 } else {
1104                         DEBUG(0, ("%s\n", msg));
1105                         SAFE_FREE(msg);
1106                 }
1107         }
1108 }
1109
1110 void winbindd_cm_status(void)
1111 {
1112         /* List open connections */
1113
1114         DEBUG(0, ("winbindd connection manager status:\n"));
1115
1116         if (cm_conns)
1117                 dump_conn_list();
1118         else
1119                 DEBUG(0, ("\tNo active connections\n"));
1120 }
1121
1122 /* Close all cached connections */
1123
1124 void winbindd_cm_flush(void)
1125 {
1126         struct winbindd_cm_conn *conn, tmp;
1127
1128         /* Flush connection cache */
1129
1130         for (conn = cm_conns; conn; conn = conn->next) {
1131
1132                 if (!connection_ok(conn))
1133                         continue;
1134
1135                 DEBUG(10, ("Closing connection to %s on %s\n",
1136                         conn->pipe_name, conn->controller));
1137
1138                 if (conn->cli)
1139                         cli_shutdown(conn->cli);
1140
1141                 tmp.next = conn->next;
1142
1143                 DLIST_REMOVE(cm_conns, conn);
1144                 SAFE_FREE(conn);
1145                 conn = &tmp;
1146         }
1147
1148         /* Flush failed connection cache */
1149
1150         flush_negative_conn_cache();
1151 }