static NTSTATUS check_netlogond_security(const struct auth_context *auth_context, void *my_private_data, TALLOC_CTX *mem_ctx, const struct auth_usersupplied_info *user_info, struct auth_serversupplied_info **server_info) { TALLOC_CTX *frame = talloc_stackframe(); struct netr_SamInfo3 *info3 = NULL; struct rpc_pipe_client *p = NULL; struct pipe_auth_data *auth = NULL; uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; uint8_t machine_password[16]; struct netlogon_creds_CredentialState *creds; NTSTATUS schannel_bind_result, status; struct named_mutex *mutex = NULL; const char *ncalrpcsock; DEBUG(10, ("Check auth for: [%s]\n", user_info->mapped.account_name)); ncalrpcsock = lp_parm_const_string( GLOBAL_SECTION_SNUM, "auth_netlogond", "socket", NULL); if (ncalrpcsock == NULL) { ncalrpcsock = talloc_asprintf(talloc_tos(), "%s/%s", get_dyn_NCALRPCDIR(), "DEFAULT"); } if (ncalrpcsock == NULL) { status = NT_STATUS_NO_MEMORY; goto done; } creds = secrets_fetch_local_schannel_creds(talloc_tos()); if (creds == NULL) { goto new_key; } status = netlogond_validate(talloc_tos(), auth_context, ncalrpcsock, creds, user_info, &info3, &schannel_bind_result); DEBUG(10, ("netlogond_validate returned %s\n", nt_errstr(status))); if (NT_STATUS_IS_OK(status)) { goto okay; } if (NT_STATUS_IS_OK(schannel_bind_result)) { /* * This is a real failure from the DC */ goto done; } new_key: mutex = grab_named_mutex(talloc_tos(), "LOCAL_SCHANNEL_KEY", 60); if (mutex == NULL) { DEBUG(10, ("Could not get mutex LOCAL_SCHANNEL_KEY\n")); status = NT_STATUS_ACCESS_DENIED; goto done; } DEBUG(10, ("schannel bind failed, setting up new key\n")); status = rpc_pipe_open_ncalrpc(talloc_tos(), ncalrpcsock, &ndr_table_netlogon.syntax_id, &p); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("rpc_pipe_open_ncalrpc failed: %s\n", nt_errstr(status))); goto done; } status = rpccli_anon_bind_data(p, &auth); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("rpccli_anon_bind_data failed: %s\n", nt_errstr(status))); goto done; } status = rpc_pipe_bind(p, auth); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("rpc_pipe_bind failed: %s\n", nt_errstr(status))); goto done; } status = mymachinepw(machine_password); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("mymachinepw failed: %s\n", nt_errstr(status))); goto done; } DEBUG(10, ("machinepw ")); dump_data(10, machine_password, 16); status = rpccli_netlogon_setup_creds( p, global_myname(), lp_workgroup(), global_myname(), global_myname(), machine_password, SEC_CHAN_BDC, &neg_flags); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("rpccli_netlogon_setup_creds failed: %s\n", nt_errstr(status))); goto done; } secrets_store_local_schannel_creds(p->dc); /* * Retry the authentication with the mutex held. This way nobody else * can step on our toes. */ status = netlogond_validate(talloc_tos(), auth_context, ncalrpcsock, p->dc, user_info, &info3, &schannel_bind_result); TALLOC_FREE(p); DEBUG(10, ("netlogond_validate returned %s\n", nt_errstr(status))); if (!NT_STATUS_IS_OK(status)) { goto done; } okay: status = make_server_info_info3(mem_ctx, user_info->client.account_name, user_info->mapped.domain_name, server_info, info3); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("make_server_info_info3 failed: %s\n", nt_errstr(status))); TALLOC_FREE(frame); return status; } status = NT_STATUS_OK; done: TALLOC_FREE(frame); return status; }
static struct cli_state *server_cryptkey(TALLOC_CTX *mem_ctx) { struct cli_state *cli = NULL; char *desthost = NULL; struct sockaddr_storage dest_ss; const char *p; char *pserver = NULL; bool connected_ok = False; struct named_mutex *mutex = NULL; NTSTATUS status; pserver = talloc_strdup(mem_ctx, lp_passwordserver()); p = pserver; while(next_token_talloc(mem_ctx, &p, &desthost, LIST_SEP)) { desthost = talloc_sub_basic(mem_ctx, current_user_info.smb_name, current_user_info.domain, desthost); if (!desthost) { return NULL; } strupper_m(desthost); if (strequal(desthost, myhostname())) { DEBUG(1,("Password server loop - disabling " "password server %s\n", desthost)); continue; } if(!resolve_name( desthost, &dest_ss, 0x20, false)) { DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost)); continue; } if (ismyaddr((struct sockaddr *)(void *)&dest_ss)) { DEBUG(1,("Password server loop - disabling password server %s\n",desthost)); continue; } /* we use a mutex to prevent two connections at once - when a Win2k PDC get two connections where one hasn't completed a session setup yet it will send a TCP reset to the first connection (tridge) */ mutex = grab_named_mutex(talloc_tos(), desthost, 10); if (mutex == NULL) { return NULL; } status = cli_connect_nb(desthost, &dest_ss, 0, 0x20, lp_netbios_name(), Undefined, &cli); if (NT_STATUS_IS_OK(status)) { DEBUG(3,("connected to password server %s\n",desthost)); connected_ok = True; break; } DEBUG(10,("server_cryptkey: failed to connect to server %s. Error %s\n", desthost, nt_errstr(status) )); TALLOC_FREE(mutex); } if (!connected_ok) { DEBUG(0,("password server not available\n")); return NULL; } /* security = server just can't function with spnego */ cli->use_spnego = False; DEBUG(3,("got session\n")); status = cli_negprot(cli); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(mutex); DEBUG(1, ("%s rejected the negprot: %s\n", desthost, nt_errstr(status))); cli_shutdown(cli); return NULL; } if (cli->protocol < PROTOCOL_LANMAN2 || !(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) { TALLOC_FREE(mutex); DEBUG(1,("%s isn't in user level security mode\n",desthost)); cli_shutdown(cli); return NULL; } /* Get the first session setup done quickly, to avoid silly Win2k bugs. (The next connection to the server will kill this one... */ status = cli_session_setup(cli, "", "", 0, "", 0, ""); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(mutex); DEBUG(0,("%s rejected the initial session setup (%s)\n", desthost, nt_errstr(status))); cli_shutdown(cli); return NULL; } TALLOC_FREE(mutex); DEBUG(3,("password server OK\n")); return cli; }
static NTSTATUS connect_to_domain_password_server(struct cli_state **cli, const char *domain, const char *dc_name, const struct sockaddr_storage *dc_ss, struct rpc_pipe_client **pipe_ret) { NTSTATUS result; struct rpc_pipe_client *netlogon_pipe = NULL; *cli = NULL; *pipe_ret = NULL; /* TODO: Send a SAMLOGON request to determine whether this is a valid logonserver. We can avoid a 30-second timeout if the DC is down if the SAMLOGON request fails as it is only over UDP. */ /* we use a mutex to prevent two connections at once - when a Win2k PDC get two connections where one hasn't completed a session setup yet it will send a TCP reset to the first connection (tridge) */ /* * With NT4.x DC's *all* authentication must be serialized to avoid * ACCESS_DENIED errors if 2 auths are done from the same machine. JRA. */ mutex = grab_named_mutex(NULL, dc_name, 10); if (mutex == NULL) { return NT_STATUS_NO_LOGON_SERVERS; } /* Attempt connection */ result = cli_full_connection(cli, lp_netbios_name(), dc_name, dc_ss, 0, "IPC$", "IPC", "", "", "", 0, SMB_SIGNING_DEFAULT); if (!NT_STATUS_IS_OK(result)) { /* map to something more useful */ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) { result = NT_STATUS_NO_LOGON_SERVERS; } if (*cli) { cli_shutdown(*cli); *cli = NULL; } TALLOC_FREE(mutex); return result; } /* * We now have an anonymous connection to IPC$ on the domain password server. */ /* * Even if the connect succeeds we need to setup the netlogon * pipe here. We do this as we may just have changed the domain * account password on the PDC and yet we may be talking to * a BDC that doesn't have this replicated yet. In this case * a successful connect to a DC needs to take the netlogon connect * into account also. This patch from "Bjart Kvarme" <*****@*****.**>. */ /* open the netlogon pipe. */ if (lp_client_schannel()) { /* We also setup the creds chain in the open_schannel call. */ result = cli_rpc_pipe_open_schannel( *cli, &ndr_table_netlogon, NCACN_NP, DCERPC_AUTH_LEVEL_PRIVACY, domain, &netlogon_pipe); } else { result = cli_rpc_pipe_open_noauth( *cli, &ndr_table_netlogon, &netlogon_pipe); } if (!NT_STATUS_IS_OK(result)) { DEBUG(0,("connect_to_domain_password_server: unable to open the domain client session to \ machine %s. Error was : %s.\n", dc_name, nt_errstr(result))); cli_shutdown(*cli); *cli = NULL; TALLOC_FREE(mutex); return result; }
static bool tdbsam_open( const char *name ) { int32_t version; int32_t minor_version; NTSTATUS status; /* check if we are already open */ if ( db_sam ) { return true; } /* Try to open tdb passwd. Create a new one if necessary */ db_sam = db_open(NULL, name, 0, TDB_DEFAULT, O_CREAT|O_RDWR, 0600, DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE); if (db_sam == NULL) { DEBUG(0, ("tdbsam_open: Failed to open/create TDB passwd " "[%s]\n", name)); return false; } /* Check the version */ status = dbwrap_fetch_int32_bystring(db_sam, TDBSAM_VERSION_STRING, &version); if (!NT_STATUS_IS_OK(status)) { version = 0; /* Version not found, assume version 0 */ } /* Get the minor version */ status = dbwrap_fetch_int32_bystring( db_sam, TDBSAM_MINOR_VERSION_STRING, &minor_version); if (!NT_STATUS_IS_OK(status)) { minor_version = 0; /* Minor version not found, assume 0 */ } /* Compare the version */ if (version > TDBSAM_VERSION) { /* Version more recent than the latest known */ DEBUG(0, ("tdbsam_open: unknown version => %d\n", version)); TALLOC_FREE(db_sam); return false; } if ( version < TDBSAM_VERSION || (version == TDBSAM_VERSION && minor_version < TDBSAM_MINOR_VERSION) ) { /* * Ok - we think we're going to have to convert. * Due to the backup process we now must do to * upgrade we have to get a mutex and re-check * the version. Someone else may have upgraded * whilst we were checking. */ struct named_mutex *mtx = grab_named_mutex(NULL, "tdbsam_upgrade_mutex", 600); if (!mtx) { DEBUG(0, ("tdbsam_open: failed to grab mutex.\n")); TALLOC_FREE(db_sam); return false; } /* Re-check the version */ status = dbwrap_fetch_int32_bystring( db_sam, TDBSAM_VERSION_STRING, &version); if (!NT_STATUS_IS_OK(status)) { version = 0; /* Version not found, assume version 0 */ } /* Re-check the minor version */ status = dbwrap_fetch_int32_bystring( db_sam, TDBSAM_MINOR_VERSION_STRING, &minor_version); if (!NT_STATUS_IS_OK(status)) { minor_version = 0; /* Minor version not found, assume 0 */ } /* Compare the version */ if (version > TDBSAM_VERSION) { /* Version more recent than the latest known */ DEBUG(0, ("tdbsam_open: unknown version => %d\n", version)); TALLOC_FREE(db_sam); TALLOC_FREE(mtx); return false; } if ( version < TDBSAM_VERSION || (version == TDBSAM_VERSION && minor_version < TDBSAM_MINOR_VERSION) ) { /* * Note that minor versions we read that are greater * than the current minor version we have hard coded * are assumed to be compatible if they have the same * major version. That allows previous versions of the * passdb code that don't know about minor versions to * still use this database. JRA. */ DEBUG(1, ("tdbsam_open: Converting version %d.%d database to " "version %d.%d.\n", version, minor_version, TDBSAM_VERSION, TDBSAM_MINOR_VERSION)); if ( !tdbsam_convert(&db_sam, name, version) ) { DEBUG(0, ("tdbsam_open: Error when trying to convert " "tdbsam [%s]\n",name)); TALLOC_FREE(db_sam); TALLOC_FREE(mtx); return false; } DEBUG(3, ("TDBSAM converted successfully.\n")); } TALLOC_FREE(mtx); } DEBUG(4,("tdbsam_open: successfully opened %s\n", name )); return true; }
NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, const char *realm, time_t time_offset, const DATA_BLOB *ticket, char **principal, struct PAC_DATA **pac_data, DATA_BLOB *ap_rep, DATA_BLOB *session_key, bool use_replay_cache) { NTSTATUS sret = NT_STATUS_LOGON_FAILURE; NTSTATUS pac_ret; DATA_BLOB auth_data; krb5_context context = NULL; krb5_auth_context auth_context = NULL; krb5_data packet; krb5_ticket *tkt = NULL; krb5_rcache rcache = NULL; krb5_keyblock *keyblock = NULL; time_t authtime; krb5_error_code ret = 0; int flags = 0; krb5_principal host_princ = NULL; krb5_const_principal client_principal = NULL; char *host_princ_s = NULL; bool auth_ok = False; bool got_auth_data = False; struct named_mutex *mutex = NULL; ZERO_STRUCT(packet); ZERO_STRUCT(auth_data); *principal = NULL; *pac_data = NULL; *ap_rep = data_blob_null; *session_key = data_blob_null; initialize_krb5_error_table(); ret = krb5_init_context(&context); if (ret) { DEBUG(1,("ads_verify_ticket: krb5_init_context failed (%s)\n", error_message(ret))); return NT_STATUS_LOGON_FAILURE; } if (time_offset != 0) { krb5_set_real_time(context, time(NULL) + time_offset, 0); } ret = krb5_set_default_realm(context, realm); if (ret) { DEBUG(1,("ads_verify_ticket: krb5_set_default_realm failed (%s)\n", error_message(ret))); goto out; } /* This whole process is far more complex than I would like. We have to go through all this to allow us to store the secret internally, instead of using /etc/krb5.keytab */ ret = krb5_auth_con_init(context, &auth_context); if (ret) { DEBUG(1,("ads_verify_ticket: krb5_auth_con_init failed (%s)\n", error_message(ret))); goto out; } krb5_auth_con_getflags( context, auth_context, &flags ); if ( !use_replay_cache ) { /* Disable default use of a replay cache */ flags &= ~KRB5_AUTH_CONTEXT_DO_TIME; krb5_auth_con_setflags( context, auth_context, flags ); } if (asprintf(&host_princ_s, "%s$", global_myname()) == -1) { goto out; } strlower_m(host_princ_s); ret = smb_krb5_parse_name(context, host_princ_s, &host_princ); if (ret) { DEBUG(1,("ads_verify_ticket: smb_krb5_parse_name(%s) failed (%s)\n", host_princ_s, error_message(ret))); goto out; } if ( use_replay_cache ) { /* Lock a mutex surrounding the replay as there is no locking in the MIT krb5 code surrounding the replay cache... */ mutex = grab_named_mutex(talloc_tos(), "replay cache mutex", 10); if (mutex == NULL) { DEBUG(1,("ads_verify_ticket: unable to protect " "replay cache with mutex.\n")); ret = KRB5_CC_IO; goto out; } /* JRA. We must set the rcache here. This will prevent replay attacks. */ ret = krb5_get_server_rcache(context, krb5_princ_component(context, host_princ, 0), &rcache); if (ret) { DEBUG(1,("ads_verify_ticket: krb5_get_server_rcache " "failed (%s)\n", error_message(ret))); goto out; } ret = krb5_auth_con_setrcache(context, auth_context, rcache); if (ret) { DEBUG(1,("ads_verify_ticket: krb5_auth_con_setrcache " "failed (%s)\n", error_message(ret))); goto out; } } /* Try secrets.tdb first and fallback to the krb5.keytab if necessary */ auth_ok = ads_secrets_verify_ticket(context, auth_context, host_princ, ticket, &tkt, &keyblock, &ret); if (!auth_ok && (ret == KRB5KRB_AP_ERR_TKT_NYV || ret == KRB5KRB_AP_ERR_TKT_EXPIRED || ret == KRB5KRB_AP_ERR_SKEW)) { goto auth_failed; } if (!auth_ok && lp_use_kerberos_keytab()) { auth_ok = ads_keytab_verify_ticket(context, auth_context, ticket, &tkt, &keyblock, &ret); } if ( use_replay_cache ) { TALLOC_FREE(mutex); #if 0 /* Heimdal leaks here, if we fix the leak, MIT crashes */ if (rcache) { krb5_rc_close(context, rcache); } #endif } auth_failed: if (!auth_ok) { DEBUG(3,("ads_verify_ticket: krb5_rd_req with auth failed (%s)\n", error_message(ret))); /* Try map the error return in case it's something like * a clock skew error. */ sret = krb5_to_nt_status(ret); if (NT_STATUS_IS_OK(sret) || NT_STATUS_EQUAL(sret,NT_STATUS_UNSUCCESSFUL)) { sret = NT_STATUS_LOGON_FAILURE; } DEBUG(10,("ads_verify_ticket: returning error %s\n", nt_errstr(sret) )); goto out; } authtime = get_authtime_from_tkt(tkt); client_principal = get_principal_from_tkt(tkt); ret = krb5_mk_rep(context, auth_context, &packet); if (ret) { DEBUG(3,("ads_verify_ticket: Failed to generate mutual authentication reply (%s)\n", error_message(ret))); goto out; } *ap_rep = data_blob(packet.data, packet.length); if (packet.data) { kerberos_free_data_contents(context, &packet); ZERO_STRUCT(packet); } get_krb5_smb_session_key(context, auth_context, session_key, True); dump_data_pw("SMB session key (from ticket)\n", session_key->data, session_key->length); #if 0 file_save("/tmp/ticket.dat", ticket->data, ticket->length); #endif /* continue when no PAC is retrieved or we couldn't decode the PAC (like accounts that have the UF_NO_AUTH_DATA_REQUIRED flag set, or Kerberos tickets encrypted using a DES key) - Guenther */ got_auth_data = get_auth_data_from_tkt(mem_ctx, &auth_data, tkt); if (!got_auth_data) { DEBUG(3,("ads_verify_ticket: did not retrieve auth data. continuing without PAC\n")); } if (got_auth_data) { pac_ret = decode_pac_data(mem_ctx, &auth_data, context, keyblock, client_principal, authtime, pac_data); if (!NT_STATUS_IS_OK(pac_ret)) { DEBUG(3,("ads_verify_ticket: failed to decode PAC_DATA: %s\n", nt_errstr(pac_ret))); *pac_data = NULL; } data_blob_free(&auth_data); } #if 0 #if defined(HAVE_KRB5_TKT_ENC_PART2) /* MIT */ if (tkt->enc_part2) { file_save("/tmp/authdata.dat", tkt->enc_part2->authorization_data[0]->contents, tkt->enc_part2->authorization_data[0]->length); } #else /* Heimdal */ if (tkt->ticket.authorization_data) { file_save("/tmp/authdata.dat", tkt->ticket.authorization_data->val->ad_data.data, tkt->ticket.authorization_data->val->ad_data.length); } #endif #endif if ((ret = smb_krb5_unparse_name(context, client_principal, principal))) { DEBUG(3,("ads_verify_ticket: smb_krb5_unparse_name failed (%s)\n", error_message(ret))); sret = NT_STATUS_LOGON_FAILURE; goto out; } sret = NT_STATUS_OK; out: TALLOC_FREE(mutex); if (!NT_STATUS_IS_OK(sret)) { data_blob_free(&auth_data); } if (!NT_STATUS_IS_OK(sret)) { data_blob_free(ap_rep); } if (host_princ) { krb5_free_principal(context, host_princ); } if (keyblock) { krb5_free_keyblock(context, keyblock); } if (tkt != NULL) { krb5_free_ticket(context, tkt); } SAFE_FREE(host_princ_s); if (auth_context) { krb5_auth_con_free(context, auth_context); } if (context) { krb5_free_context(context); } return sret; }
static NTSTATUS connect_to_domain_password_server(struct cli_state **cli_ret, const char *domain, const char *dc_name, const struct sockaddr_storage *dc_ss, struct rpc_pipe_client **pipe_ret, TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_context **creds_ret) { TALLOC_CTX *frame = talloc_stackframe(); struct messaging_context *msg_ctx = server_messaging_context(); NTSTATUS result; struct cli_state *cli = NULL; struct rpc_pipe_client *netlogon_pipe = NULL; struct netlogon_creds_cli_context *netlogon_creds = NULL; struct netlogon_creds_CredentialState *creds = NULL; uint32_t netlogon_flags = 0; enum netr_SchannelType sec_chan_type = 0; const char *_account_name = NULL; const char *account_name = NULL; struct samr_Password current_nt_hash; struct samr_Password *previous_nt_hash = NULL; bool ok; *cli_ret = NULL; *pipe_ret = NULL; *creds_ret = NULL; /* TODO: Send a SAMLOGON request to determine whether this is a valid logonserver. We can avoid a 30-second timeout if the DC is down if the SAMLOGON request fails as it is only over UDP. */ /* we use a mutex to prevent two connections at once - when a Win2k PDC get two connections where one hasn't completed a session setup yet it will send a TCP reset to the first connection (tridge) */ /* * With NT4.x DC's *all* authentication must be serialized to avoid * ACCESS_DENIED errors if 2 auths are done from the same machine. JRA. */ mutex = grab_named_mutex(NULL, dc_name, 10); if (mutex == NULL) { TALLOC_FREE(frame); return NT_STATUS_NO_LOGON_SERVERS; } /* Attempt connection */ result = cli_full_connection(&cli, lp_netbios_name(), dc_name, dc_ss, 0, "IPC$", "IPC", "", "", "", 0, SMB_SIGNING_DEFAULT); if (!NT_STATUS_IS_OK(result)) { /* map to something more useful */ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) { result = NT_STATUS_NO_LOGON_SERVERS; } TALLOC_FREE(mutex); TALLOC_FREE(frame); return result; } /* * We now have an anonymous connection to IPC$ on the domain password server. */ ok = get_trust_pw_hash(domain, current_nt_hash.hash, &_account_name, &sec_chan_type); if (!ok) { cli_shutdown(cli); TALLOC_FREE(mutex); TALLOC_FREE(frame); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } account_name = talloc_asprintf(talloc_tos(), "%s$", _account_name); if (account_name == NULL) { cli_shutdown(cli); TALLOC_FREE(mutex); TALLOC_FREE(frame); return NT_STATUS_NO_MEMORY; } result = rpccli_create_netlogon_creds(dc_name, domain, account_name, sec_chan_type, msg_ctx, talloc_tos(), &netlogon_creds); if (!NT_STATUS_IS_OK(result)) { cli_shutdown(cli); TALLOC_FREE(mutex); TALLOC_FREE(frame); SAFE_FREE(previous_nt_hash); return result; } result = rpccli_setup_netlogon_creds(cli, netlogon_creds, false, /* force_reauth */ current_nt_hash, previous_nt_hash); SAFE_FREE(previous_nt_hash); if (!NT_STATUS_IS_OK(result)) { cli_shutdown(cli); TALLOC_FREE(mutex); TALLOC_FREE(frame); return result; } result = netlogon_creds_cli_get(netlogon_creds, talloc_tos(), &creds); if (!NT_STATUS_IS_OK(result)) { cli_shutdown(cli); TALLOC_FREE(mutex); TALLOC_FREE(frame); return result; } netlogon_flags = creds->negotiate_flags; TALLOC_FREE(creds); if (netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC) { result = cli_rpc_pipe_open_schannel_with_key( cli, &ndr_table_netlogon, NCACN_NP, domain, netlogon_creds, &netlogon_pipe); } else { result = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon, &netlogon_pipe); } if (!NT_STATUS_IS_OK(result)) { DEBUG(0,("connect_to_domain_password_server: " "unable to open the domain client session to " "machine %s. Flags[0x%08X] Error was : %s.\n", dc_name, (unsigned)netlogon_flags, nt_errstr(result))); cli_shutdown(cli); TALLOC_FREE(mutex); TALLOC_FREE(frame); return result; } if(!netlogon_pipe) { DEBUG(0, ("connect_to_domain_password_server: unable to open " "the domain client session to machine %s. Error " "was : %s.\n", dc_name, nt_errstr(result))); cli_shutdown(cli); TALLOC_FREE(mutex); TALLOC_FREE(frame); return NT_STATUS_NO_LOGON_SERVERS; } /* We exit here with the mutex *locked*. JRA */ *cli_ret = cli; *pipe_ret = netlogon_pipe; *creds_ret = talloc_move(mem_ctx, &netlogon_creds); TALLOC_FREE(frame); return NT_STATUS_OK; }