/* return the time on a server. This does not require any authentication */ static time_t cli_servertime(const char *host, const struct sockaddr_storage *dest_ss, int *zone) { time_t ret = 0; struct cli_state *cli = NULL; NTSTATUS status; status = cli_connect_nb(host, dest_ss, 0, 0x20, lp_netbios_name(), SMB_SIGNING_DEFAULT, 0, &cli); if (!NT_STATUS_IS_OK(status)) { fprintf(stderr, _("Can't contact server %s. Error %s\n"), host, nt_errstr(status)); goto done; } status = smbXcli_negprot(cli->conn, cli->timeout, PROTOCOL_CORE, PROTOCOL_NT1); if (!NT_STATUS_IS_OK(status)) { fprintf(stderr, _("Protocol negotiation failed: %s\n"), nt_errstr(status)); goto done; } ret = cli_state_server_time(cli); if (zone) *zone = smb1cli_conn_server_time_zone(cli->conn); done: if (cli) { cli_shutdown(cli); } return ret; }
static void sync_child(char *name, int nm_type, char *workgroup, struct in_addr ip, bool local, bool servers, char *fname) { fstring unix_workgroup; struct cli_state *cli; uint32 local_type = local ? SV_TYPE_LOCAL_LIST_ONLY : 0; struct sockaddr_storage ss; NTSTATUS status; /* W2K DMB's return empty browse lists on port 445. Use 139. * Patch from Andy Levine [email protected]. */ in_addr_to_sockaddr_storage(&ss, ip); status = cli_connect_nb(name, &ss, NBT_SMB_PORT, nm_type, get_local_machine_name(), SMB_SIGNING_DEFAULT, 0, &cli); if (!NT_STATUS_IS_OK(status)) { return; } status = cli_negprot(cli, PROTOCOL_NT1); if (!NT_STATUS_IS_OK(status)) { cli_shutdown(cli); return; } if (!NT_STATUS_IS_OK(cli_session_setup(cli, "", "", 1, "", 0, workgroup))) { cli_shutdown(cli); return; } if (!NT_STATUS_IS_OK(cli_tree_connect(cli, "IPC$", "IPC", "", 1))) { cli_shutdown(cli); return; } /* All the cli_XX functions take UNIX character set. */ fstrcpy(unix_workgroup, cli->server_domain ? cli->server_domain : workgroup); /* Fetch a workgroup list. */ cli_NetServerEnum(cli, unix_workgroup, local_type|SV_TYPE_DOMAIN_ENUM, callback, NULL); /* Now fetch a server list. */ if (servers) { fstrcpy(unix_workgroup, workgroup); cli_NetServerEnum(cli, unix_workgroup, local?SV_TYPE_LOCAL_LIST_ONLY:SV_TYPE_ALL, callback, NULL); } cli_shutdown(cli); }
/* check to see if smbd is running on localhost by trying to open a connection then closing it */ bool smbd_running(void) { struct in_addr loopback_ip; NTSTATUS status; struct cli_state *cli; struct sockaddr_storage ss; loopback_ip.s_addr = htonl(INADDR_LOOPBACK); in_addr_to_sockaddr_storage(&ss, loopback_ip); status = cli_connect_nb("localhost", &ss, 0, 0x20, lp_netbios_name(), Undefined, 0, &cli); if (!NT_STATUS_IS_OK(status)) { return false; } cli_shutdown(cli); return True; }
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 SMBCSRV * SMBC_server_internal(TALLOC_CTX *ctx, SMBCCTX *context, bool connect_if_not_found, const char *server, uint16_t port, const char *share, char **pp_workgroup, char **pp_username, char **pp_password, bool *in_cache) { SMBCSRV *srv=NULL; char *workgroup = NULL; struct cli_state *c = NULL; const char *server_n = server; int is_ipc = (share != NULL && strcmp(share, "IPC$") == 0); uint32_t fs_attrs = 0; const char *username_used; NTSTATUS status; char *newserver, *newshare; int flags = 0; struct smbXcli_tcon *tcon = NULL; int signing_state = SMB_SIGNING_DEFAULT; ZERO_STRUCT(c); *in_cache = false; if (server[0] == 0) { errno = EPERM; return NULL; } /* Look for a cached connection */ srv = SMBC_find_server(ctx, context, server, share, pp_workgroup, pp_username, pp_password); /* * If we found a connection and we're only allowed one share per * server... */ if (srv && share != NULL && *share != '\0' && smbc_getOptionOneSharePerServer(context)) { /* * ... then if there's no current connection to the share, * connect to it. SMBC_find_server(), or rather the function * pointed to by context->get_cached_srv_fn which * was called by SMBC_find_server(), will have issued a tree * disconnect if the requested share is not the same as the * one that was already connected. */ /* * Use srv->cli->desthost and srv->cli->share instead of * server and share below to connect to the actual share, * i.e., a normal share or a referred share from * 'msdfs proxy' share. */ if (!cli_state_has_tcon(srv->cli)) { /* Ensure we have accurate auth info */ SMBC_call_auth_fn(ctx, context, smbXcli_conn_remote_name(srv->cli->conn), srv->cli->share, pp_workgroup, pp_username, pp_password); if (!*pp_workgroup || !*pp_username || !*pp_password) { errno = ENOMEM; cli_shutdown(srv->cli); srv->cli = NULL; smbc_getFunctionRemoveCachedServer(context)(context, srv); return NULL; } /* * We don't need to renegotiate encryption * here as the encryption context is not per * tid. */ status = cli_tree_connect(srv->cli, srv->cli->share, "?????", *pp_password, strlen(*pp_password)+1); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); cli_shutdown(srv->cli); srv->cli = NULL; smbc_getFunctionRemoveCachedServer(context)(context, srv); srv = NULL; } /* Determine if this share supports case sensitivity */ if (is_ipc) { DEBUG(4, ("IPC$ so ignore case sensitivity\n")); status = NT_STATUS_OK; } else { status = cli_get_fs_attr_info(c, &fs_attrs); } if (!NT_STATUS_IS_OK(status)) { DEBUG(4, ("Could not retrieve " "case sensitivity flag: %s.\n", nt_errstr(status))); /* * We can't determine the case sensitivity of * the share. We have no choice but to use the * user-specified case sensitivity setting. */ if (smbc_getOptionCaseSensitive(context)) { cli_set_case_sensitive(c, True); } else { cli_set_case_sensitive(c, False); } } else if (!is_ipc) { DEBUG(4, ("Case sensitive: %s\n", (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? "True" : "False"))); cli_set_case_sensitive( c, (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? True : False)); } /* * Regenerate the dev value since it's based on both * server and share */ if (srv) { const char *remote_name = smbXcli_conn_remote_name(srv->cli->conn); srv->dev = (dev_t)(str_checksum(remote_name) ^ str_checksum(srv->cli->share)); } } } /* If we have a connection... */ if (srv) { /* ... then we're done here. Give 'em what they came for. */ *in_cache = true; goto done; } /* If we're not asked to connect when a connection doesn't exist... */ if (! connect_if_not_found) { /* ... then we're done here. */ return NULL; } if (!*pp_workgroup || !*pp_username || !*pp_password) { errno = ENOMEM; return NULL; } DEBUG(4,("SMBC_server: server_n=[%s] server=[%s]\n", server_n, server)); DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server)); status = NT_STATUS_UNSUCCESSFUL; if (smbc_getOptionUseKerberos(context)) { flags |= CLI_FULL_CONNECTION_USE_KERBEROS; } if (smbc_getOptionFallbackAfterKerberos(context)) { flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS; } if (smbc_getOptionUseCCache(context)) { flags |= CLI_FULL_CONNECTION_USE_CCACHE; } if (smbc_getOptionUseNTHash(context)) { flags |= CLI_FULL_CONNECTION_USE_NT_HASH; } if (context->internal->smb_encryption_level != SMBC_ENCRYPTLEVEL_NONE) { signing_state = SMB_SIGNING_REQUIRED; } if (port == 0) { if (share == NULL || *share == '\0' || is_ipc) { /* * Try 139 first for IPC$ */ status = cli_connect_nb(server_n, NULL, NBT_SMB_PORT, 0x20, smbc_getNetbiosName(context), signing_state, flags, &c); } } if (!NT_STATUS_IS_OK(status)) { /* * No IPC$ or 139 did not work */ status = cli_connect_nb(server_n, NULL, port, 0x20, smbc_getNetbiosName(context), signing_state, flags, &c); } if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); return NULL; } cli_set_timeout(c, smbc_getTimeout(context)); status = smbXcli_negprot(c->conn, c->timeout, lp_client_min_protocol(), lp_client_max_protocol()); if (!NT_STATUS_IS_OK(status)) { cli_shutdown(c); errno = ETIMEDOUT; return NULL; } if (smbXcli_conn_protocol(c->conn) >= PROTOCOL_SMB2_02) { /* Ensure we ask for some initial credits. */ smb2cli_conn_set_max_credits(c->conn, DEFAULT_SMB2_MAX_CREDITS); } username_used = *pp_username; if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used, *pp_password, strlen(*pp_password), *pp_password, strlen(*pp_password), *pp_workgroup))) { /* Failed. Try an anonymous login, if allowed by flags. */ username_used = ""; if (smbc_getOptionNoAutoAnonymousLogin(context) || !NT_STATUS_IS_OK(cli_session_setup(c, username_used, *pp_password, 1, *pp_password, 0, *pp_workgroup))) { cli_shutdown(c); errno = EPERM; return NULL; } } DEBUG(4,(" session setup ok\n")); /* here's the fun part....to support 'msdfs proxy' shares (on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL here before trying to connect to the original share. cli_check_msdfs_proxy() will fail if it is a normal share. */ if (smbXcli_conn_dfs_supported(c->conn) && cli_check_msdfs_proxy(ctx, c, share, &newserver, &newshare, /* FIXME: cli_check_msdfs_proxy() does not support smbc_smb_encrypt_level type */ context->internal->smb_encryption_level ? true : false, *pp_username, *pp_password, *pp_workgroup)) { cli_shutdown(c); srv = SMBC_server_internal(ctx, context, connect_if_not_found, newserver, port, newshare, pp_workgroup, pp_username, pp_password, in_cache); TALLOC_FREE(newserver); TALLOC_FREE(newshare); return srv; } /* must be a normal share */ status = cli_tree_connect(c, share, "?????", *pp_password, strlen(*pp_password)+1); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); cli_shutdown(c); return NULL; } DEBUG(4,(" tconx ok\n")); if (smbXcli_conn_protocol(c->conn) >= PROTOCOL_SMB2_02) { tcon = c->smb2.tcon; } else { tcon = c->smb1.tcon; } /* Determine if this share supports case sensitivity */ if (is_ipc) { DEBUG(4, ("IPC$ so ignore case sensitivity\n")); status = NT_STATUS_OK; } else { status = cli_get_fs_attr_info(c, &fs_attrs); } if (!NT_STATUS_IS_OK(status)) { DEBUG(4, ("Could not retrieve case sensitivity flag: %s.\n", nt_errstr(status))); /* * We can't determine the case sensitivity of the share. We * have no choice but to use the user-specified case * sensitivity setting. */ if (smbc_getOptionCaseSensitive(context)) { cli_set_case_sensitive(c, True); } else { cli_set_case_sensitive(c, False); } } else if (!is_ipc) { DEBUG(4, ("Case sensitive: %s\n", (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? "True" : "False"))); smbXcli_tcon_set_fs_attributes(tcon, fs_attrs); } if (context->internal->smb_encryption_level) { /* Attempt UNIX smb encryption. */ if (!NT_STATUS_IS_OK(cli_force_encryption(c, username_used, *pp_password, *pp_workgroup))) { /* * context->smb_encryption_level == 1 * means don't fail if encryption can't be negotiated, * == 2 means fail if encryption can't be negotiated. */ DEBUG(4,(" SMB encrypt failed\n")); if (context->internal->smb_encryption_level == 2) { cli_shutdown(c); errno = EPERM; return NULL; } } DEBUG(4,(" SMB encrypt ok\n")); } /* * Ok, we have got a nice connection * Let's allocate a server structure. */ srv = SMB_MALLOC_P(SMBCSRV); if (!srv) { cli_shutdown(c); errno = ENOMEM; return NULL; } ZERO_STRUCTP(srv); DLIST_ADD(srv->cli, c); srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share)); srv->no_pathinfo = False; srv->no_pathinfo2 = False; srv->no_pathinfo3 = False; srv->no_nt_session = False; done: if (!pp_workgroup || !*pp_workgroup || !**pp_workgroup) { workgroup = talloc_strdup(ctx, smbc_getWorkgroup(context)); } else { workgroup = *pp_workgroup; } if(!workgroup) { if (c != NULL) { cli_shutdown(c); } SAFE_FREE(srv); return NULL; } /* set the credentials to make DFS work */ smbc_set_credentials_with_fallback(context, workgroup, *pp_username, *pp_password); return srv; }
NTSTATUS remote_password_change(const char *remote_machine, const char *user_name, const char *old_passwd, const char *new_passwd, char **err_str) { struct cli_state *cli = NULL; struct rpc_pipe_client *pipe_hnd = NULL; char *user, *domain, *p; NTSTATUS result; bool pass_must_change = False; user = talloc_strdup(talloc_tos(), user_name); SMB_ASSERT(user != NULL); domain = talloc_strdup(talloc_tos(), ""); SMB_ASSERT(domain != NULL); /* allow usernames of the form domain\\user or domain/user */ if ((p = strchr_m(user,'\\')) || (p = strchr_m(user,'/')) || (p = strchr_m(user,*lp_winbind_separator()))) { *p = 0; domain = user; user = p+1; } *err_str = NULL; result = cli_connect_nb(remote_machine, NULL, 0, 0x20, NULL, SMB_SIGNING_DEFAULT, 0, &cli); if (!NT_STATUS_IS_OK(result)) { if (asprintf(err_str, "Unable to connect to SMB server on " "machine %s. Error was : %s.\n", remote_machine, nt_errstr(result))==-1) { *err_str = NULL; } return result; } result = cli_negprot(cli, PROTOCOL_NT1); if (!NT_STATUS_IS_OK(result)) { if (asprintf(err_str, "machine %s rejected the negotiate " "protocol. Error was : %s.\n", remote_machine, nt_errstr(result)) == -1) { *err_str = NULL; } cli_shutdown(cli); return result; } /* Given things like SMB signing, restrict anonymous and the like, try an authenticated connection first */ result = cli_session_setup(cli, user_name, old_passwd, strlen(old_passwd)+1, old_passwd, strlen(old_passwd)+1, ""); if (!NT_STATUS_IS_OK(result)) { /* Password must change or Password expired are the only valid * error conditions here from where we can proceed, the rest like * account locked out or logon failure will lead to errors later * anyway */ if (!NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) && !NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED)) { if (asprintf(err_str, "Could not connect to machine %s: " "%s\n", remote_machine, nt_errstr(result)) == -1) { *err_str = NULL; } cli_shutdown(cli); return result; } pass_must_change = True; /* * We should connect as the anonymous user here, in case * the server has "must change password" checked... * Thanks to <*****@*****.**> for this fix. */ result = cli_session_setup(cli, "", "", 0, "", 0, ""); if (!NT_STATUS_IS_OK(result)) { if (asprintf(err_str, "machine %s rejected the session " "setup. Error was : %s.\n", remote_machine, nt_errstr(result)) == -1) { *err_str = NULL; } cli_shutdown(cli); return result; } result = cli_init_creds(cli, "", "", NULL); if (!NT_STATUS_IS_OK(result)) { cli_shutdown(cli); return result; } } else { result = cli_init_creds(cli, user, domain, old_passwd); if (!NT_STATUS_IS_OK(result)) { cli_shutdown(cli); return result; } } result = cli_tree_connect(cli, "IPC$", "IPC", "", 1); if (!NT_STATUS_IS_OK(result)) { if (asprintf(err_str, "machine %s rejected the tconX on the " "IPC$ share. Error was : %s.\n", remote_machine, nt_errstr(result))) { *err_str = NULL; } cli_shutdown(cli); return result; } /* Try not to give the password away too easily */ if (!pass_must_change) { result = cli_rpc_pipe_open_ntlmssp(cli, &ndr_table_samr.syntax_id, NCACN_NP, DCERPC_AUTH_LEVEL_PRIVACY, domain, user, old_passwd, &pipe_hnd); } else { /* * If the user password must be changed the ntlmssp bind will * fail the same way as the session setup above did. The * difference ist that with a pipe bind we don't get a good * error message, the result will be that the rpc call below * will just fail. So we do it anonymously, there's no other * way. */ result = cli_rpc_pipe_open_noauth( cli, &ndr_table_samr.syntax_id, &pipe_hnd); } if (!NT_STATUS_IS_OK(result)) { if (lp_client_lanman_auth()) { /* Use the old RAP method. */ if (!cli_oem_change_password(cli, user_name, new_passwd, old_passwd)) { result = cli_nt_error(cli); if (asprintf(err_str, "machine %s rejected the " "password change: Error was : %s.\n", remote_machine, nt_errstr(result)) == -1) { *err_str = NULL; } cli_shutdown(cli); return result; } } else { if (asprintf(err_str, "SAMR connection to machine %s " "failed. Error was %s, but LANMAN password " "changes are disabled\n", remote_machine, nt_errstr(result)) == -1) { *err_str = NULL; } cli_shutdown(cli); return result; } } result = rpccli_samr_chgpasswd_user2(pipe_hnd, talloc_tos(), user_name, new_passwd, old_passwd); if (NT_STATUS_IS_OK(result)) { /* Great - it all worked! */ cli_shutdown(cli); return NT_STATUS_OK; } else if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) { /* it failed, but for reasons such as wrong password, too short etc ... */ if (asprintf(err_str, "machine %s rejected the password change: " "Error was : %s.\n", remote_machine, get_friendly_nt_error_msg(result)) == -1) { *err_str = NULL; } cli_shutdown(cli); return result; } /* OK, that failed, so try again... */ TALLOC_FREE(pipe_hnd); /* Try anonymous NTLMSSP... */ result = cli_init_creds(cli, "", "", NULL); if (!NT_STATUS_IS_OK(result)) { cli_shutdown(cli); return result; } result = NT_STATUS_UNSUCCESSFUL; /* OK, this is ugly, but... try an anonymous pipe. */ result = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id, &pipe_hnd); if ( NT_STATUS_IS_OK(result) && (NT_STATUS_IS_OK(result = rpccli_samr_chgpasswd_user2( pipe_hnd, talloc_tos(), user_name, new_passwd, old_passwd)))) { /* Great - it all worked! */ cli_shutdown(cli); return NT_STATUS_OK; } else { if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) { /* it failed, but again it was due to things like new password too short */ if (asprintf(err_str, "machine %s rejected the " "(anonymous) password change: Error was : " "%s.\n", remote_machine, get_friendly_nt_error_msg(result)) == -1) { *err_str = NULL; } cli_shutdown(cli); return result; } /* We have failed to change the user's password, and we think the server just might not support SAMR password changes, so fall back */ if (lp_client_lanman_auth()) { /* Use the old RAP method. */ if (cli_oem_change_password(cli, user_name, new_passwd, old_passwd)) { /* SAMR failed, but the old LanMan protocol worked! */ cli_shutdown(cli); return NT_STATUS_OK; } result = cli_nt_error(cli); if (asprintf(err_str, "machine %s rejected the password " "change: Error was : %s.\n", remote_machine, nt_errstr(result)) == -1) { *err_str = NULL; } cli_shutdown(cli); return result; } else { if (asprintf(err_str, "SAMR connection to machine %s " "failed. Error was %s, but LANMAN password " "changes are disabled\n", nt_errstr(result), remote_machine) == -1) { *err_str = NULL; } cli_shutdown(cli); return NT_STATUS_UNSUCCESSFUL; } } }
static NTSTATUS do_connect(TALLOC_CTX *ctx, const char *server, const char *share, const struct user_auth_info *auth_info, bool show_sessetup, bool force_encrypt, int max_protocol, int port, int name_type, struct cli_state **pcli) { struct cli_state *c = NULL; char *servicename; char *sharename; char *newserver, *newshare; const char *username; const char *password; NTSTATUS status; int flags = 0; /* make a copy so we don't modify the global string 'service' */ servicename = talloc_strdup(ctx,share); if (!servicename) { return NT_STATUS_NO_MEMORY; } sharename = servicename; if (*sharename == '\\') { sharename += 2; if (server == NULL) { server = sharename; } sharename = strchr_m(sharename,'\\'); if (!sharename) { return NT_STATUS_NO_MEMORY; } *sharename = 0; sharename++; } if (server == NULL) { return NT_STATUS_INVALID_PARAMETER; } if (get_cmdline_auth_info_use_kerberos(auth_info)) { flags |= CLI_FULL_CONNECTION_USE_KERBEROS; } if (get_cmdline_auth_info_fallback_after_kerberos(auth_info)) { flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS; } if (get_cmdline_auth_info_use_ccache(auth_info)) { flags |= CLI_FULL_CONNECTION_USE_CCACHE; } status = cli_connect_nb( server, NULL, port, name_type, NULL, get_cmdline_auth_info_signing_state(auth_info), flags, &c); if (!NT_STATUS_IS_OK(status)) { d_printf("Connection to %s failed (Error %s)\n", server, nt_errstr(status)); return status; } if (max_protocol == 0) { max_protocol = PROTOCOL_NT1; } DEBUG(4,(" session request ok\n")); status = cli_negprot(c, max_protocol); if (!NT_STATUS_IS_OK(status)) { d_printf("protocol negotiation failed: %s\n", nt_errstr(status)); cli_shutdown(c); return status; } username = get_cmdline_auth_info_username(auth_info); password = get_cmdline_auth_info_password(auth_info); status = cli_session_setup(c, username, password, strlen(password), password, strlen(password), lp_workgroup()); if (!NT_STATUS_IS_OK(status)) { /* If a password was not supplied then * try again with a null username. */ if (password[0] || !username[0] || get_cmdline_auth_info_use_kerberos(auth_info) || !NT_STATUS_IS_OK(status = cli_session_setup(c, "", "", 0, "", 0, lp_workgroup()))) { d_printf("session setup failed: %s\n", nt_errstr(status)); if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) d_printf("did you forget to run kinit?\n"); cli_shutdown(c); return status; } d_printf("Anonymous login successful\n"); status = cli_init_creds(c, "", lp_workgroup(), ""); } else { status = cli_init_creds(c, username, lp_workgroup(), password); } if (!NT_STATUS_IS_OK(status)) { DEBUG(10,("cli_init_creds() failed: %s\n", nt_errstr(status))); cli_shutdown(c); return status; } if ( show_sessetup ) { if (*c->server_domain) { DEBUG(0,("Domain=[%s] OS=[%s] Server=[%s]\n", c->server_domain,c->server_os,c->server_type)); } else if (*c->server_os || *c->server_type) { DEBUG(0,("OS=[%s] Server=[%s]\n", c->server_os,c->server_type)); } } DEBUG(4,(" session setup ok\n")); /* here's the fun part....to support 'msdfs proxy' shares (on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL here before trying to connect to the original share. cli_check_msdfs_proxy() will fail if it is a normal share. */ if ((cli_state_capabilities(c) & CAP_DFS) && cli_check_msdfs_proxy(ctx, c, sharename, &newserver, &newshare, force_encrypt, username, password, lp_workgroup())) { cli_shutdown(c); return do_connect(ctx, newserver, newshare, auth_info, false, force_encrypt, max_protocol, port, name_type, pcli); } /* must be a normal share */ status = cli_tree_connect(c, sharename, "?????", password, strlen(password)+1); if (!NT_STATUS_IS_OK(status)) { d_printf("tree connect failed: %s\n", nt_errstr(status)); cli_shutdown(c); return status; } if (force_encrypt) { status = cli_cm_force_encryption(c, username, password, lp_workgroup(), sharename); if (!NT_STATUS_IS_OK(status)) { cli_shutdown(c); return status; } } DEBUG(4,(" tconx ok\n")); *pcli = c; return NT_STATUS_OK; }
/***************************************************** return a connection to a server *******************************************************/ static struct cli_state *connect_one(char *share, int snum) { struct cli_state *c; char *server_n; fstring server; fstring myname; static int count; NTSTATUS status; int flags = 0; fstrcpy(server,share+2); share = strchr_m(server,'\\'); if (!share) return NULL; *share = 0; share++; server_n = server; slprintf(myname,sizeof(myname), "lock-%lu-%u", (unsigned long)getpid(), count++); /* have to open a new connection */ if (use_kerberos) { flags |= CLI_FULL_CONNECTION_USE_KERBEROS; } if (use_oplocks) { flags |= CLI_FULL_CONNECTION_OPLOCKS; } status = cli_connect_nb(server_n, NULL, 0, 0x20, myname, SMB_SIGNING_DEFAULT, flags, &c); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Connection to %s failed. Error %s\n", server_n, nt_errstr(status))); return NULL; } status = cli_negprot(c, PROTOCOL_NT1); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("protocol negotiation failed: %s\n", nt_errstr(status))); cli_shutdown(c); return NULL; } if (!got_pass) { char *pass = getpass("Password: "******"session setup failed: %s\n", nt_errstr(status))); return NULL; } /* * These next two lines are needed to emulate * old client behaviour for people who have * scripts based on client output. * QUESTION ? Do we want to have a 'client compatibility * mode to turn these on/off ? JRA. */ if (*c->server_domain || *c->server_os || *c->server_type) DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n", c->server_domain,c->server_os,c->server_type)); DEBUG(4,(" session setup ok\n")); status = cli_tcon_andx(c, share, "?????", password[snum], strlen(password[snum])+1); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("tree connect failed: %s\n", nt_errstr(status))); cli_shutdown(c); return NULL; } DEBUG(4,(" tconx ok\n")); return c; }