static bool cli_dfs_check_error(struct cli_state *cli, NTSTATUS expected, NTSTATUS status) { /* only deal with DS when we negotiated NT_STATUS codes and UNICODE */ if (!(cli_state_capabilities(cli) & CAP_UNICODE)) { return false; } if (!(cli_state_capabilities(cli) & CAP_STATUS32)) { return false; } if (NT_STATUS_EQUAL(status, expected)) { return true; } return false; }
int SMBC_fstatvfs_ctx(SMBCCTX *context, SMBCFILE *file, struct statvfs *st) { unsigned long flags = 0; uint32 fs_attrs = 0; struct cli_state *cli = file->srv->cli; /* Initialize all fields (at least until we actually use them) */ memset(st, 0, sizeof(*st)); /* * The state of each flag is such that the same bits are unset as * would typically be unset on a local file system on a POSIX OS. Thus * the bit is on, for example, only for case-insensitive file systems * since most POSIX file systems are case sensitive and fstatvfs() * would typically return zero in these bits on such a local file * system. */ /* See if the server has UNIX CIFS support */ if (! SERVER_HAS_UNIX_CIFS(cli)) { uint64_t total_allocation_units; uint64_t caller_allocation_units; uint64_t actual_allocation_units; uint64_t sectors_per_allocation_unit; uint64_t bytes_per_sector; NTSTATUS status; /* Nope. If size data is available... */ status = cli_get_fs_full_size_info(cli, &total_allocation_units, &caller_allocation_units, &actual_allocation_units, §ors_per_allocation_unit, &bytes_per_sector); if (NT_STATUS_IS_OK(status)) { /* ... then provide it */ st->f_bsize = (unsigned long) bytes_per_sector; #if HAVE_FRSIZE st->f_frsize = (unsigned long) sectors_per_allocation_unit; #endif st->f_blocks = (fsblkcnt_t) total_allocation_units; st->f_bfree = (fsblkcnt_t) actual_allocation_units; } flags |= SMBC_VFS_FEATURE_NO_UNIXCIFS; } else { uint32 optimal_transfer_size; uint32 block_size; uint64_t total_blocks; uint64_t blocks_available; uint64_t user_blocks_available; uint64_t total_file_nodes; uint64_t free_file_nodes; uint64_t fs_identifier; NTSTATUS status; /* Has UNIXCIFS. If POSIX filesystem info is available... */ status = cli_get_posix_fs_info(cli, &optimal_transfer_size, &block_size, &total_blocks, &blocks_available, &user_blocks_available, &total_file_nodes, &free_file_nodes, &fs_identifier); if (NT_STATUS_IS_OK(status)) { /* ... then what's provided here takes precedence. */ st->f_bsize = (unsigned long) block_size; st->f_blocks = (fsblkcnt_t) total_blocks; st->f_bfree = (fsblkcnt_t) blocks_available; st->f_bavail = (fsblkcnt_t) user_blocks_available; st->f_files = (fsfilcnt_t) total_file_nodes; st->f_ffree = (fsfilcnt_t) free_file_nodes; #if HAVE_FSID_INT st->f_fsid = (unsigned long) fs_identifier; #endif } } /* See if the share is case sensitive */ if (!NT_STATUS_IS_OK(cli_get_fs_attr_info(cli, &fs_attrs))) { /* * 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)) { flags |= SMBC_VFS_FEATURE_CASE_INSENSITIVE; } } else { if (! (fs_attrs & FILE_CASE_SENSITIVE_SEARCH)) { flags |= SMBC_VFS_FEATURE_CASE_INSENSITIVE; } } /* See if DFS is supported */ if ((cli_state_capabilities(cli) & CAP_DFS) && cli->dfsroot) { flags |= SMBC_VFS_FEATURE_DFS; } #if HAVE_STATVFS_F_FLAG st->f_flag = flags; #elif HAVE_STATVFS_F_FLAGS st->f_flags = flags; #endif return 0; }
/* * Get info from an SMB server on a file. Use a qpathinfo call first * and if that fails, use getatr, as Win95 sometimes refuses qpathinfo */ bool SMBC_getatr(SMBCCTX * context, SMBCSRV *srv, const char *path, uint16 *mode, off_t *size, struct timespec *create_time_ts, struct timespec *access_time_ts, struct timespec *write_time_ts, struct timespec *change_time_ts, SMB_INO_T *ino) { char *fixedpath = NULL; char *targetpath = NULL; struct cli_state *targetcli = NULL; time_t write_time; TALLOC_CTX *frame = talloc_stackframe(); NTSTATUS status; if (!context || !context->internal->initialized) { errno = EINVAL; TALLOC_FREE(frame); return False; } /* path fixup for . and .. */ if (strequal(path, ".") || strequal(path, "..")) { fixedpath = talloc_strdup(frame, "\\"); if (!fixedpath) { errno = ENOMEM; TALLOC_FREE(frame); return False; } } else { fixedpath = talloc_strdup(frame, path); if (!fixedpath) { errno = ENOMEM; TALLOC_FREE(frame); return False; } trim_string(fixedpath, NULL, "\\.."); trim_string(fixedpath, NULL, "\\."); } DEBUG(4,("SMBC_getatr: sending qpathinfo\n")); status = cli_resolve_path(frame, "", context->internal->auth_info, srv->cli, fixedpath, &targetcli, &targetpath); if (!NT_STATUS_IS_OK(status)) { d_printf("Couldn't resolve %s\n", path); errno = ENOENT; TALLOC_FREE(frame); return False; } if (!srv->no_pathinfo2 && NT_STATUS_IS_OK(cli_qpathinfo2(targetcli, targetpath, create_time_ts, access_time_ts, write_time_ts, change_time_ts, size, mode, ino))) { TALLOC_FREE(frame); return True; } /* if this is NT then don't bother with the getatr */ if (cli_state_capabilities(targetcli) & CAP_NT_SMBS) { errno = EPERM; TALLOC_FREE(frame); return False; } if (NT_STATUS_IS_OK(cli_getatr(targetcli, targetpath, mode, size, &write_time))) { struct timespec w_time_ts; w_time_ts = convert_time_t_to_timespec(write_time); if (write_time_ts != NULL) { *write_time_ts = w_time_ts; } if (create_time_ts != NULL) { *create_time_ts = w_time_ts; } if (access_time_ts != NULL) { *access_time_ts = w_time_ts; } if (change_time_ts != NULL) { *change_time_ts = w_time_ts; } srv->no_pathinfo2 = True; TALLOC_FREE(frame); return True; } errno = EPERM; TALLOC_FREE(frame); return False; }
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; }