fstring domain;
fstring controller;
fstring pipe_name;
+ size_t mutex_ref_count;
struct cli_state *cli;
POLICY_HND pol;
};
struct get_dc_name_cache *prev, *next;
};
-
/*
find the DC for a domain using methods appropriate for a ADS domain
*/
ADS_STRUCT *ads;
const char *realm = domain;
- if (strcasecmp(realm, lp_workgroup()) == 0) {
+ if (strcasecmp(realm, lp_workgroup()) == 0)
realm = lp_realm();
- }
ads = ads_init(realm, domain, NULL);
- if (!ads) {
+ if (!ads)
return False;
- }
/* we don't need to bind, just connect */
ads->auth.flags |= ADS_AUTH_NO_BIND;
ads_connect(ads);
#endif
- if (!ads->config.realm) {
+ if (!ads->config.realm)
return False;
- }
fstrcpy(srv_name, ads->config.ldap_server_name);
strupper(srv_name);
return True;
}
-/*
- find the DC for a domain using methods appropriate for a RPC domain
-*/
-static BOOL cm_rpc_find_dc(const char *domain, struct in_addr *dc_ip, fstring srv_name)
-{
- struct in_addr *ip_list = NULL, exclude_ip;
- int count, i;
-
- zero_ip(&exclude_ip);
-
- /* Lookup domain controller name. Try the real PDC first to avoid
- SAM sync delays */
-
- if (get_dc_list(True, domain, &ip_list, &count)) {
- if (name_status_find(domain, 0x1c, 0x20, ip_list[0], srv_name)) {
- *dc_ip = ip_list[0];
- SAFE_FREE(ip_list);
- return True;
- }
- /* Didn't get name, remember not to talk to this DC. */
- exclude_ip = ip_list[0];
- SAFE_FREE(ip_list);
- }
-
- if (!get_dc_list(False, domain, &ip_list, &count)) {
- DEBUG(3, ("Could not look up dc's for domain %s\n", domain));
- return False;
- }
-
- /* Remove the entry we've already failed with (should be the PDC). */
- for (i = 0; i < count; i++) {
- if (ip_equal( exclude_ip, ip_list[i]))
- zero_ip(&ip_list[i]);
- }
-
- /* Pick a nice close server */
- /* Look for DC on local net */
- for (i = 0; i < count; i++) {
- if (is_zero_ip(ip_list[i]))
- continue;
-
- if (!is_local_net(ip_list[i]))
- continue;
-
- if (name_status_find(domain, 0x1c, 0x20, ip_list[i], srv_name)) {
- *dc_ip = ip_list[i];
- SAFE_FREE(ip_list);
- return True;
- }
- zero_ip(&ip_list[i]);
- }
-
- /*
- * Secondly try and contact a random PDC/BDC.
- */
-
- i = (sys_random() % count);
-
- if (!is_zero_ip(ip_list[i]) &&
- name_status_find(domain, 0x1c, 0x20,
- ip_list[i], srv_name)) {
- *dc_ip = ip_list[i];
- SAFE_FREE(ip_list);
- return True;
- }
- zero_ip(&ip_list[i]); /* Tried and failed. */
-
- /* Finally return first DC that we can contact using a node
- status */
- for (i = 0; i < count; i++) {
- if (is_zero_ip(ip_list[i]))
- continue;
-
- if (name_status_find(domain, 0x1c, 0x20, ip_list[i], srv_name)) {
- *dc_ip = ip_list[i];
- SAFE_FREE(ip_list);
- return True;
- }
- }
-
- SAFE_FREE(ip_list);
-
- return False;
-}
static BOOL cm_get_dc_name(const char *domain, fstring srv_name, struct in_addr *ip_out)
zero_ip(&dc_ip);
ret = False;
- if (lp_security() == SEC_ADS) {
+ if (lp_security() == SEC_ADS)
ret = cm_ads_find_dc(domain, &dc_ip, srv_name);
- }
+
if (!ret) {
/* fall back on rpc methods if the ADS methods fail */
- ret = cm_rpc_find_dc(domain, &dc_ip, srv_name);
+ ret = rpc_find_dc(domain, srv_name, &dc_ip);
}
- if (!ret) {
+ if (!ret)
return False;
- }
/* We have a name so make the cache entry positive now */
fstrcpy(dcc->srv_name, srv_name);
*password = secrets_fetch(SECRETS_AUTH_PASSWORD, NULL);
if (*username && **username) {
- if (!*domain || !**domain) {
+
+ if (!*domain || !**domain)
*domain = smb_xstrdup(lp_workgroup());
- }
- DEBUG(3, ("IPC$ connections done by user %s\\%s\n", *domain, *username));
+ if (!*password || !**password)
+ *password = smb_xstrdup("");
+
+ DEBUG(3, ("IPC$ connections done by user %s\\%s\n",
+ *domain, *username));
+
} else {
DEBUG(3, ("IPC$ connections done anonymously\n"));
*username = smb_xstrdup("");
/* Open a connction to the remote server, cache failures for 30 seconds */
-static NTSTATUS cm_open_connection(const char *domain,const char *pipe_name,
+static NTSTATUS cm_open_connection(const char *domain, const int pipe_index,
struct winbindd_cm_conn *new_conn)
{
struct failed_connection_cache *fcc;
- extern pstring global_myname;
NTSTATUS result;
char *ipc_username, *ipc_domain, *ipc_password;
struct in_addr dc_ip;
+ int i;
+ BOOL retry = True;
ZERO_STRUCT(dc_ip);
fstrcpy(new_conn->domain, domain);
- fstrcpy(new_conn->pipe_name, pipe_name);
+ fstrcpy(new_conn->pipe_name, get_pipe_name_from_index(pipe_index));
/* Look for a domain controller for this domain. Negative results
are cached so don't bother applying the caching for this
cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
DEBUG(5, ("connecting to %s from %s with username [%s]\\[%s]\n",
- new_conn->controller, global_myname, ipc_domain, ipc_username));
+ new_conn->controller, global_myname(), ipc_domain, ipc_username));
- result = cli_full_connection(&(new_conn->cli), global_myname, new_conn->controller,
- &dc_ip, 0, "IPC$",
- "IPC", ipc_username, ipc_domain,
- ipc_password, 0);
+ for (i = 0; retry && (i < 3); i++) {
+ BOOL got_mutex;
+ if (!(got_mutex = secrets_named_mutex(new_conn->controller, WINBIND_SERVER_MUTEX_WAIT_TIME))) {
+ DEBUG(0,("cm_open_connection: mutex grab failed for %s\n", new_conn->controller));
+ result = NT_STATUS_POSSIBLE_DEADLOCK;
+ continue;
+ }
+
+ result = cli_full_connection(&new_conn->cli, global_myname(), new_conn->controller,
+ &dc_ip, 0, "IPC$", "IPC", ipc_username, ipc_domain,
+ ipc_password, CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK, &retry);
+
+ secrets_named_mutex_release(new_conn->controller);
+
+ if (NT_STATUS_IS_OK(result))
+ break;
+ }
SAFE_FREE(ipc_username);
SAFE_FREE(ipc_domain);
return result;
}
- if (!cli_nt_session_open (new_conn->cli, pipe_name)) {
+ if ( !cli_nt_session_open (new_conn->cli, pipe_index) ) {
result = NT_STATUS_PIPE_NOT_AVAILABLE;
- add_failed_connection_entry(new_conn, result);
+ /*
+ * only cache a failure if we are not trying to open the
+ * **win2k** specific lsarpc UUID. This could be an NT PDC
+ * and therefore a failure is normal. This should probably
+ * be abstracted to a check for 2k specific pipes and wondering
+ * if the PDC is an NT4 box. but since there is only one 2k
+ * specific UUID right now, i'm not going to bother. --jerry
+ */
+ if ( !is_win2k_pipe(pipe_index) )
+ add_failed_connection_entry(new_conn, result);
cli_shutdown(new_conn->cli);
return result;
}
/* Get a connection to the remote DC and open the pipe. If there is already a connection, use that */
-static NTSTATUS get_connection_from_cache(const char *domain, const char *pipe_name, struct winbindd_cm_conn **conn_out)
+static NTSTATUS get_connection_from_cache(const char *domain, const char *pipe_name,
+ struct winbindd_cm_conn **conn_out)
{
struct winbindd_cm_conn *conn, conn_temp;
NTSTATUS result;
if (strequal(conn->domain, domain) &&
strequal(conn->pipe_name, pipe_name)) {
if (!connection_ok(conn)) {
- if (conn->cli) {
+ if (conn->cli)
cli_shutdown(conn->cli);
- }
ZERO_STRUCT(conn_temp);
conn_temp.next = conn->next;
DLIST_REMOVE(cm_conns, conn);
ZERO_STRUCTP(conn);
- if (!NT_STATUS_IS_OK(result = cm_open_connection(domain, pipe_name, conn))) {
+ if (!NT_STATUS_IS_OK(result = cm_open_connection(domain, get_pipe_index(pipe_name), conn))) {
DEBUG(3, ("Could not open a connection to %s for %s (%s)\n",
domain, pipe_name, nt_errstr(result)));
SAFE_FREE(conn);
return NT_STATUS_OK;
}
+
+/**********************************************************************************
+**********************************************************************************/
+
+BOOL cm_check_for_native_mode_win2k( const char *domain )
+{
+ NTSTATUS result;
+ struct winbindd_cm_conn conn;
+ DS_DOMINFO_CTR ctr;
+ BOOL ret = False;
+
+ ZERO_STRUCT( conn );
+ ZERO_STRUCT( ctr );
+
+
+ if ( !NT_STATUS_IS_OK(result = cm_open_connection(domain, PI_LSARPC_DS, &conn)) ) {
+ DEBUG(5, ("cm_check_for_native_mode_win2k: Could not open a connection to %s for PIPE_LSARPC (%s)\n",
+ domain, nt_errstr(result)));
+ return False;
+ }
+
+ if ( conn.cli ) {
+ if ( !NT_STATUS_IS_OK(cli_ds_getprimarydominfo( conn.cli,
+ conn.cli->mem_ctx, DsRolePrimaryDomainInfoBasic, &ctr)) ) {
+ ret = False;
+ goto done;
+ }
+ }
+
+ if ( (ctr.basic->flags & DSROLE_PRIMARY_DS_RUNNING)
+ && !(ctr.basic->flags & DSROLE_PRIMARY_DS_MIXED_MODE) )
+ ret = True;
+
+done:
+ if ( conn.cli )
+ cli_shutdown( conn.cli );
+
+ return ret;
+}
+
+
+
/* Return a LSA policy handle on a domain */
-CLI_POLICY_HND *cm_get_lsa_handle(char *domain)
+CLI_POLICY_HND *cm_get_lsa_handle(const char *domain)
{
struct winbindd_cm_conn *conn;
uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
/* Look for existing connections */
- if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn))) {
+ if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
return NULL;
- }
/* This *shitty* code needs scrapping ! JRA */
if (policy_handle_is_valid(&conn->pol)) {
if (!NT_STATUS_IS_OK(result)) {
/* Hit the cache code again. This cleans out the old connection and gets a new one */
if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
- if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn))) {
+ if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_LSARPC, &conn)))
return NULL;
- }
result = cli_lsa_open_policy(conn->cli, conn->cli->mem_ctx, False,
des_access, &conn->pol);
/* Look for existing connections */
- if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn))) {
+ if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
return NULL;
- }
/* This *shitty* code needs scrapping ! JRA */
if (policy_handle_is_valid(&conn->pol)) {
if (!NT_STATUS_IS_OK(result)) {
/* Hit the cache code again. This cleans out the old connection and gets a new one */
if (conn->cli->fd == -1) { /* Try again, if the remote host disapeared */
- if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn))) {
+ if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_SAMR, &conn)))
return NULL;
- }
result = cli_samr_connect(conn->cli, conn->cli->mem_ctx,
des_access, &conn->pol);
/* Get a handle on a netlogon pipe. This is a bit of a hack to re-use the
netlogon pipe as no handle is returned. */
-NTSTATUS cm_get_netlogon_cli(char *domain, unsigned char *trust_passwd,
+NTSTATUS cm_get_netlogon_cli(const char *domain, const unsigned char *trust_passwd,
struct cli_state **cli)
{
NTSTATUS result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
struct winbindd_cm_conn *conn;
uint32 neg_flags = 0x000001ff;
+ fstring lock_name;
+ BOOL got_mutex;
- if (!cli) {
+ if (!cli)
return NT_STATUS_INVALID_PARAMETER;
- }
- /* Open an initial conection */
+ /* Open an initial conection - keep the mutex. */
- if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_NETLOGON, &conn))) {
+ if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_NETLOGON, &conn)))
return result;
- }
- result = cli_nt_setup_creds(conn->cli, get_sec_chan(), trust_passwd, &neg_flags, 2);
+ snprintf(lock_name, sizeof(lock_name), "NETLOGON\\%s", conn->controller);
+ if (!(got_mutex = secrets_named_mutex(lock_name, WINBIND_SERVER_MUTEX_WAIT_TIME))) {
+ DEBUG(0,("cm_get_netlogon_cli: mutex grab failed for %s\n", conn->controller));
+ }
+
+ result = cli_nt_setup_creds(conn->cli, get_sec_chan(), trust_passwd, &neg_flags, 2);
+
+ if (got_mutex)
+ secrets_named_mutex_release(lock_name);
+
if (!NT_STATUS_IS_OK(result)) {
DEBUG(0, ("error connecting to domain password server: %s\n",
nt_errstr(result)));
/* Hit the cache code again. This cleans out the old connection and gets a new one */
if (conn->cli->fd == -1) {
- if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_NETLOGON, &conn))) {
+ if (!NT_STATUS_IS_OK(result = get_connection_from_cache(domain, PIPE_NETLOGON, &conn)))
return result;
+
+ snprintf(lock_name, sizeof(lock_name), "NETLOGON\\%s", conn->controller);
+ if (!(got_mutex = secrets_named_mutex(lock_name, WINBIND_SERVER_MUTEX_WAIT_TIME))) {
+ DEBUG(0,("cm_get_netlogon_cli: mutex grab failed for %s\n", conn->controller));
}
/* Try again */
result = cli_nt_setup_creds( conn->cli, get_sec_chan(),trust_passwd, &neg_flags, 2);
+
+ if (got_mutex)
+ secrets_named_mutex_release(lock_name);
}
if (!NT_STATUS_IS_OK(result)) {