nsswitch/winbindd_cm.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003 
00004    Winbind daemon connection manager
00005 
00006    Copyright (C) Tim Potter                2001
00007    Copyright (C) Andrew Bartlett           2002
00008    Copyright (C) Gerald (Jerry) Carter     2003-2005.
00009    Copyright (C) Volker Lendecke           2004-2005
00010    Copyright (C) Jeremy Allison            2006
00011    
00012    This program is free software; you can redistribute it and/or modify
00013    it under the terms of the GNU General Public License as published by
00014    the Free Software Foundation; either version 2 of the License, or
00015    (at your option) any later version.
00016    
00017    This program is distributed in the hope that it will be useful,
00018    but WITHOUT ANY WARRANTY; without even the implied warranty of
00019    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020    GNU General Public License for more details.
00021    
00022    You should have received a copy of the GNU General Public License
00023    along with this program; if not, write to the Free Software
00024    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00025 */
00026 
00027 /*
00028    We need to manage connections to domain controllers without having to
00029    mess up the main winbindd code with other issues.  The aim of the
00030    connection manager is to:
00031   
00032        - make connections to domain controllers and cache them
00033        - re-establish connections when networks or servers go down
00034        - centralise the policy on connection timeouts, domain controller
00035          selection etc
00036        - manage re-entrancy for when winbindd becomes able to handle
00037          multiple outstanding rpc requests
00038   
00039    Why not have connection management as part of the rpc layer like tng?
00040    Good question.  This code may morph into libsmb/rpc_cache.c or something
00041    like that but at the moment it's simply staying as part of winbind.  I
00042    think the TNG architecture of forcing every user of the rpc layer to use
00043    the connection caching system is a bad idea.  It should be an optional
00044    method of using the routines.
00045 
00046    The TNG design is quite good but I disagree with some aspects of the
00047    implementation. -tpot
00048 
00049  */
00050 
00051 /*
00052    TODO:
00053 
00054      - I'm pretty annoyed by all the make_nmb_name() stuff.  It should be
00055        moved down into another function.
00056 
00057      - Take care when destroying cli_structs as they can be shared between
00058        various sam handles.
00059 
00060  */
00061 
00062 #include "includes.h"
00063 #include "winbindd.h"
00064 
00065 #undef DBGC_CLASS
00066 #define DBGC_CLASS DBGC_WINBIND
00067 
00068 struct dc_name_ip {
00069         fstring name;
00070         struct in_addr ip;
00071 };
00072 
00073 extern struct winbindd_methods reconnect_methods;
00074 extern BOOL override_logfile;
00075 
00076 static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain);
00077 static void set_dc_type_and_flags( struct winbindd_domain *domain );
00078 static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain,
00079                     struct dc_name_ip **dcs, int *num_dcs);
00080 
00081 /****************************************************************
00082  Child failed to find DC's. Reschedule check.
00083 ****************************************************************/
00084 
00085 static void msg_failed_to_go_online(int msg_type, struct process_id src,
00086                                     void *buf, size_t len, void *private_data)
00087 {
00088         struct winbindd_domain *domain;
00089         const char *domainname = (const char *)buf;
00090 
00091         if (buf == NULL || len == 0) {
00092                 return;
00093         }
00094 
00095         DEBUG(5,("msg_fail_to_go_online: received for domain %s.\n", domainname));
00096 
00097         for (domain = domain_list(); domain; domain = domain->next) {
00098                 if (domain->internal) {
00099                         continue;
00100                 }
00101 
00102                 if (strequal(domain->name, domainname)) {
00103                         if (domain->online) {
00104                                 /* We're already online, ignore. */
00105                                 DEBUG(5,("msg_fail_to_go_online: domain %s "
00106                                         "already online.\n", domainname));
00107                                 continue;
00108                         }
00109 
00110                         /* Reschedule the online check. */
00111                         set_domain_offline(domain);
00112                         break;
00113                 }
00114         }
00115 }
00116 
00117 /****************************************************************
00118  Actually cause a reconnect from a message.
00119 ****************************************************************/
00120 
00121 static void msg_try_to_go_online(int msg_type, struct process_id src,
00122                                  void *buf, size_t len, void *private_data)
00123 {
00124         struct winbindd_domain *domain;
00125         const char *domainname = (const char *)buf;
00126 
00127         if (buf == NULL || len == 0) {
00128                 return;
00129         }
00130 
00131         DEBUG(5,("msg_try_to_go_online: received for domain %s.\n", domainname));
00132 
00133         for (domain = domain_list(); domain; domain = domain->next) {
00134                 if (domain->internal) {
00135                         continue;
00136                 }
00137 
00138                 if (strequal(domain->name, domainname)) {
00139 
00140                         if (domain->online) {
00141                                 /* We're already online, ignore. */
00142                                 DEBUG(5,("msg_try_to_go_online: domain %s "
00143                                         "already online.\n", domainname));
00144                                 continue;
00145                         }
00146 
00147                         /* This call takes care of setting the online
00148                            flag to true if we connected, or re-adding
00149                            the offline handler if false. Bypasses online
00150                            check so always does network calls. */
00151 
00152                         init_dc_connection_network(domain);
00153                         break;
00154                 }
00155         }
00156 }
00157 
00158 /****************************************************************
00159  Fork a child to try and contact a DC. Do this as contacting a
00160  DC requires blocking lookups and we don't want to block our
00161  parent.
00162 ****************************************************************/
00163 
00164 static BOOL fork_child_dc_connect(struct winbindd_domain *domain)
00165 {
00166         struct dc_name_ip *dcs = NULL;
00167         int num_dcs = 0;
00168         TALLOC_CTX *mem_ctx = NULL;
00169         pid_t child_pid;
00170         pid_t parent_pid = sys_getpid();
00171 
00172         /* Stop zombies */
00173         CatchChild();
00174 
00175         message_block();
00176 
00177         child_pid = sys_fork();
00178 
00179         if (child_pid == -1) {
00180                 DEBUG(0, ("fork_child_dc_connect: Could not fork: %s\n", strerror(errno)));
00181                 message_unblock();
00182                 return False;
00183         }
00184 
00185         if (child_pid != 0) {
00186                 /* Parent */
00187                 message_register(MSG_WINBIND_TRY_TO_GO_ONLINE,
00188                                  msg_try_to_go_online, NULL);
00189                 message_register(MSG_WINBIND_FAILED_TO_GO_ONLINE,
00190                                  msg_failed_to_go_online, NULL);
00191                 message_unblock();
00192                 return True;
00193         }
00194 
00195         /* Child. */
00196 
00197         /* Leave messages blocked - we will never process one. */
00198 
00199         /* tdb needs special fork handling */
00200         if (tdb_reopen_all(1) == -1) {
00201                 DEBUG(0,("tdb_reopen_all failed.\n"));
00202                 _exit(0);
00203         }
00204 
00205         close_conns_after_fork();
00206 
00207         if (!override_logfile) {
00208                 pstring logfile;
00209                 pstr_sprintf(logfile, "%s/winbindd-dc-connect.log", dyn_LOGFILEBASE);
00210                 lp_set_logfile(logfile);
00211                 reopen_logs();
00212         }
00213 
00214         mem_ctx = talloc_init("fork_child_dc_connect");
00215         if (!mem_ctx) {
00216                 DEBUG(0,("talloc_init failed.\n"));
00217                 _exit(0);
00218         }
00219 
00220         if ((!get_dcs(mem_ctx, domain, &dcs, &num_dcs)) || (num_dcs == 0)) {
00221                 /* Still offline ? Can't find DC's. */
00222                 message_send_pid(pid_to_procid(parent_pid), MSG_WINBIND_FAILED_TO_GO_ONLINE,
00223                                 domain->name,
00224                                 strlen(domain->name)+1, False);
00225                 _exit(0);
00226         }
00227 
00228         /* We got a DC. Send a message to our parent to get it to
00229            try and do the same. */
00230 
00231         message_send_pid(pid_to_procid(parent_pid), MSG_WINBIND_TRY_TO_GO_ONLINE,
00232                                 domain->name,
00233                                 strlen(domain->name)+1, False);
00234         _exit(0);
00235 }
00236 
00237 /****************************************************************
00238  Handler triggered if we're offline to try and detect a DC.
00239 ****************************************************************/
00240 
00241 static void check_domain_online_handler(struct event_context *ctx,
00242                                         struct timed_event *te,
00243                                         const struct timeval *now,
00244                                         void *private_data)
00245 {
00246         struct winbindd_domain *domain =
00247                 (struct winbindd_domain *)private_data;
00248 
00249         DEBUG(10,("check_domain_online_handler: called for domain %s\n",
00250                 domain->name ));
00251 
00252         TALLOC_FREE(domain->check_online_event);
00253 
00254         /* Are we still in "startup" mode ? */
00255 
00256         if (domain->startup && (now->tv_sec > domain->startup_time + 30)) {
00257                 /* No longer in "startup" mode. */
00258                 DEBUG(10,("check_domain_online_handler: domain %s no longer in 'startup' mode.\n",
00259                         domain->name ));
00260                 domain->startup = False;
00261         }
00262 
00263         /* We've been told to stay offline, so stay
00264            that way. */
00265 
00266         if (get_global_winbindd_state_offline()) {
00267                 DEBUG(10,("check_domain_online_handler: domain %s remaining globally offline\n",
00268                         domain->name ));
00269                 return;
00270         }
00271 
00272         /* Fork a child to test if it can contact a DC. 
00273            If it can then send ourselves a message to
00274            cause a reconnect. */
00275 
00276         fork_child_dc_connect(domain);
00277 }
00278 
00279 /****************************************************************
00280  If we're still offline setup the timeout check.
00281 ****************************************************************/
00282 
00283 static void calc_new_online_timeout_check(struct winbindd_domain *domain)
00284 {
00285         int wbc = lp_winbind_cache_time();
00286 
00287         if (domain->startup) {
00288                 domain->check_online_timeout = 10;
00289         } else if (domain->check_online_timeout < wbc) {
00290                 domain->check_online_timeout = wbc;
00291         }
00292 }
00293 
00294 /****************************************************************
00295  Set domain offline and also add handler to put us back online
00296  if we detect a DC.
00297 ****************************************************************/
00298 
00299 void set_domain_offline(struct winbindd_domain *domain)
00300 {
00301         DEBUG(10,("set_domain_offline: called for domain %s\n",
00302                 domain->name ));
00303 
00304         TALLOC_FREE(domain->check_online_event);
00305 
00306         if (domain->internal) {
00307                 DEBUG(3,("set_domain_offline: domain %s is internal - logic error.\n",
00308                         domain->name ));
00309                 return;
00310         }
00311 
00312         domain->online = False;
00313 
00314         /* Offline domains are always initialized. They're
00315            re-initialized when they go back online. */
00316 
00317         domain->initialized = True;
00318 
00319         /* We only add the timeout handler that checks and
00320            allows us to go back online when we've not
00321            been told to remain offline. */
00322 
00323         if (get_global_winbindd_state_offline()) {
00324                 DEBUG(10,("set_domain_offline: domain %s remaining globally offline\n",
00325                         domain->name ));
00326                 return;
00327         }
00328 
00329         /* If we're in statup mode, check again in 10 seconds, not in
00330            lp_winbind_cache_time() seconds (which is 5 mins by default). */
00331 
00332         calc_new_online_timeout_check(domain);
00333 
00334         domain->check_online_event = event_add_timed(winbind_event_context(),
00335                                                 NULL,
00336                                                 timeval_current_ofs(domain->check_online_timeout,0),
00337                                                 "check_domain_online_handler",
00338                                                 check_domain_online_handler,
00339                                                 domain);
00340 
00341         /* The above *has* to succeed for winbindd to work. */
00342         if (!domain->check_online_event) {
00343                 smb_panic("set_domain_offline: failed to add online handler.\n");
00344         }
00345 
00346         DEBUG(10,("set_domain_offline: added event handler for domain %s\n",
00347                 domain->name ));
00348 }
00349 
00350 /****************************************************************
00351  Set domain online - if allowed.
00352 ****************************************************************/
00353 
00354 static void set_domain_online(struct winbindd_domain *domain)
00355 {
00356         struct timeval now;
00357 
00358         DEBUG(10,("set_domain_online: called for domain %s\n",
00359                 domain->name ));
00360 
00361         if (domain->internal) {
00362                 DEBUG(3,("set_domain_online: domain %s is internal - logic error.\n",
00363                         domain->name ));
00364                 return;
00365         }
00366 
00367         if (get_global_winbindd_state_offline()) {
00368                 DEBUG(10,("set_domain_online: domain %s remaining globally offline\n",
00369                         domain->name ));
00370                 return;
00371         }
00372 
00373         /* If we are waiting to get a krb5 ticket, trigger immediately. */
00374         GetTimeOfDay(&now);
00375         set_event_dispatch_time(winbind_event_context(),
00376                                 "krb5_ticket_gain_handler", now);
00377 
00378         /* Ok, we're out of any startup mode now... */
00379         domain->startup = False;
00380 
00381         if (domain->online == False) {
00382                 /* We were offline - now we're online. We default to
00383                    using the MS-RPC backend if we started offline,
00384                    and if we're going online for the first time we
00385                    should really re-initialize the backends and the
00386                    checks to see if we're talking to an AD or NT domain.
00387                 */
00388 
00389                 domain->initialized = False;
00390 
00391                 /* 'reconnect_methods' is the MS-RPC backend. */
00392                 if (domain->backend == &reconnect_methods) {
00393                         domain->backend = NULL;
00394                 }
00395         }
00396 
00397         /* Ensure we have no online timeout checks. */
00398         domain->check_online_timeout = 0;
00399         TALLOC_FREE(domain->check_online_event);
00400 
00401         /* Ensure we ignore any pending child messages. */
00402         message_deregister(MSG_WINBIND_TRY_TO_GO_ONLINE);
00403         message_deregister(MSG_WINBIND_FAILED_TO_GO_ONLINE);
00404 
00405         domain->online = True;
00406 }
00407 
00408 /****************************************************************
00409  Requested to set a domain online.
00410 ****************************************************************/
00411 
00412 void set_domain_online_request(struct winbindd_domain *domain)
00413 {
00414         struct timeval tev;
00415 
00416         DEBUG(10,("set_domain_online_request: called for domain %s\n",
00417                 domain->name ));
00418 
00419         if (get_global_winbindd_state_offline()) {
00420                 DEBUG(10,("set_domain_online_request: domain %s remaining globally offline\n",
00421                         domain->name ));
00422                 return;
00423         }
00424 
00425         /* We've been told it's safe to go online and
00426            try and connect to a DC. But I don't believe it
00427            because network manager seems to lie.
00428            Wait at least 5 seconds. Heuristics suck... */
00429 
00430         if (!domain->check_online_event) {
00431                 /* If we've come from being globally offline we
00432                    don't have a check online event handler set.
00433                    We need to add one now we're trying to go
00434                    back online. */
00435 
00436                 DEBUG(10,("set_domain_online_request: domain %s was globally offline.\n",
00437                         domain->name ));
00438 
00439                 domain->check_online_event = event_add_timed(winbind_event_context(),
00440                                                                 NULL,
00441                                                                 timeval_current_ofs(5, 0),
00442                                                                 "check_domain_online_handler",
00443                                                                 check_domain_online_handler,
00444                                                                 domain);
00445 
00446                 /* The above *has* to succeed for winbindd to work. */
00447                 if (!domain->check_online_event) {
00448                         smb_panic("set_domain_online_request: failed to add online handler.\n");
00449                 }
00450         }
00451 
00452         GetTimeOfDay(&tev);
00453 
00454         /* Go into "startup" mode again. */
00455         domain->startup_time = tev.tv_sec;
00456         domain->startup = True;
00457 
00458         tev.tv_sec += 5;
00459 
00460         set_event_dispatch_time(winbind_event_context(), "check_domain_online_handler", tev);
00461 }
00462 
00463 /****************************************************************
00464  Add -ve connection cache entries for domain and realm.
00465 ****************************************************************/
00466 
00467 void winbind_add_failed_connection_entry(const struct winbindd_domain *domain,
00468                                         const char *server,
00469                                         NTSTATUS result)
00470 {
00471         add_failed_connection_entry(domain->name, server, result);
00472         /* If this was the saf name for the last thing we talked to,
00473            remove it. */
00474         saf_delete(domain->name);
00475         if (*domain->alt_name) {
00476                 add_failed_connection_entry(domain->alt_name, server, result);
00477                 saf_delete(domain->alt_name);
00478         }
00479 }
00480 
00481 /* Choose between anonymous or authenticated connections.  We need to use
00482    an authenticated connection if DCs have the RestrictAnonymous registry
00483    entry set > 0, or the "Additional restrictions for anonymous
00484    connections" set in the win2k Local Security Policy. 
00485    
00486    Caller to free() result in domain, username, password
00487 */
00488 
00489 static void cm_get_ipc_userpass(char **username, char **domain, char **password)
00490 {
00491         *username = (char *)secrets_fetch(SECRETS_AUTH_USER, NULL);
00492         *domain = (char *)secrets_fetch(SECRETS_AUTH_DOMAIN, NULL);
00493         *password = (char *)secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
00494         
00495         if (*username && **username) {
00496 
00497                 if (!*domain || !**domain)
00498                         *domain = smb_xstrdup(lp_workgroup());
00499                 
00500                 if (!*password || !**password)
00501                         *password = smb_xstrdup("");
00502 
00503                 DEBUG(3, ("cm_get_ipc_userpass: Retrieved auth-user from secrets.tdb [%s\\%s]\n", 
00504                           *domain, *username));
00505 
00506         } else {
00507                 DEBUG(3, ("cm_get_ipc_userpass: No auth-user defined\n"));
00508                 *username = smb_xstrdup("");
00509                 *domain = smb_xstrdup("");
00510                 *password = smb_xstrdup("");
00511         }
00512 }
00513 
00514 static BOOL get_dc_name_via_netlogon(const struct winbindd_domain *domain,
00515                                      fstring dcname, struct in_addr *dc_ip)
00516 {
00517         struct winbindd_domain *our_domain = NULL;
00518         struct rpc_pipe_client *netlogon_pipe = NULL;
00519         NTSTATUS result;
00520         WERROR werr;
00521         TALLOC_CTX *mem_ctx;
00522         unsigned int orig_timeout;
00523         fstring tmp;
00524         char *p;
00525 
00526         /* Hmmmm. We can only open one connection to the NETLOGON pipe at the
00527          * moment.... */
00528 
00529         if (IS_DC) {
00530                 return False;
00531         }
00532 
00533         if (domain->primary) {
00534                 return False;
00535         }
00536 
00537         our_domain = find_our_domain();
00538 
00539         if ((mem_ctx = talloc_init("get_dc_name_via_netlogon")) == NULL) {
00540                 return False;
00541         }
00542 
00543         result = cm_connect_netlogon(our_domain, &netlogon_pipe);
00544         if (!NT_STATUS_IS_OK(result)) {
00545                 talloc_destroy(mem_ctx);
00546                 return False;
00547         }
00548 
00549         /* This call can take a long time - allow the server to time out.
00550            35 seconds should do it. */
00551 
00552         orig_timeout = cli_set_timeout(netlogon_pipe->cli, 35000);
00553         
00554         werr = rpccli_netlogon_getanydcname(netlogon_pipe, mem_ctx, our_domain->dcname,
00555                                             domain->name, tmp);
00556 
00557         /* And restore our original timeout. */
00558         cli_set_timeout(netlogon_pipe->cli, orig_timeout);
00559 
00560         talloc_destroy(mem_ctx);
00561 
00562         if (!W_ERROR_IS_OK(werr)) {
00563                 DEBUG(10, ("rpccli_netlogon_getanydcname failed: %s\n",
00564                            dos_errstr(werr)));
00565                 return False;
00566         }
00567 
00568         /* cli_netlogon_getanydcname gives us a name with \\ */
00569         p = tmp;
00570         if (*p == '\\') {
00571                 p+=1;
00572         }
00573         if (*p == '\\') {
00574                 p+=1;
00575         }
00576 
00577         fstrcpy(dcname, p);
00578 
00579         DEBUG(10, ("rpccli_netlogon_getanydcname returned %s\n", dcname));
00580 
00581         if (!resolve_name(dcname, dc_ip, 0x20)) {
00582                 return False;
00583         }
00584 
00585         return True;
00586 }
00587 
00588 /**
00589  * Helper function to assemble trust password and account name
00590  */
00591 static NTSTATUS get_trust_creds(const struct winbindd_domain *domain,
00592                                 char **machine_password,
00593                                 char **machine_account,
00594                                 char **machine_krb5_principal)
00595 {
00596         const char *account_name;
00597 
00598         if (!get_trust_pw_clear(domain->name, machine_password,
00599                                 &account_name, NULL))
00600         {
00601                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
00602         }
00603 
00604         if ((machine_account != NULL) &&
00605             (asprintf(machine_account, "%s$", account_name) == -1))
00606         {
00607                 return NT_STATUS_NO_MEMORY;
00608         }
00609 
00610         /* For now assume our machine account only exists in our domain */
00611 
00612         if (machine_krb5_principal != NULL)
00613         {
00614                 if (asprintf(machine_krb5_principal, "%s$@%s",
00615                              account_name, lp_realm()) == -1)
00616                 {
00617                         return NT_STATUS_NO_MEMORY;
00618                 }
00619 
00620                 strupper_m(*machine_krb5_principal);
00621         }
00622 
00623         return NT_STATUS_OK;
00624 }
00625 
00626 /************************************************************************
00627  Given a fd with a just-connected TCP connection to a DC, open a connection
00628  to the pipe.
00629 ************************************************************************/
00630 
00631 static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
00632                                       const int sockfd,
00633                                       const char *controller,
00634                                       struct cli_state **cli,
00635                                       BOOL *retry)
00636 {
00637         char *machine_password = NULL;
00638         char *machine_krb5_principal = NULL;
00639         char *machine_account = NULL;
00640         char *ipc_username = NULL;
00641         char *ipc_domain = NULL;
00642         char *ipc_password = NULL;
00643 
00644         BOOL got_mutex;
00645 
00646         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
00647 
00648         struct sockaddr peeraddr;
00649         socklen_t peeraddr_len;
00650 
00651         struct sockaddr_in *peeraddr_in = (struct sockaddr_in *)&peeraddr;
00652 
00653         DEBUG(10,("cm_prepare_connection: connecting to DC %s for domain %s\n",
00654                 controller, domain->name ));
00655 
00656         *retry = True;
00657 
00658         got_mutex = secrets_named_mutex(controller,
00659                                         WINBIND_SERVER_MUTEX_WAIT_TIME);
00660 
00661         if (!got_mutex) {
00662                 DEBUG(0,("cm_prepare_connection: mutex grab failed for %s\n",
00663                          controller));
00664                 result = NT_STATUS_POSSIBLE_DEADLOCK;
00665                 goto done;
00666         }
00667 
00668         if ((*cli = cli_initialise()) == NULL) {
00669                 DEBUG(1, ("Could not cli_initialize\n"));
00670                 result = NT_STATUS_NO_MEMORY;
00671                 goto done;
00672         }
00673 
00674         (*cli)->timeout = 10000;        /* 10 seconds */
00675         (*cli)->fd = sockfd;
00676         fstrcpy((*cli)->desthost, controller);
00677         (*cli)->use_kerberos = True;
00678 
00679         peeraddr_len = sizeof(peeraddr);
00680 
00681         if ((getpeername((*cli)->fd, &peeraddr, &peeraddr_len) != 0) ||
00682             (peeraddr_len != sizeof(struct sockaddr_in)) ||
00683             (peeraddr_in->sin_family != PF_INET))
00684         {
00685                 DEBUG(0,("cm_prepare_connection: %s\n", strerror(errno)));
00686                 result = NT_STATUS_UNSUCCESSFUL;
00687                 goto done;
00688         }
00689 
00690         if (ntohs(peeraddr_in->sin_port) == 139) {
00691                 struct nmb_name calling;
00692                 struct nmb_name called;
00693 
00694                 make_nmb_name(&calling, global_myname(), 0x0);
00695                 make_nmb_name(&called, "*SMBSERVER", 0x20);
00696 
00697                 if (!cli_session_request(*cli, &calling, &called)) {
00698                         DEBUG(8, ("cli_session_request failed for %s\n",
00699                                   controller));
00700                         result = NT_STATUS_UNSUCCESSFUL;
00701                         goto done;
00702                 }
00703         }
00704 
00705         cli_setup_signing_state(*cli, Undefined);
00706 
00707         if (!cli_negprot(*cli)) {
00708                 DEBUG(1, ("cli_negprot failed\n"));
00709                 result = NT_STATUS_UNSUCCESSFUL;
00710                 goto done;
00711         }
00712 
00713         if (!is_trusted_domain_situation(domain->name) &&
00714             (*cli)->protocol >= PROTOCOL_NT1 &&
00715             (*cli)->capabilities & CAP_EXTENDED_SECURITY)
00716         {
00717                 ADS_STATUS ads_status;
00718 
00719                 result = get_trust_creds(domain, &machine_password,
00720                                          &machine_account,
00721                                          &machine_krb5_principal);
00722                 if (!NT_STATUS_IS_OK(result)) {
00723                         goto anon_fallback;
00724                 }
00725 
00726                 if (lp_security() == SEC_ADS) {
00727 
00728                         /* Try a krb5 session */
00729 
00730                         (*cli)->use_kerberos = True;
00731                         DEBUG(5, ("connecting to %s from %s with kerberos principal "
00732                                   "[%s] and realm [%s]\n", controller, global_myname(),
00733                                   machine_krb5_principal, domain->alt_name));
00734 
00735                         ads_status = cli_session_setup_spnego(*cli,
00736                                                               machine_krb5_principal, 
00737                                                               machine_password, 
00738                                                               lp_workgroup(),
00739                                                               domain->alt_name);
00740 
00741                         if (!ADS_ERR_OK(ads_status)) {
00742                                 DEBUG(4,("failed kerberos session setup with %s\n",
00743                                          ads_errstr(ads_status)));
00744                         }
00745 
00746                         result = ads_ntstatus(ads_status);
00747                         if (NT_STATUS_IS_OK(result)) {
00748                                 /* Ensure creds are stored for NTLMSSP authenticated pipe access. */
00749                                 cli_init_creds(*cli, machine_account, domain->name, machine_password);
00750                                 goto session_setup_done;
00751                         }
00752                 }
00753 
00754                 /* Fall back to non-kerberos session setup using NTLMSSP SPNEGO with the machine account. */
00755                 (*cli)->use_kerberos = False;
00756 
00757                 DEBUG(5, ("connecting to %s from %s with username "
00758                           "[%s]\\[%s]\n",  controller, global_myname(),
00759                           lp_workgroup(), machine_account));
00760 
00761                 ads_status = cli_session_setup_spnego(*cli,
00762                                                       machine_account, 
00763                                                       machine_password, 
00764                                                       lp_workgroup(),
00765                                                       NULL);
00766                 if (!ADS_ERR_OK(ads_status)) {
00767                         DEBUG(4, ("authenticated session setup failed with %s\n",
00768                                 ads_errstr(ads_status)));
00769                 }
00770 
00771                 result = ads_ntstatus(ads_status);
00772                 if (NT_STATUS_IS_OK(result)) {
00773                         /* Ensure creds are stored for NTLMSSP authenticated pipe access. */
00774                         cli_init_creds(*cli, machine_account, domain->name, machine_password);
00775                         goto session_setup_done;
00776                 }
00777         }
00778 
00779         /* Fall back to non-kerberos session setup with auth_user */
00780 
00781         (*cli)->use_kerberos = False;
00782 
00783         cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
00784 
00785         if ((((*cli)->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) != 0) &&
00786             (strlen(ipc_username) > 0)) {
00787 
00788                 /* Only try authenticated if we have a username */
00789 
00790                 DEBUG(5, ("connecting to %s from %s with username "
00791                           "[%s]\\[%s]\n",  controller, global_myname(),
00792                           ipc_domain, ipc_username));
00793 
00794                 if (NT_STATUS_IS_OK(cli_session_setup(
00795                                             *cli, ipc_username,
00796                                             ipc_password, strlen(ipc_password)+1,
00797                                             ipc_password, strlen(ipc_password)+1,
00798                                             ipc_domain))) {
00799                         /* Successful logon with given username. */
00800                         cli_init_creds(*cli, ipc_username, ipc_domain, ipc_password);
00801                         goto session_setup_done;
00802                 } else {
00803                         DEBUG(4, ("authenticated session setup with user %s\\%s failed.\n",
00804                                 ipc_domain, ipc_username ));
00805                 }
00806         }
00807 
00808  anon_fallback:
00809 
00810         /* Fall back to anonymous connection, this might fail later */
00811 
00812         if (NT_STATUS_IS_OK(cli_session_setup(*cli, "", NULL, 0,
00813                                               NULL, 0, ""))) {
00814                 DEBUG(5, ("Connected anonymously\n"));
00815                 cli_init_creds(*cli, "", "", "");
00816                 goto session_setup_done;
00817         }
00818 
00819         result = cli_nt_error(*cli);
00820 
00821         if (NT_STATUS_IS_OK(result))
00822                 result = NT_STATUS_UNSUCCESSFUL;
00823 
00824         /* We can't session setup */
00825 
00826         goto done;
00827 
00828  session_setup_done:
00829 
00830         /* cache the server name for later connections */
00831 
00832         saf_store( domain->name, (*cli)->desthost );
00833         if (domain->alt_name && (*cli)->use_kerberos) {
00834                 saf_store( domain->alt_name, (*cli)->desthost );
00835         }
00836 
00837         if (!cli_send_tconX(*cli, "IPC$", "IPC", "", 0)) {
00838 
00839                 result = cli_nt_error(*cli);
00840 
00841                 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
00842 
00843                 if (NT_STATUS_IS_OK(result))
00844                         result = NT_STATUS_UNSUCCESSFUL;
00845 
00846                 goto done;
00847         }
00848 
00849         secrets_named_mutex_release(controller);
00850         got_mutex = False;
00851         *retry = False;
00852 
00853         /* set the domain if empty; needed for schannel connections */
00854         if ( !*(*cli)->domain ) {
00855                 fstrcpy( (*cli)->domain, domain->name );
00856         }
00857 
00858         result = NT_STATUS_OK;
00859 
00860  done:
00861         if (got_mutex) {
00862                 secrets_named_mutex_release(controller);
00863         }
00864 
00865         SAFE_FREE(machine_account);
00866         SAFE_FREE(machine_password);
00867         SAFE_FREE(machine_krb5_principal);
00868         SAFE_FREE(ipc_username);
00869         SAFE_FREE(ipc_domain);
00870         SAFE_FREE(ipc_password);
00871 
00872         if (!NT_STATUS_IS_OK(result)) {
00873                 winbind_add_failed_connection_entry(domain, controller, result);
00874                 if ((*cli) != NULL) {
00875                         cli_shutdown(*cli);
00876                         *cli = NULL;
00877                 }
00878         }
00879 
00880         return result;
00881 }
00882 
00883 static BOOL add_one_dc_unique(TALLOC_CTX *mem_ctx, const char *domain_name,
00884                               const char *dcname, struct in_addr ip,
00885                               struct dc_name_ip **dcs, int *num)
00886 {
00887         if (!NT_STATUS_IS_OK(check_negative_conn_cache(domain_name, dcname))) {
00888                 DEBUG(10, ("DC %s was in the negative conn cache\n", dcname));
00889                 return False;
00890         }
00891 
00892         *dcs = TALLOC_REALLOC_ARRAY(mem_ctx, *dcs, struct dc_name_ip, (*num)+1);
00893 
00894         if (*dcs == NULL)
00895                 return False;
00896 
00897         fstrcpy((*dcs)[*num].name, dcname);
00898         (*dcs)[*num].ip = ip;
00899         *num += 1;
00900         return True;
00901 }
00902 
00903 static BOOL add_sockaddr_to_array(TALLOC_CTX *mem_ctx,
00904                                   struct in_addr ip, uint16 port,
00905                                   struct sockaddr_in **addrs, int *num)
00906 {
00907         *addrs = TALLOC_REALLOC_ARRAY(mem_ctx, *addrs, struct sockaddr_in, (*num)+1);
00908 
00909         if (*addrs == NULL) {
00910                 *num = 0;
00911                 return False;
00912         }
00913 
00914         (*addrs)[*num].sin_family = PF_INET;
00915         putip((char *)&((*addrs)[*num].sin_addr), (char *)&ip);
00916         (*addrs)[*num].sin_port = htons(port);
00917 
00918         *num += 1;
00919         return True;
00920 }
00921 
00922 static void mailslot_name(struct in_addr dc_ip, fstring name)
00923 {
00924         fstr_sprintf(name, "\\MAILSLOT\\NET\\GETDC%X", dc_ip.s_addr);
00925 }
00926 
00927 static BOOL send_getdc_request(struct in_addr dc_ip,
00928                                const char *domain_name,
00929                                const DOM_SID *sid)
00930 {
00931         pstring outbuf;
00932         char *p;
00933         fstring my_acct_name;
00934         fstring my_mailslot;
00935 
00936         mailslot_name(dc_ip, my_mailslot);
00937 
00938         memset(outbuf, '\0', sizeof(outbuf));
00939 
00940         p = outbuf;
00941 
00942         SCVAL(p, 0, SAMLOGON);
00943         p++;
00944 
00945         SCVAL(p, 0, 0); /* Count pointer ... */
00946         p++;
00947 
00948         SIVAL(p, 0, 0); /* The sender's token ... */
00949         p += 2;
00950 
00951         p += dos_PutUniCode(p, global_myname(),
00952                 sizeof(outbuf) - PTR_DIFF(p, outbuf), True);
00953         fstr_sprintf(my_acct_name, "%s$", global_myname());
00954         p += dos_PutUniCode(p, my_acct_name,
00955                         sizeof(outbuf) - PTR_DIFF(p, outbuf), True);
00956 
00957         if (strlen(my_mailslot)+1 > sizeof(outbuf) - PTR_DIFF(p, outbuf)) {
00958                 return False;
00959         }
00960 
00961         memcpy(p, my_mailslot, strlen(my_mailslot)+1);
00962         p += strlen(my_mailslot)+1;
00963 
00964         if (sizeof(outbuf) - PTR_DIFF(p, outbuf) < 8) {
00965                 return False;
00966         }
00967         SIVAL(p, 0, 0x80);
00968         p+=4;
00969 
00970         SIVAL(p, 0, sid_size(sid));
00971         p+=4;
00972 
00973         p = ALIGN4(p, outbuf);
00974 
00975         if (PTR_DIFF(p, outbuf) > sizeof(outbuf)) {
00976                 return False;
00977         }
00978 
00979         if (sid_size(sid) + 8 > sizeof(outbuf) - PTR_DIFF(p, outbuf)) {
00980                 return False;
00981         }
00982 
00983         sid_linearize(p, sizeof(outbuf) - PTR_DIFF(p, outbuf), sid);
00984         p += sid_size(sid);
00985 
00986         SIVAL(p, 0, 1);
00987         SSVAL(p, 4, 0xffff);
00988         SSVAL(p, 6, 0xffff);
00989         p+=8;
00990 
00991         return cli_send_mailslot(False, "\\MAILSLOT\\NET\\NTLOGON", 0,
00992                                  outbuf, PTR_DIFF(p, outbuf),
00993                                  global_myname(), 0, domain_name, 0x1c,
00994                                  dc_ip);
00995 }
00996 
00997 static BOOL receive_getdc_response(struct in_addr dc_ip,
00998                                    const char *domain_name,
00999                                    fstring dc_name)
01000 {
01001         struct packet_struct *packet;
01002         fstring my_mailslot;
01003         char *buf, *p;
01004         fstring dcname, user, domain;
01005         int len;
01006 
01007         mailslot_name(dc_ip, my_mailslot);
01008 
01009         packet = receive_unexpected(DGRAM_PACKET, 0, my_mailslot);
01010 
01011         if (packet == NULL) {
01012                 DEBUG(5, ("Did not receive packet for %s\n", my_mailslot));
01013                 return False;
01014         }
01015 
01016         DEBUG(5, ("Received packet for %s\n", my_mailslot));
01017 
01018         buf = packet->packet.dgram.data;
01019         len = packet->packet.dgram.datasize;
01020 
01021         if (len < 70) {
01022                 /* 70 is a completely arbitrary value to make sure
01023                    the SVAL below does not read uninitialized memory */
01024                 DEBUG(3, ("GetDC got short response\n"));
01025                 return False;
01026         }
01027 
01028         /* This should be (buf-4)+SVAL(buf-4, smb_vwv12)... */
01029         p = buf+SVAL(buf, smb_vwv10);
01030 
01031         if (CVAL(p,0) != SAMLOGON_R) {
01032                 DEBUG(8, ("GetDC got invalid response type %d\n", CVAL(p, 0)));
01033                 return False;
01034         }
01035 
01036         p+=2;
01037         pull_ucs2(buf, dcname, p, sizeof(dcname), PTR_DIFF(buf+len, p),
01038                   STR_TERMINATE|STR_NOALIGN);
01039         p = skip_unibuf(p, PTR_DIFF(buf+len, p));
01040         pull_ucs2(buf, user, p, sizeof(dcname), PTR_DIFF(buf+len, p),
01041                   STR_TERMINATE|STR_NOALIGN);
01042         p = skip_unibuf(p, PTR_DIFF(buf+len, p));
01043         pull_ucs2(buf, domain, p, sizeof(dcname), PTR_DIFF(buf+len, p),
01044                   STR_TERMINATE|STR_NOALIGN);
01045         p = skip_unibuf(p, PTR_DIFF(buf+len, p));
01046 
01047         if (!strequal(domain, domain_name)) {
01048                 DEBUG(3, ("GetDC: Expected domain %s, got %s\n",
01049                           domain_name, domain));
01050                 return False;
01051         }
01052 
01053         p = dcname;
01054         if (*p == '\\') p += 1;
01055         if (*p == '\\') p += 1;
01056 
01057         fstrcpy(dc_name, p);
01058 
01059         DEBUG(10, ("GetDC gave name %s for domain %s\n",
01060                    dc_name, domain));
01061 
01062         return True;
01063 }
01064 
01065 /*******************************************************************
01066  convert an ip to a name
01067 *******************************************************************/
01068 
01069 static BOOL dcip_to_name(const struct winbindd_domain *domain, struct in_addr ip, fstring name )
01070 {
01071         struct ip_service ip_list;
01072 
01073         ip_list.ip = ip;
01074         ip_list.port = 0;
01075 
01076 #ifdef WITH_ADS
01077         /* For active directory servers, try to get the ldap server name.
01078            None of these failures should be considered critical for now */
01079 
01080         if (lp_security() == SEC_ADS) {
01081                 ADS_STRUCT *ads;
01082 
01083                 ads = ads_init(domain->alt_name, domain->name, NULL);
01084                 ads->auth.flags |= ADS_AUTH_NO_BIND;
01085 
01086                 if (ads_try_connect( ads, inet_ntoa(ip) ) )  {
01087                         /* We got a cldap packet. */
01088                         fstrcpy(name, ads->config.ldap_server_name);
01089                         namecache_store(name, 0x20, 1, &ip_list);
01090 
01091                         DEBUG(10,("dcip_to_name: flags = 0x%x\n", (unsigned int)ads->config.flags));
01092 
01093                         if (domain->primary && (ads->config.flags & ADS_KDC)) {
01094                                 if (ads_closest_dc(ads)) {
01095                                         char *sitename = sitename_fetch(ads->config.realm);
01096 
01097                                         /* We're going to use this KDC for this realm/domain.
01098                                            If we are using sites, then force the krb5 libs
01099                                            to use this KDC. */
01100 
01101                                         create_local_private_krb5_conf_for_domain(domain->alt_name,
01102                                                                         domain->name,
01103                                                                         sitename,
01104                                                                         ip);
01105 
01106                                         SAFE_FREE(sitename);
01107                                 } else {
01108                                         /* use an off site KDC */
01109                                         create_local_private_krb5_conf_for_domain(domain->alt_name,
01110                                                                         domain->name,
01111                                                                         NULL,
01112                                                                         ip);
01113                                 }
01114                                 /* Ensure we contact this DC also. */
01115                                 saf_store( domain->name, name);
01116                                 saf_store( domain->alt_name, name);
01117                         }
01118 
01119                         ads_destroy( &ads );
01120                         return True;
01121                 }
01122 
01123                 ads_destroy( &ads );
01124         }
01125 #endif
01126 
01127         /* try GETDC requests next */
01128         
01129         if (send_getdc_request(ip, domain->name, &domain->sid)) {
01130                 int i;
01131                 smb_msleep(100);
01132                 for (i=0; i<5; i++) {
01133                         if (receive_getdc_response(ip, domain->name, name)) {
01134                                 namecache_store(name, 0x20, 1, &ip_list);
01135                                 return True;
01136                         }
01137                         smb_msleep(500);
01138                 }
01139         }
01140 
01141         /* try node status request */
01142 
01143         if ( name_status_find(domain->name, 0x1c, 0x20, ip, name) ) {
01144                 namecache_store(name, 0x20, 1, &ip_list);
01145                 return True;
01146         }
01147         return False;
01148 }
01149 
01150 /*******************************************************************
01151  Retreive a list of IP address for domain controllers.  Fill in 
01152  the dcs[]  with results.
01153 *******************************************************************/
01154 
01155 static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain,
01156                     struct dc_name_ip **dcs, int *num_dcs)
01157 {
01158         fstring dcname;
01159         struct  in_addr ip;
01160         struct  ip_service *ip_list = NULL;
01161         int     iplist_size = 0;
01162         int     i;
01163         BOOL    is_our_domain;
01164         enum security_types sec = (enum security_types)lp_security();
01165 
01166         is_our_domain = strequal(domain->name, lp_workgroup());
01167 
01168         if ( !is_our_domain 
01169                 && get_dc_name_via_netlogon(domain, dcname, &ip) 
01170                 && add_one_dc_unique(mem_ctx, domain->name, dcname, ip, dcs, num_dcs) )
01171         {
01172                 DEBUG(10, ("Retrieved DC %s at %s via netlogon\n",
01173                            dcname, inet_ntoa(ip)));
01174                 return True;
01175         }
01176 
01177         if (sec == SEC_ADS) {
01178                 char *sitename = NULL;
01179 
01180                 /* We need to make sure we know the local site before
01181                    doing any DNS queries, as this will restrict the
01182                    get_sorted_dc_list() call below to only fetching
01183                    DNS records for the correct site. */
01184 
01185                 /* Find any DC to get the site record.
01186                    We deliberately don't care about the
01187                    return here. */
01188 
01189                 get_dc_name(domain->name, domain->alt_name, dcname, &ip);
01190 
01191                 sitename = sitename_fetch(domain->alt_name);
01192                 if (sitename) {
01193 
01194                         /* Do the site-specific AD dns lookup first. */
01195                         get_sorted_dc_list(domain->alt_name, sitename, &ip_list, &iplist_size, True);
01196 
01197                         for ( i=0; i<iplist_size; i++ ) {
01198                                 add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip_list[i].ip),
01199                                                         ip_list[i].ip, dcs, num_dcs);
01200                         }
01201 
01202                         SAFE_FREE(ip_list);
01203                         SAFE_FREE(sitename);
01204                         iplist_size = 0;
01205                 }
01206 
01207                 /* Now we add DCs from the main AD dns lookup. */
01208                 get_sorted_dc_list(domain->alt_name, NULL, &ip_list, &iplist_size, True);
01209 
01210                 for ( i=0; i<iplist_size; i++ ) {
01211                         add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip_list[i].ip),
01212                                                 ip_list[i].ip, dcs, num_dcs);
01213                 }
01214         }
01215 
01216         /* try standard netbios queries if no ADS */
01217 
01218         if (iplist_size==0) {
01219                 get_sorted_dc_list(domain->name, NULL, &ip_list, &iplist_size, False);
01220         }
01221 
01222         /* FIXME!! this is where we should re-insert the GETDC requests --jerry */
01223 
01224         /* now add to the dc array.  We'll wait until the last minute 
01225            to look up the name of the DC.  But we fill in the char* for 
01226            the ip now in to make the failed connection cache work */
01227 
01228         for ( i=0; i<iplist_size; i++ ) {
01229                 add_one_dc_unique(mem_ctx, domain->name, inet_ntoa(ip_list[i].ip), 
01230                         ip_list[i].ip, dcs, num_dcs);
01231         }
01232 
01233         SAFE_FREE( ip_list );
01234 
01235         return True;
01236 }
01237 
01238 static BOOL find_new_dc(TALLOC_CTX *mem_ctx,
01239                         const struct winbindd_domain *domain,
01240                         fstring dcname, struct sockaddr_in *addr, int *fd)
01241 {
01242         struct dc_name_ip *dcs = NULL;
01243         int num_dcs = 0;
01244 
01245         const char **dcnames = NULL;
01246         int num_dcnames = 0;
01247 
01248         struct sockaddr_in *addrs = NULL;
01249         int num_addrs = 0;
01250 
01251         int i, fd_index;
01252 
01253         *fd = -1;
01254 
01255  again:
01256         if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs) || (num_dcs == 0))
01257                 return False;
01258 
01259         for (i=0; i<num_dcs; i++) {
01260 
01261                 if (!add_string_to_array(mem_ctx, dcs[i].name,
01262                                     &dcnames, &num_dcnames)) {
01263                         return False;
01264                 }
01265                 if (!add_sockaddr_to_array(mem_ctx, dcs[i].ip, 445,
01266                                       &addrs, &num_addrs)) {
01267                         return False;
01268                 }
01269 
01270                 if (!add_string_to_array(mem_ctx, dcs[i].name,
01271                                     &dcnames, &num_dcnames)) {
01272                         return False;
01273                 }
01274                 if (!add_sockaddr_to_array(mem_ctx, dcs[i].ip, 139,
01275                                       &addrs, &num_addrs)) {
01276                         return False;
01277                 }
01278         }
01279 
01280         if ((num_dcnames == 0) || (num_dcnames != num_addrs))
01281                 return False;
01282 
01283         if ((addrs == NULL) || (dcnames == NULL))
01284                 return False;
01285 
01286         /* 5 second timeout. */
01287         if ( !open_any_socket_out(addrs, num_addrs, 5000, &fd_index, fd) ) 
01288         {
01289                 for (i=0; i<num_dcs; i++) {
01290                         DEBUG(10, ("find_new_dc: open_any_socket_out failed for "
01291                                 "domain %s address %s. Error was %s\n",
01292                                 domain->name, inet_ntoa(dcs[i].ip), strerror(errno) ));
01293                         winbind_add_failed_connection_entry(domain,
01294                                 dcs[i].name, NT_STATUS_UNSUCCESSFUL);
01295                 }
01296                 return False;
01297         }
01298 
01299         *addr = addrs[fd_index];
01300 
01301         if (*dcnames[fd_index] != '\0' && !is_ipaddress(dcnames[fd_index])) {
01302                 /* Ok, we've got a name for the DC */
01303                 fstrcpy(dcname, dcnames[fd_index]);
01304                 return True;
01305         }
01306 
01307         /* Try to figure out the name */
01308         if (dcip_to_name( domain, addr->sin_addr, dcname )) {
01309                 return True;
01310         }
01311 
01312         /* We can not continue without the DC's name */
01313         winbind_add_failed_connection_entry(domain, dcs[fd_index].name,
01314                                     NT_STATUS_UNSUCCESSFUL);
01315 
01316         /* Throw away all arrays as we're doing this again. */
01317         TALLOC_FREE(dcs);
01318         num_dcs = 0;
01319 
01320         TALLOC_FREE(dcnames);
01321         num_dcnames = 0;
01322 
01323         TALLOC_FREE(addrs);
01324         num_addrs = 0;
01325 
01326         *fd = -1;
01327 
01328         goto again;
01329 }
01330 
01331 static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
01332                                    struct winbindd_cm_conn *new_conn)
01333 {
01334         TALLOC_CTX *mem_ctx;
01335         NTSTATUS result;
01336         char *saf_servername = saf_fetch( domain->name );
01337         int retries;
01338 
01339         if ((mem_ctx = talloc_init("cm_open_connection")) == NULL) {
01340                 SAFE_FREE(saf_servername);
01341                 set_domain_offline(domain);
01342                 return NT_STATUS_NO_MEMORY;
01343         }
01344 
01345         /* we have to check the server affinity cache here since 
01346            later we selecte a DC based on response time and not preference */
01347            
01348         /* Check the negative connection cache
01349            before talking to it. It going down may have
01350            triggered the reconnection. */
01351 
01352         if ( saf_servername && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, saf_servername))) {
01353 
01354                 DEBUG(10,("cm_open_connection: saf_servername is '%s' for domain %s\n",
01355                         saf_servername, domain->name ));
01356 
01357                 /* convert an ip address to a name */
01358                 if ( is_ipaddress( saf_servername ) ) {
01359                         fstring saf_name;
01360                         struct in_addr ip;
01361 
01362                         ip = *interpret_addr2( saf_servername );
01363                         if (dcip_to_name( domain, ip, saf_name )) {
01364                                 fstrcpy( domain->dcname, saf_name );
01365                         } else {
01366                                 winbind_add_failed_connection_entry(
01367                                         domain, saf_servername,
01368                                         NT_STATUS_UNSUCCESSFUL);
01369                         }
01370                 } else {
01371                         fstrcpy( domain->dcname, saf_servername );
01372                 }
01373 
01374                 SAFE_FREE( saf_servername );
01375         }
01376 
01377         for (retries = 0; retries < 3; retries++) {
01378 
01379                 int fd = -1;
01380                 BOOL retry = False;
01381 
01382                 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
01383 
01384                 DEBUG(10,("cm_open_connection: dcname is '%s' for domain %s\n",
01385                         domain->dcname, domain->name ));
01386 
01387                 if (*domain->dcname 
01388                         && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, domain->dcname))
01389                         && (resolve_name(domain->dcname, &domain->dcaddr.sin_addr, 0x20)))
01390                 {
01391                         struct sockaddr_in *addrs = NULL;
01392                         int num_addrs = 0;
01393                         int dummy = 0;
01394 
01395                         if (!add_sockaddr_to_array(mem_ctx, domain->dcaddr.sin_addr, 445, &addrs, &num_addrs)) {
01396                                 set_domain_offline(domain);
01397                                 talloc_destroy(mem_ctx);
01398                                 return NT_STATUS_NO_MEMORY;
01399                         }
01400                         if (!add_sockaddr_to_array(mem_ctx, domain->dcaddr.sin_addr, 139, &addrs, &num_addrs)) {
01401                                 set_domain_offline(domain);
01402                                 talloc_destroy(mem_ctx);
01403                                 return NT_STATUS_NO_MEMORY;
01404                         }
01405 
01406                         /* 5 second timeout. */
01407                         if (!open_any_socket_out(addrs, num_addrs, 5000, &dummy, &fd)) {
01408                                 fd = -1;
01409                         }
01410                 }
01411 
01412                 if ((fd == -1) 
01413                         && !find_new_dc(mem_ctx, domain, domain->dcname, &domain->dcaddr, &fd))
01414                 {
01415                         /* This is the one place where we will
01416                            set the global winbindd offline state
01417                            to true, if a "WINBINDD_OFFLINE" entry
01418                            is found in the winbindd cache. */
01419                         set_global_winbindd_state_offline();
01420                         break;
01421                 }
01422 
01423                 new_conn->cli = NULL;
01424 
01425                 result = cm_prepare_connection(domain, fd, domain->dcname,
01426                         &new_conn->cli, &retry);
01427 
01428                 if (!retry)
01429                         break;
01430         }
01431 
01432         if (NT_STATUS_IS_OK(result)) {
01433                 if (domain->online == False) {
01434                         /* We're changing state from offline to online. */
01435                         set_global_winbindd_state_online();
01436                 }
01437                 set_domain_online(domain);
01438         } else {
01439                 /* Ensure we setup the retry handler. */
01440                 set_domain_offline(domain);
01441         }
01442 
01443         talloc_destroy(mem_ctx);
01444         return result;
01445 }
01446 
01447 /* Close down all open pipes on a connection. */
01448 
01449 void invalidate_cm_connection(struct winbindd_cm_conn *conn)
01450 {
01451         /* We're closing down a possibly dead
01452            connection. Don't have impossibly long (10s) timeouts. */
01453 
01454         if (conn->cli) {
01455                 cli_set_timeout(conn->cli, 1000); /* 1 second. */
01456         }
01457 
01458         if (conn->samr_pipe != NULL) {
01459                 if (!cli_rpc_pipe_close(conn->samr_pipe)) {
01460                         /* Ok, it must be dead. Drop timeout to 0.5 sec. */
01461                         if (conn->cli) {
01462                                 cli_set_timeout(conn->cli, 500);
01463                         }
01464                 }
01465                 conn->samr_pipe = NULL;
01466         }
01467 
01468         if (conn->lsa_pipe != NULL) {
01469                 if (!cli_rpc_pipe_close(conn->lsa_pipe)) {
01470                         /* Ok, it must be dead. Drop timeout to 0.5 sec. */
01471                         if (conn->cli) {
01472                                 cli_set_timeout(conn->cli, 500);
01473                         }
01474                 }
01475                 conn->lsa_pipe = NULL;
01476         }
01477 
01478         if (conn->netlogon_pipe != NULL) {
01479                 if (!cli_rpc_pipe_close(conn->netlogon_pipe)) {
01480                         /* Ok, it must be dead. Drop timeout to 0.5 sec. */
01481                         if (conn->cli) {
01482                                 cli_set_timeout(conn->cli, 500);
01483                         }
01484                 }
01485                 conn->netlogon_pipe = NULL;
01486         }
01487 
01488         if (conn->cli) {
01489                 cli_shutdown(conn->cli);
01490         }
01491 
01492         conn->cli = NULL;
01493 }
01494 
01495 void close_conns_after_fork(void)
01496 {
01497         struct winbindd_domain *domain;
01498 
01499         for (domain = domain_list(); domain; domain = domain->next) {
01500                 if (domain->conn.cli == NULL)
01501                         continue;
01502 
01503                 if (domain->conn.cli->fd == -1)
01504                         continue;
01505 
01506                 close(domain->conn.cli->fd);
01507                 domain->conn.cli->fd = -1;
01508         }
01509 }
01510 
01511 static BOOL connection_ok(struct winbindd_domain *domain)
01512 {
01513         if (domain->conn.cli == NULL) {
01514                 DEBUG(8, ("connection_ok: Connection to %s for domain %s has NULL "
01515                           "cli!\n", domain->dcname, domain->name));
01516                 return False;
01517         }
01518 
01519         if (!domain->conn.cli->initialised) {
01520                 DEBUG(3, ("connection_ok: Connection to %s for domain %s was never "
01521                           "initialised!\n", domain->dcname, domain->name));
01522                 return False;
01523         }
01524 
01525         if (domain->conn.cli->fd == -1) {
01526                 DEBUG(3, ("connection_ok: Connection to %s for domain %s has died or was "
01527                           "never started (fd == -1)\n", 
01528                           domain->dcname, domain->name));
01529                 return False;
01530         }
01531 
01532         if (domain->online == False) {
01533                 DEBUG(3, ("connection_ok: Domain %s is offline\n", domain->name));
01534                 return False;
01535         }
01536 
01537         return True;
01538 }
01539 
01540 /* Initialize a new connection up to the RPC BIND.
01541    Bypass online status check so always does network calls. */
01542 
01543 static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain)
01544 {
01545         NTSTATUS result;
01546 
01547         /* Internal connections never use the network. */
01548         if (domain->internal) {
01549                 domain->initialized = True;
01550                 return NT_STATUS_OK;
01551         }
01552 
01553         if (connection_ok(domain)) {
01554                 if (!domain->initialized) {
01555                         set_dc_type_and_flags(domain);
01556                 }
01557                 return NT_STATUS_OK;
01558         }
01559 
01560         invalidate_cm_connection(&domain->conn);
01561 
01562         result = cm_open_connection(domain, &domain->conn);
01563 
01564         if (NT_STATUS_IS_OK(result) && !domain->initialized) {
01565                 set_dc_type_and_flags(domain);
01566         }
01567 
01568         return result;
01569 }
01570 
01571 NTSTATUS init_dc_connection(struct winbindd_domain *domain)
01572 {
01573         if (domain->initialized && !domain->online) {
01574                 /* We check for online status elsewhere. */
01575                 return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
01576         }
01577 
01578         return init_dc_connection_network(domain);
01579 }
01580 
01581 /******************************************************************************
01582  We can 'sense' certain things about the DC by it's replies to certain
01583  questions.
01584 
01585  This tells us if this particular remote server is Active Directory, and if it
01586  is native mode.
01587 ******************************************************************************/
01588 
01589 static void set_dc_type_and_flags( struct winbindd_domain *domain )
01590 {
01591         NTSTATUS                result;
01592         DS_DOMINFO_CTR          ctr;
01593         TALLOC_CTX              *mem_ctx = NULL;
01594         struct rpc_pipe_client  *cli;
01595         POLICY_HND pol;
01596 
01597         char *domain_name = NULL;
01598         char *dns_name = NULL;
01599         char *forest_name = NULL;       
01600         DOM_SID *dom_sid = NULL;        
01601 
01602         ZERO_STRUCT( ctr );
01603         
01604         if (!connection_ok(domain)) {
01605                 return;
01606         }
01607 
01608         DEBUG(5, ("set_dc_type_and_flags: domain %s\n", domain->name ));
01609 
01610         cli = cli_rpc_pipe_open_noauth(domain->conn.cli, PI_LSARPC_DS,
01611                                        &result);
01612 
01613         if (cli == NULL) {
01614                 DEBUG(5, ("set_dc_type_and_flags: Could not bind to "
01615                           "PI_LSARPC_DS on domain %s: (%s)\n",
01616                           domain->name, nt_errstr(result)));
01617 
01618                 /* if this is just a non-AD domain we need to continue
01619                  * identifying so that we can in the end return with
01620                  * domain->initialized = True - gd */
01621 
01622                 goto no_lsarpc_ds;
01623         }
01624 
01625         result = rpccli_ds_getprimarydominfo(cli, cli->cli->mem_ctx,
01626                                              DsRolePrimaryDomainInfoBasic,
01627                                              &ctr);
01628         cli_rpc_pipe_close(cli);
01629 
01630         if (!NT_STATUS_IS_OK(result)) {
01631                 DEBUG(5, ("set_dc_type_and_flags: rpccli_ds_getprimarydominfo "
01632                           "on domain %s failed: (%s)\n",
01633                           domain->name, nt_errstr(result)));
01634 
01635                 /* older samba3 DCs will return DCERPC_FAULT_OP_RNG_ERROR for
01636                  * every opcode on the LSARPC_DS pipe, continue with
01637                  * no_lsarpc_ds mode here as well to get domain->initialized
01638                  * set - gd */
01639 
01640                 if (NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR) {
01641                         goto no_lsarpc_ds;
01642                 }
01643 
01644                 return;
01645         }
01646         
01647         if ((ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING) &&
01648             !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE)) {
01649                 domain->native_mode = True;
01650         } else {
01651                 domain->native_mode = False;
01652         }
01653 
01654 no_lsarpc_ds:
01655         cli = cli_rpc_pipe_open_noauth(domain->conn.cli, PI_LSARPC, &result);
01656 
01657         if (cli == NULL) {
01658                 DEBUG(5, ("set_dc_type_and_flags: Could not bind to "
01659                           "PI_LSARPC on domain %s: (%s)\n",
01660                           domain->name, nt_errstr(result)));
01661                 cli_rpc_pipe_close(cli);
01662                 return;
01663         }
01664 
01665         mem_ctx = talloc_init("set_dc_type_and_flags on domain %s\n",
01666                               domain->name);
01667         if (!mem_ctx) {
01668                 DEBUG(1, ("set_dc_type_and_flags: talloc_init() failed\n"));
01669                 cli_rpc_pipe_close(cli);
01670                 return;
01671         }
01672 
01673         result = rpccli_lsa_open_policy2(cli, mem_ctx, True, 
01674                                          SEC_RIGHTS_MAXIMUM_ALLOWED, &pol);
01675                 
01676         if (NT_STATUS_IS_OK(result)) {
01677                 /* This particular query is exactly what Win2k clients use 
01678                    to determine that the DC is active directory */
01679                 result = rpccli_lsa_query_info_policy2(cli, mem_ctx, &pol,
01680                                                        12, &domain_name,
01681                                                        &dns_name, &forest_name,
01682                                                        NULL, &dom_sid);
01683         }
01684 
01685         if (NT_STATUS_IS_OK(result)) {
01686                 domain->active_directory = True;
01687 
01688                 if (domain_name)
01689                         fstrcpy(domain->name, domain_name);
01690 
01691                 if (dns_name)
01692                         fstrcpy(domain->alt_name, dns_name);
01693 
01694                 if ( forest_name )
01695                         fstrcpy(domain->forest_name, forest_name);              
01696 
01697                 if (dom_sid) 
01698                         sid_copy(&domain->sid, dom_sid);
01699         } else {
01700                 domain->active_directory = False;
01701 
01702                 result = rpccli_lsa_open_policy(cli, mem_ctx, True, 
01703                                                 SEC_RIGHTS_MAXIMUM_ALLOWED,
01704                                                 &pol);
01705                         
01706                 if (!NT_STATUS_IS_OK(result))
01707                         goto done;
01708                         
01709                 result = rpccli_lsa_query_info_policy(cli, mem_ctx, 
01710                                                       &pol, 5, &domain_name, 
01711                                                       &dom_sid);
01712                         
01713                 if (NT_STATUS_IS_OK(result)) {
01714                         if (domain_name)
01715                                 fstrcpy(domain->name, domain_name);
01716 
01717                         if (dom_sid) 
01718                                 sid_copy(&domain->sid, dom_sid);
01719                 }
01720         }
01721 done:
01722 
01723         DEBUG(5, ("set_dc_type_and_flags: domain %s is %sin native mode.\n",
01724                   domain->name, domain->native_mode ? "" : "NOT "));
01725 
01726         DEBUG(5,("set_dc_type_and_flags: domain %s is %srunning active directory.\n",
01727                   domain->name, domain->active_directory ? "" : "NOT "));
01728 
01729         cli_rpc_pipe_close(cli);
01730         
01731         talloc_destroy(mem_ctx);
01732 
01733         domain->initialized = True;
01734 }
01735 
01736 static BOOL cm_get_schannel_dcinfo(struct winbindd_domain *domain,
01737                                    struct dcinfo **ppdc)
01738 {
01739         NTSTATUS result;
01740         struct rpc_pipe_client *netlogon_pipe;
01741 
01742         if (lp_client_schannel() == False) {
01743                 return False;
01744         }
01745 
01746         result = cm_connect_netlogon(domain, &netlogon_pipe);
01747         if (!NT_STATUS_IS_OK(result)) {
01748                 return False;
01749         }
01750 
01751         /* Return a pointer to the struct dcinfo from the
01752            netlogon pipe. */
01753 
01754         *ppdc = domain->conn.netlogon_pipe->dc;
01755         return True;
01756 }
01757 
01758 NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
01759                         struct rpc_pipe_client **cli, POLICY_HND *sam_handle)
01760 {
01761         struct winbindd_cm_conn *conn;
01762         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
01763         fstring conn_pwd;
01764         struct dcinfo *p_dcinfo;
01765         char *machine_password = NULL;
01766         char *machine_account = NULL;
01767         char *domain_name = NULL;
01768 
01769         result = init_dc_connection(domain);
01770         if (!NT_STATUS_IS_OK(result)) {
01771                 return result;
01772         }
01773 
01774         conn = &domain->conn;
01775 
01776         if (conn->samr_pipe != NULL) {
01777                 goto done;
01778         }
01779 
01780         /*
01781          * No SAMR pipe yet. Attempt to get an NTLMSSP SPNEGO authenticated
01782          * sign and sealed pipe using the machine account password by
01783          * preference. If we can't - try schannel, if that fails, try
01784          * anonymous.
01785          */
01786 
01787         pwd_get_cleartext(&conn->cli->pwd, conn_pwd);
01788         if ((conn->cli->user_name[0] == '\0') ||
01789             (conn->cli->domain[0] == '\0') || 
01790             (conn_pwd[0] == '\0'))
01791         {
01792                 result = get_trust_creds(domain, &machine_password,
01793                                          &machine_account, NULL);
01794                 if (!NT_STATUS_IS_OK(result)) {
01795                         DEBUG(10, ("cm_connect_sam: No no user available for "
01796                                    "domain %s, trying schannel\n", conn->cli->domain));
01797                         goto schannel;
01798                 }
01799                 domain_name = domain->name;
01800         } else {
01801                 machine_password = SMB_STRDUP(conn_pwd);                
01802                 machine_account = SMB_STRDUP(conn->cli->user_name);
01803                 domain_name = conn->cli->domain;
01804         }
01805 
01806         if (!machine_password || !machine_account) {
01807                 result = NT_STATUS_NO_MEMORY;
01808                 goto done;
01809         }
01810 
01811         /* We have an authenticated connection. Use a NTLMSSP SPNEGO
01812            authenticated SAMR pipe with sign & seal. */
01813         conn->samr_pipe =
01814                 cli_rpc_pipe_open_spnego_ntlmssp(conn->cli, PI_SAMR,
01815                                                  PIPE_AUTH_LEVEL_PRIVACY,
01816                                                  domain_name,
01817                                                  machine_account,
01818                                                  machine_password, &result);
01819 
01820         if (conn->samr_pipe == NULL) {
01821                 DEBUG(10,("cm_connect_sam: failed to connect to SAMR "
01822                           "pipe for domain %s using NTLMSSP "
01823                           "authenticated pipe: user %s\\%s. Error was "
01824                           "%s\n", domain->name, domain_name,
01825                           machine_account, nt_errstr(result)));
01826                 goto schannel;
01827         }
01828 
01829         DEBUG(10,("cm_connect_sam: connected to SAMR pipe for "
01830                   "domain %s using NTLMSSP authenticated "
01831                   "pipe: user %s\\%s\n", domain->name,
01832                   domain_name, machine_account));
01833 
01834         result = rpccli_samr_connect(conn->samr_pipe, mem_ctx,
01835                                      SEC_RIGHTS_MAXIMUM_ALLOWED,
01836                                      &conn->sam_connect_handle);
01837         if (NT_STATUS_IS_OK(result)) {
01838                 goto open_domain;
01839         }
01840         DEBUG(10,("cm_connect_sam: ntlmssp-sealed rpccli_samr_connect "
01841                   "failed for domain %s, error was %s. Trying schannel\n",
01842                   domain->name, nt_errstr(result) ));
01843         cli_rpc_pipe_close(conn->samr_pipe);
01844 
01845  schannel:
01846 
01847         /* Fall back to schannel if it's a W2K pre-SP1 box. */
01848 
01849         if (!cm_get_schannel_dcinfo(domain, &p_dcinfo)) {
01850                 /* If this call fails - conn->cli can now be NULL ! */
01851                 DEBUG(10, ("cm_connect_sam: Could not get schannel auth info "
01852                            "for domain %s, trying anon\n", domain->name));
01853                 goto anonymous;
01854         }
01855         conn->samr_pipe = cli_rpc_pipe_open_schannel_with_key
01856                 (conn->cli, PI_SAMR, PIPE_AUTH_LEVEL_PRIVACY,
01857                  domain->name, p_dcinfo, &result);
01858 
01859         if (conn->samr_pipe == NULL) {
01860                 DEBUG(10,("cm_connect_sam: failed to connect to SAMR pipe for "
01861                           "domain %s using schannel. Error was %s\n",
01862                           domain->name, nt_errstr(result) ));
01863                 goto anonymous;
01864         }
01865         DEBUG(10,("cm_connect_sam: connected to SAMR pipe for domain %s using "
01866                   "schannel.\n", domain->name ));
01867 
01868         result = rpccli_samr_connect(conn->samr_pipe, mem_ctx,
01869                                      SEC_RIGHTS_MAXIMUM_ALLOWED,
01870                                      &conn->sam_connect_handle);
01871         if (NT_STATUS_IS_OK(result)) {
01872                 goto open_domain;
01873         }
01874         DEBUG(10,("cm_connect_sam: schannel-sealed rpccli_samr_connect failed "
01875                   "for domain %s, error was %s. Trying anonymous\n",
01876                   domain->name, nt_errstr(result) ));
01877         cli_rpc_pipe_close(conn->samr_pipe);
01878 
01879  anonymous:
01880 
01881         /* Finally fall back to anonymous. */
01882         conn->samr_pipe = cli_rpc_pipe_open_noauth(conn->cli, PI_SAMR,
01883                                                    &result);
01884 
01885         if (conn->samr_pipe == NULL) {
01886                 result = NT_STATUS_PIPE_NOT_AVAILABLE;
01887                 goto done;
01888         }
01889 
01890         result = rpccli_samr_connect(conn->samr_pipe, mem_ctx,
01891                                      SEC_RIGHTS_MAXIMUM_ALLOWED,
01892                                      &conn->sam_connect_handle);
01893         if (!NT_STATUS_IS_OK(result)) {
01894                 DEBUG(10,("cm_connect_sam: rpccli_samr_connect failed "
01895                           "for domain %s Error was %s\n",
01896                           domain->name, nt_errstr(result) ));
01897                 goto done;
01898         }
01899 
01900  open_domain:
01901         result = rpccli_samr_open_domain(conn->samr_pipe,
01902                                          mem_ctx,
01903                                          &conn->sam_connect_handle,
01904                                          SEC_RIGHTS_MAXIMUM_ALLOWED,
01905                                          &domain->sid,
01906                                          &conn->sam_domain_handle);
01907 
01908  done:
01909 
01910         if (!NT_STATUS_IS_OK(result)) {
01911                 invalidate_cm_connection(conn);
01912                 return result;
01913         }
01914 
01915         *cli = conn->samr_pipe;
01916         *sam_handle = conn->sam_domain_handle;
01917         SAFE_FREE(machine_password);
01918         SAFE_FREE(machine_account);
01919         return result;
01920 }
01921 
01922 NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
01923                         struct rpc_pipe_client **cli, POLICY_HND *lsa_policy)
01924 {
01925         struct winbindd_cm_conn *conn;
01926         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
01927         fstring conn_pwd;
01928         struct dcinfo *p_dcinfo;
01929 
01930         result = init_dc_connection(domain);
01931         if (!NT_STATUS_IS_OK(result))
01932                 return result;
01933 
01934         conn = &domain->conn;
01935 
01936         if (conn->lsa_pipe != NULL) {
01937                 goto done;
01938         }
01939 
01940         pwd_get_cleartext(&conn->cli->pwd, conn_pwd);
01941         if ((conn->cli->user_name[0] == '\0') ||
01942             (conn->cli->domain[0] == '\0') || 
01943             (conn_pwd[0] == '\0')) {
01944                 DEBUG(10, ("cm_connect_lsa: No no user available for "
01945                            "domain %s, trying schannel\n", conn->cli->domain));
01946                 goto schannel;
01947         }
01948 
01949         /* We have an authenticated connection. Use a NTLMSSP SPNEGO
01950          * authenticated LSA pipe with sign & seal. */
01951         conn->lsa_pipe = cli_rpc_pipe_open_spnego_ntlmssp
01952                 (conn->cli, PI_LSARPC, PIPE_AUTH_LEVEL_PRIVACY,
01953                  conn->cli->domain, conn->cli->user_name, conn_pwd, &result);
01954 
01955         if (conn->lsa_pipe == NULL) {
01956                 DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
01957                           "domain %s using NTLMSSP authenticated pipe: user "
01958                           "%s\\%s. Error was %s. Trying schannel.\n",
01959                           domain->name, conn->cli->domain,
01960                           conn->cli->user_name, nt_errstr(result)));
01961                 goto schannel;
01962         }
01963 
01964         DEBUG(10,("cm_connect_lsa: connected to LSA pipe for domain %s using "
01965                   "NTLMSSP authenticated pipe: user %s\\%s\n",
01966                   domain->name, conn->cli->domain, conn->cli->user_name ));
01967 
01968         result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
01969                                         SEC_RIGHTS_MAXIMUM_ALLOWED,
01970                                         &conn->lsa_policy);
01971         if (NT_STATUS_IS_OK(result)) {
01972                 goto done;
01973         }
01974 
01975         DEBUG(10,("cm_connect_lsa: rpccli_lsa_open_policy failed, trying "
01976                   "schannel\n"));
01977 
01978         cli_rpc_pipe_close(conn->lsa_pipe);
01979 
01980  schannel:
01981 
01982         /* Fall back to schannel if it's a W2K pre-SP1 box. */
01983 
01984         if (!cm_get_schannel_dcinfo(domain, &p_dcinfo)) {
01985                 /* If this call fails - conn->cli can now be NULL ! */
01986                 DEBUG(10, ("cm_connect_lsa: Could not get schannel auth info "
01987                            "for domain %s, trying anon\n", domain->name));
01988                 goto anonymous;
01989         }
01990         conn->lsa_pipe = cli_rpc_pipe_open_schannel_with_key
01991                 (conn->cli, PI_LSARPC, PIPE_AUTH_LEVEL_PRIVACY,
01992                  domain->name, p_dcinfo, &result);
01993 
01994         if (conn->lsa_pipe == NULL) {
01995                 DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
01996                           "domain %s using schannel. Error was %s\n",
01997                           domain->name, nt_errstr(result) ));
01998                 goto anonymous;
01999         }
02000         DEBUG(10,("cm_connect_lsa: connected to LSA pipe for domain %s using "
02001                   "schannel.\n", domain->name ));
02002 
02003         result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
02004                                         SEC_RIGHTS_MAXIMUM_ALLOWED,
02005                                         &conn->lsa_policy);
02006         if (NT_STATUS_IS_OK(result)) {
02007                 goto done;
02008         }
02009 
02010         DEBUG(10,("cm_connect_lsa: rpccli_lsa_open_policy failed, trying "
02011                   "anonymous\n"));
02012 
02013         cli_rpc_pipe_close(conn->lsa_pipe);
02014 
02015  anonymous:
02016 
02017         conn->lsa_pipe = cli_rpc_pipe_open_noauth(conn->cli, PI_LSARPC,
02018                                                   &result);
02019         if (conn->lsa_pipe == NULL) {
02020                 result = NT_STATUS_PIPE_NOT_AVAILABLE;
02021                 goto done;
02022         }
02023 
02024         result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
02025                                         SEC_RIGHTS_MAXIMUM_ALLOWED,
02026                                         &conn->lsa_policy);
02027  done:
02028         if (!NT_STATUS_IS_OK(result)) {
02029                 invalidate_cm_connection(conn);
02030                 return result;
02031         }
02032 
02033         *cli = conn->lsa_pipe;
02034         *lsa_policy = conn->lsa_policy;
02035         return result;
02036 }
02037 
02038 /****************************************************************************
02039  Open the netlogon pipe to this DC. Use schannel if specified in client conf.
02040  session key stored in conn->netlogon_pipe->dc->sess_key.
02041 ****************************************************************************/
02042 
02043 NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
02044                              struct rpc_pipe_client **cli)
02045 {
02046         struct winbindd_cm_conn *conn;
02047         NTSTATUS result;
02048 
02049         uint32 neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
02050         uint8  mach_pwd[16];
02051         uint32  sec_chan_type;
02052         const char *account_name;
02053         struct rpc_pipe_client *netlogon_pipe = NULL;
02054 
02055         *cli = NULL;
02056 
02057         result = init_dc_connection(domain);
02058         if (!NT_STATUS_IS_OK(result)) {
02059                 return result;
02060         }
02061 
02062         conn = &domain->conn;
02063 
02064         if (conn->netlogon_pipe != NULL) {
02065                 *cli = conn->netlogon_pipe;
02066                 return NT_STATUS_OK;
02067         }
02068 
02069         netlogon_pipe = cli_rpc_pipe_open_noauth(conn->cli, PI_NETLOGON,
02070                                                  &result);
02071         if (netlogon_pipe == NULL) {
02072                 return result;
02073         }
02074 
02075         if ((!IS_DC) && (!domain->primary)) {
02076                 /* Clear the schannel request bit and drop down */
02077                 neg_flags &= ~NETLOGON_NEG_SCHANNEL;            
02078                 goto no_schannel;
02079         }
02080 
02081         if (lp_client_schannel() != False) {
02082                 neg_flags |= NETLOGON_NEG_SCHANNEL;
02083         }
02084 
02085         if (!get_trust_pw_hash(domain->name, mach_pwd, &account_name,
02086                                &sec_chan_type))
02087         {
02088                 cli_rpc_pipe_close(netlogon_pipe);
02089                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
02090         }
02091 
02092         result = rpccli_netlogon_setup_creds(
02093                  netlogon_pipe,
02094                  domain->dcname, /* server name. */
02095                  domain->name,   /* domain name */
02096                  global_myname(), /* client name */
02097                  account_name,   /* machine account */
02098                  mach_pwd,       /* machine password */
02099                  sec_chan_type,  /* from get_trust_pw */
02100                  &neg_flags);
02101 
02102         if (!NT_STATUS_IS_OK(result)) {
02103                 cli_rpc_pipe_close(netlogon_pipe);
02104                 return result;
02105         }
02106 
02107         if ((lp_client_schannel() == True) &&
02108                         ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
02109                 DEBUG(3, ("Server did not offer schannel\n"));
02110                 cli_rpc_pipe_close(netlogon_pipe);
02111                 return NT_STATUS_ACCESS_DENIED;
02112         }
02113 
02114  no_schannel:
02115         if ((lp_client_schannel() == False) ||
02116                         ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
02117                 /* We're done - just keep the existing connection to NETLOGON
02118                  * open */
02119                 conn->netlogon_pipe = netlogon_pipe;
02120                 *cli = conn->netlogon_pipe;
02121                 return NT_STATUS_OK;
02122         }
02123 
02124         /* Using the credentials from the first pipe, open a signed and sealed
02125            second netlogon pipe. The session key is stored in the schannel
02126            part of the new pipe auth struct.
02127         */
02128 
02129         conn->netlogon_pipe =
02130                 cli_rpc_pipe_open_schannel_with_key(conn->cli,
02131                                                     PI_NETLOGON,
02132                                                     PIPE_AUTH_LEVEL_PRIVACY,
02133                                                     domain->name,
02134                                                     netlogon_pipe->dc,
02135                                                     &result);
02136 
02137         /* We can now close the initial netlogon pipe. */
02138         cli_rpc_pipe_close(netlogon_pipe);
02139 
02140         if (conn->netlogon_pipe == NULL) {
02141                 DEBUG(3, ("Could not open schannel'ed NETLOGON pipe. Error "
02142                           "was %s\n", nt_errstr(result)));
02143                           
02144                 /* make sure we return something besides OK */
02145                 return !NT_STATUS_IS_OK(result) ? result : NT_STATUS_PIPE_NOT_AVAILABLE;
02146         }
02147 
02148         *cli = conn->netlogon_pipe;
02149         return NT_STATUS_OK;
02150 }

Sambaに対してSat Aug 29 21:23:10 2009に生成されました。  doxygen 1.4.7