mirror of
https://github.com/samba-team/samba.git
synced 2025-01-03 01:18:10 +03:00
Compare commits
52 Commits
04e0fb9b2d
...
c7839facdb
Author | SHA1 | Date | |
---|---|---|---|
|
c7839facdb | ||
|
31eac22e08 | ||
|
9a80e4e27a | ||
|
0bb35e2461 | ||
|
800363a2cd | ||
|
5052be5162 | ||
|
56e3a8e3f8 | ||
|
0fc8d8bfc5 | ||
|
99fa20b418 | ||
|
82fd2230a8 | ||
|
88abb775dc | ||
|
10512eebec | ||
|
c0bbeded93 | ||
|
9550f4370e | ||
|
e571da800f | ||
|
88f582d3ca | ||
|
bd30c9c128 | ||
|
3ab6a9a9bf | ||
|
6e9c6dd6d6 | ||
|
dade2981c3 | ||
|
142a78eb24 | ||
|
c31e7aecba | ||
|
0ab88a1fe7 | ||
|
f8994bc289 | ||
|
01f15d0e5e | ||
|
48464c66f8 | ||
|
774005be76 | ||
|
3b38639330 | ||
|
45f50eee06 | ||
|
ea597019aa | ||
|
bea01e845c | ||
|
7430831f88 | ||
|
eecdd0fb59 | ||
|
4b3b283b1f | ||
|
47c8d9b62a | ||
|
3dc89edf9c | ||
|
6c8d817f00 | ||
|
4f727b919a | ||
|
7c4d1f9de1 | ||
|
542cf01bfe | ||
|
fd5562bee7 | ||
|
72ff0312d1 | ||
|
83582d417c | ||
|
83bb0c4ae6 | ||
|
804568a1d7 | ||
|
282a5778fb | ||
|
3a5068f294 | ||
|
8a64775334 | ||
|
63f0b59cbe | ||
|
ccb6e6634a | ||
|
5d19591e75 | ||
|
b80afa1ca0 |
@ -232,11 +232,10 @@ static int ldb_dn_escape_internal(char *dst, const char *src, int len)
|
||||
case '\0': {
|
||||
/* any others get \XX form */
|
||||
unsigned char v;
|
||||
const char *hexbytes = "0123456789ABCDEF";
|
||||
v = (const unsigned char)c;
|
||||
*d++ = '\\';
|
||||
*d++ = hexbytes[v>>4];
|
||||
*d++ = hexbytes[v&0xF];
|
||||
*d++ = hexchars_upper[v>>4];
|
||||
*d++ = hexchars_upper[v&0xF];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -131,8 +131,6 @@ inet_pton6(src, dst)
|
||||
const char *src;
|
||||
unsigned char *dst;
|
||||
{
|
||||
static const char xdigits_l[] = "0123456789abcdef",
|
||||
xdigits_u[] = "0123456789ABCDEF";
|
||||
unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
|
||||
const char *xdigits, *curtok;
|
||||
int ch, saw_xdigit;
|
||||
@ -151,8 +149,8 @@ inet_pton6(src, dst)
|
||||
while ((ch = *src++) != '\0') {
|
||||
const char *pch;
|
||||
|
||||
if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
|
||||
pch = strchr((xdigits = xdigits_u), ch);
|
||||
if ((pch = strchr((xdigits = hexchars_lower), ch)) == NULL)
|
||||
pch = strchr((xdigits = hexchars_upper), ch);
|
||||
if (pch != NULL) {
|
||||
val <<= 4;
|
||||
val |= (pch - xdigits);
|
||||
|
@ -1231,3 +1231,6 @@ int rep_renameat2(int __oldfd, const char *__old, int __newfd,
|
||||
return renameat(__oldfd, __old, __newfd, __new);
|
||||
}
|
||||
#endif /* ! HAVE_RENAMEAT2 */
|
||||
|
||||
const char hexchars_lower[] = "0123456789abcdef";
|
||||
const char hexchars_upper[] = "0123456789ABCDEF";
|
||||
|
@ -1101,6 +1101,9 @@ static inline bool hex_byte(const char *in, uint8_t *out)
|
||||
return ok;
|
||||
}
|
||||
|
||||
extern const char hexchars_lower[];
|
||||
extern const char hexchars_upper[];
|
||||
|
||||
/* Needed for Solaris atomic_add_XX functions. */
|
||||
#if defined(HAVE_SYS_ATOMIC_H)
|
||||
#include <sys/atomic.h>
|
||||
|
@ -832,9 +832,8 @@ static void fmtint(char *buffer, size_t *currlen, size_t maxlen,
|
||||
if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
|
||||
|
||||
do {
|
||||
convert[place++] =
|
||||
(caps? "0123456789ABCDEF":"0123456789abcdef")
|
||||
[uvalue % (unsigned)base ];
|
||||
convert[place++] = (caps ? hex_upper
|
||||
: hex_lower)[uvalue % (unsigned)base];
|
||||
uvalue = (uvalue / (unsigned)base );
|
||||
} while(uvalue && (place < sizeof(convert)));
|
||||
if (place == sizeof(convert)) place--;
|
||||
@ -1028,8 +1027,8 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
|
||||
idx = (int) ((temp -intpart +0.05)* 10.0);
|
||||
/* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */
|
||||
/* printf ("%llf, %f, %x\n", temp, intpart, idx); */
|
||||
iconvert[iplace++] =
|
||||
(caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
|
||||
iconvert[iplace++] = (caps ? hexchars_upper
|
||||
: hexchars_lower)[idx];
|
||||
} while (intpart && (iplace < 311));
|
||||
if (iplace == 311) iplace--;
|
||||
iconvert[iplace] = 0;
|
||||
@ -1043,8 +1042,8 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
|
||||
idx = (int) ((temp -fracpart +0.05)* 10.0);
|
||||
/* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */
|
||||
/* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */
|
||||
fconvert[fplace++] =
|
||||
(caps? "0123456789ABCDEF":"0123456789abcdef")[idx];
|
||||
fconvert[fplace++] = (caps ? hexchars_upper
|
||||
: hexchars_lower)[idx];
|
||||
} while(fracpart && (fplace < 311));
|
||||
if (fplace == 311) fplace--;
|
||||
}
|
||||
|
@ -652,54 +652,12 @@ void samba_tevent_set_debug(struct tevent_context *ev, const char *name);
|
||||
|
||||
static inline char nybble_to_hex_lower(uint8_t val)
|
||||
{
|
||||
uint8_t nybble = val & 0xf;
|
||||
|
||||
switch (nybble) {
|
||||
case 0x0: case 0x1: case 0x2: case 0x3: case 0x4:
|
||||
case 0x5: case 0x6: case 0x7: case 0x8: case 0x9:
|
||||
return '0' + nybble;
|
||||
case 0xa:
|
||||
return 'a';
|
||||
case 0xb:
|
||||
return 'b';
|
||||
case 0xc:
|
||||
return 'c';
|
||||
case 0xd:
|
||||
return 'd';
|
||||
case 0xe:
|
||||
return 'e';
|
||||
case 0xf:
|
||||
return 'f';
|
||||
}
|
||||
|
||||
/* unreachable */
|
||||
return '\0';
|
||||
return hexchars_lower[val & 0xf];
|
||||
}
|
||||
|
||||
static inline char nybble_to_hex_upper(uint8_t val)
|
||||
{
|
||||
uint8_t nybble = val & 0xf;
|
||||
|
||||
switch (nybble) {
|
||||
case 0x0: case 0x1: case 0x2: case 0x3: case 0x4:
|
||||
case 0x5: case 0x6: case 0x7: case 0x8: case 0x9:
|
||||
return '0' + nybble;
|
||||
case 0xa:
|
||||
return 'A';
|
||||
case 0xb:
|
||||
return 'B';
|
||||
case 0xc:
|
||||
return 'C';
|
||||
case 0xd:
|
||||
return 'D';
|
||||
case 0xe:
|
||||
return 'E';
|
||||
case 0xf:
|
||||
return 'F';
|
||||
}
|
||||
|
||||
/* unreachable */
|
||||
return '\0';
|
||||
return hexchars_upper[val & 0xf];
|
||||
}
|
||||
|
||||
#endif /* _SAMBA_UTIL_H_ */
|
||||
|
@ -34,7 +34,7 @@
|
||||
struct security_acl *make_sec_acl(
|
||||
TALLOC_CTX *ctx,
|
||||
enum security_acl_revision revision,
|
||||
int num_aces,
|
||||
size_t num_aces,
|
||||
const struct security_ace *ace_list)
|
||||
{
|
||||
struct security_acl *dst;
|
||||
|
@ -26,7 +26,7 @@
|
||||
struct security_acl *make_sec_acl(
|
||||
TALLOC_CTX *ctx,
|
||||
enum security_acl_revision revision,
|
||||
int num_aces,
|
||||
size_t num_aces,
|
||||
const struct security_ace *ace_list);
|
||||
|
||||
#endif /*_SECACL_H_*/
|
||||
|
@ -399,7 +399,10 @@ static NTSTATUS security_descriptor_acl_del(struct security_descriptor *sd,
|
||||
}
|
||||
|
||||
/* there can be multiple ace's for one trustee */
|
||||
for (i=0;i<acl->num_aces;i++) {
|
||||
|
||||
i = 0;
|
||||
|
||||
while (i<acl->num_aces) {
|
||||
if (dom_sid_equal(trustee, &acl->aces[i].trustee)) {
|
||||
ARRAY_DEL_ELEMENT(acl->aces, i, acl->num_aces);
|
||||
acl->num_aces--;
|
||||
@ -407,7 +410,8 @@ static NTSTATUS security_descriptor_acl_del(struct security_descriptor *sd,
|
||||
acl->aces = NULL;
|
||||
}
|
||||
found = true;
|
||||
--i;
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,7 @@ Example: MYNAME</string>
|
||||
<string id="POL_3B93FDE1_6461_572C_AD2E_6AEEAE4EA949_Help">This sets the NetBIOS scope that Samba will operate under. This should not be set unless every machine on your LAN also sets this value.</string>
|
||||
<string id="POL_E633B0BE_9CF3_5D79_A9F1_CB782C82A19C">prefork backoff increment</string>
|
||||
<string id="POL_E633B0BE_9CF3_5D79_A9F1_CB782C82A19C_Help">This option specifies the number of seconds added to the delay before a prefork master or worker process is restarted. The restart is initially zero, the prefork backoff increment is added to the delay on each restart up to the value specified by "prefork maximum backoff".
|
||||
Additionally the the backoff for an individual service by using "prefork backoff increment: service name" i.e. "prefork backoff increment:ldap = 2" to set the backoff increment to 2.
|
||||
Additionally the backoff for an individual service by using "prefork backoff increment: service name" i.e. "prefork backoff increment:ldap = 2" to set the backoff increment to 2.
|
||||
If the backoff increment is 2 and the maximum backoff is 5. There will be a zero second delay for the first restart. A two second delay for the second restart. A four second delay for the third and any subsequent restarts</string>
|
||||
<string id="POL_B4E848BD_E606_552C_8C9F_3F8CC1AEF191">prefork children</string>
|
||||
<string id="POL_B4E848BD_E606_552C_8C9F_3F8CC1AEF191_Help">This option controls the number of worker processes that are started for each service when prefork process model is enabled (see samba 8 -M) The prefork children are only started for those services that support prefork (currently ldap, kdc and netlogon). For processes that don't support preforking all requests are handled by a single process for that service.
|
||||
|
@ -1726,19 +1726,23 @@ static enum ndr_err_code ndr_push_relative_ptr2(struct ndr_push *ndr, const void
|
||||
if (p == NULL) {
|
||||
return NDR_ERR_SUCCESS;
|
||||
}
|
||||
save_offset = ndr->offset;
|
||||
if (ndr->offset < ndr->relative_base_offset) {
|
||||
return ndr_push_error(
|
||||
ndr,
|
||||
NDR_ERR_BUFSIZE,
|
||||
"ndr_push_relative_ptr2 ndr->offset(%" PRIu32 ") "
|
||||
"< ndr->relative_base_offset(%" PRIu32 ")",
|
||||
ndr->offset,
|
||||
ndr->relative_base_offset);
|
||||
}
|
||||
NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
|
||||
if (ptr_offset > ndr->offset) {
|
||||
return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
|
||||
"ndr_push_relative_ptr2 ptr_offset(%"PRIu32") > ndr->offset(%"PRIu32")",
|
||||
ptr_offset, ndr->offset);
|
||||
}
|
||||
save_offset = ndr->offset;
|
||||
ndr->offset = ptr_offset;
|
||||
if (save_offset < ndr->relative_base_offset) {
|
||||
return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
|
||||
"ndr_push_relative_ptr2 save_offset(%"PRIu32") < ndr->relative_base_offset(%"PRIu32")",
|
||||
save_offset, ndr->relative_base_offset);
|
||||
}
|
||||
NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, save_offset - ndr->relative_base_offset));
|
||||
ndr->offset = save_offset;
|
||||
return NDR_ERR_SUCCESS;
|
||||
@ -2014,6 +2018,14 @@ _PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr1(struct ndr_pull *ndr, const vo
|
||||
{
|
||||
enum ndr_err_code ret;
|
||||
rel_offset += ndr->relative_base_offset;
|
||||
if (rel_offset < ndr->relative_base_offset) {
|
||||
return ndr_pull_error(ndr,
|
||||
NDR_ERR_INVALID_POINTER,
|
||||
"Overflow rel_offset=%" PRIu32 " + "
|
||||
"relative_base_offset=%" PRIu32,
|
||||
rel_offset,
|
||||
ndr->relative_base_offset);
|
||||
}
|
||||
if (rel_offset > ndr->data_size) {
|
||||
return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
|
||||
"ndr_pull_relative_ptr1 rel_offset(%"PRIu32") > ndr->data_size(%"PRIu32")",
|
||||
|
@ -713,6 +713,15 @@ NTSTATUS safe_symlink_target_path(TALLOC_CTX *mem_ctx,
|
||||
const char *target,
|
||||
size_t unparsed,
|
||||
char **_relative);
|
||||
NTSTATUS filename_convert_dirfsp_rel(TALLOC_CTX *mem_ctx,
|
||||
connection_struct *conn,
|
||||
struct files_struct *basedir,
|
||||
const char *name_in,
|
||||
uint32_t ucf_flags,
|
||||
NTTIME twrp,
|
||||
struct files_struct **_dirfsp,
|
||||
struct smb_filename **_smb_fname,
|
||||
struct smb_filename **_smb_fname_rel);
|
||||
NTSTATUS filename_convert_dirfsp(
|
||||
TALLOC_CTX *ctx,
|
||||
connection_struct *conn,
|
||||
|
@ -83,12 +83,17 @@ static int tdb_validate_child(struct tdb_context *tdb,
|
||||
ret = 0; /* Cache is good. */
|
||||
|
||||
out:
|
||||
DEBUG(10, ("tdb_validate_child: summary of validation status:\n"));
|
||||
DEBUGADD(10,(" * tdb error: %s\n", v_status.tdb_error ? "yes" : "no"));
|
||||
DEBUGADD(10,(" * bad freelist: %s\n",v_status.bad_freelist?"yes":"no"));
|
||||
DEBUGADD(10,(" * bad entry: %s\n", v_status.bad_entry ? "yes" : "no"));
|
||||
DEBUGADD(10,(" * unknown key: %s\n", v_status.unknown_key?"yes":"no"));
|
||||
DEBUGADD(10,(" => overall success: %s\n", v_status.success?"yes":"no"));
|
||||
DBG_DEBUG("summary of validation status:\n"
|
||||
" * tdb error: %s\n"
|
||||
" * bad freelist: %s\n"
|
||||
" * bad entry: %s\n"
|
||||
" * unknown key: %s\n"
|
||||
" => overall success: %s\n",
|
||||
v_status.tdb_error ? "yes" : "no",
|
||||
v_status.bad_freelist ? "yes" : "no",
|
||||
v_status.bad_entry ? "yes" : "no",
|
||||
v_status.unknown_key ? "yes" : "no",
|
||||
v_status.success ? "yes" : "no");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -2251,7 +2251,7 @@ static void cli_smb2_qpathinfo_opened(struct tevent_req *subreq)
|
||||
state->ev,
|
||||
state->cli,
|
||||
state->fnum,
|
||||
1, /* in_info_type */
|
||||
SMB2_0_INFO_FILE,
|
||||
state->level,
|
||||
state->max_rdata,
|
||||
NULL, /* in_input_buffer */
|
||||
|
@ -6648,7 +6648,7 @@ NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
|
||||
|
||||
struct cli_notify_state {
|
||||
struct tevent_req *subreq;
|
||||
uint8_t setup[8];
|
||||
uint16_t setup[4];
|
||||
uint32_t num_changes;
|
||||
struct notify_change *changes;
|
||||
};
|
||||
|
@ -3169,6 +3169,12 @@ MODULE_INIT_FUNC(libsmb_samba_cwrapper)
|
||||
ADD_FLAGS(IO_REPARSE_TAG_DFS);
|
||||
ADD_FLAGS(IO_REPARSE_TAG_NFS);
|
||||
|
||||
ADD_FLAGS(NFS_SPECFILE_LNK);
|
||||
ADD_FLAGS(NFS_SPECFILE_CHR);
|
||||
ADD_FLAGS(NFS_SPECFILE_BLK);
|
||||
ADD_FLAGS(NFS_SPECFILE_FIFO);
|
||||
ADD_FLAGS(NFS_SPECFILE_SOCK);
|
||||
|
||||
ADD_FLAGS(FSCC_FILE_DIRECTORY_INFORMATION);
|
||||
ADD_FLAGS(FSCC_FILE_FULL_DIRECTORY_INFORMATION);
|
||||
ADD_FLAGS(FSCC_FILE_BOTH_DIRECTORY_INFORMATION);
|
||||
|
@ -607,6 +607,7 @@ static int vfswrap_openat(vfs_handle_struct *handle,
|
||||
files_struct *fsp,
|
||||
const struct vfs_open_how *how)
|
||||
{
|
||||
int dirfd = fsp_get_pathref_fd(dirfsp);
|
||||
int flags = how->flags;
|
||||
mode_t mode = how->mode;
|
||||
bool have_opath = false;
|
||||
@ -615,6 +616,8 @@ static int vfswrap_openat(vfs_handle_struct *handle,
|
||||
|
||||
START_PROFILE(syscall_openat);
|
||||
|
||||
SMB_ASSERT((dirfd != -1) || (smb_fname->base_name[0] == '/'));
|
||||
|
||||
if (how->resolve & ~(VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS |
|
||||
VFS_OPEN_HOW_WITH_BACKUP_INTENT)) {
|
||||
errno = ENOSYS;
|
||||
@ -656,7 +659,7 @@ static int vfswrap_openat(vfs_handle_struct *handle,
|
||||
.resolve = RESOLVE_NO_SYMLINKS,
|
||||
};
|
||||
|
||||
result = openat2(fsp_get_pathref_fd(dirfsp),
|
||||
result = openat2(dirfd,
|
||||
smb_fname->base_name,
|
||||
&linux_how,
|
||||
sizeof(linux_how));
|
||||
@ -683,7 +686,7 @@ static int vfswrap_openat(vfs_handle_struct *handle,
|
||||
became_root = true;
|
||||
}
|
||||
|
||||
result = openat(fsp_get_pathref_fd(dirfsp),
|
||||
result = openat(dirfd,
|
||||
smb_fname->base_name,
|
||||
flags,
|
||||
mode);
|
||||
|
@ -126,12 +126,20 @@ static int fake_acls_stat(vfs_handle_struct *handle,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fsp_get_pathref_fd(handle->conn->cwd_fsp) == -1) {
|
||||
/*
|
||||
* No tcon around, fail as if we don't have
|
||||
* the EAs
|
||||
*/
|
||||
status = NT_STATUS_INVALID_HANDLE;
|
||||
} else {
|
||||
/* Recursion guard. */
|
||||
prd->calling_pathref_fsp = true;
|
||||
status = openat_pathref_fsp(handle->conn->cwd_fsp,
|
||||
smb_fname_cp);
|
||||
/* End recursion guard. */
|
||||
prd->calling_pathref_fsp = false;
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
/*
|
||||
|
@ -413,34 +413,22 @@ static bool add_fruit_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool filter_empty_rsrc_stream(unsigned int *num_streams,
|
||||
static void filter_empty_rsrc_stream(unsigned int *num_streams,
|
||||
struct stream_struct **streams)
|
||||
{
|
||||
struct stream_struct *tmp = *streams;
|
||||
unsigned int i;
|
||||
|
||||
if (*num_streams == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (i = 0; i < *num_streams; i++) {
|
||||
if (strequal_m(tmp[i].name, AFPRESOURCE_STREAM)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
struct stream_struct *s = &(*streams)[i];
|
||||
|
||||
if (i == *num_streams) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (tmp[i].size > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
TALLOC_FREE(tmp[i].name);
|
||||
ARRAY_DEL_ELEMENT(tmp, i, *num_streams);
|
||||
if (strequal_m(s->name, AFPRESOURCE_STREAM) &&
|
||||
(s->size == 0)) {
|
||||
TALLOC_FREE(s->name);
|
||||
ARRAY_DEL_ELEMENT(streams, i, *num_streams);
|
||||
*num_streams -= 1;
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool del_fruit_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
|
||||
@ -3745,8 +3733,7 @@ static NTSTATUS fruit_streaminfo_meta_stream(
|
||||
struct stream_struct **pstreams)
|
||||
{
|
||||
struct stream_struct *stream = *pstreams;
|
||||
unsigned int num_streams = *pnum_streams;
|
||||
int i;
|
||||
unsigned int i, num_streams = *pnum_streams;
|
||||
|
||||
for (i = 0; i < num_streams; i++) {
|
||||
if (strequal_m(stream[i].name, AFPINFO_STREAM)) {
|
||||
@ -3783,10 +3770,9 @@ static NTSTATUS fruit_streaminfo_meta_netatalk(
|
||||
struct stream_struct **pstreams)
|
||||
{
|
||||
struct stream_struct *stream = *pstreams;
|
||||
unsigned int num_streams = *pnum_streams;
|
||||
unsigned int i, num_streams = *pnum_streams;
|
||||
struct adouble *ad = NULL;
|
||||
bool is_fi_empty;
|
||||
int i;
|
||||
bool ok;
|
||||
|
||||
/* Remove the Netatalk xattr from the list */
|
||||
@ -3880,13 +3866,7 @@ static NTSTATUS fruit_streaminfo_rsrc_stream(
|
||||
unsigned int *pnum_streams,
|
||||
struct stream_struct **pstreams)
|
||||
{
|
||||
bool ok;
|
||||
|
||||
ok = filter_empty_rsrc_stream(pnum_streams, pstreams);
|
||||
if (!ok) {
|
||||
DBG_ERR("Filtering resource stream failed\n");
|
||||
return NT_STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
filter_empty_rsrc_stream(pnum_streams, pstreams);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
@ -3898,13 +3878,7 @@ static NTSTATUS fruit_streaminfo_rsrc_xattr(
|
||||
unsigned int *pnum_streams,
|
||||
struct stream_struct **pstreams)
|
||||
{
|
||||
bool ok;
|
||||
|
||||
ok = filter_empty_rsrc_stream(pnum_streams, pstreams);
|
||||
if (!ok) {
|
||||
DBG_ERR("Filtering resource stream failed\n");
|
||||
return NT_STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
filter_empty_rsrc_stream(pnum_streams, pstreams);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
@ -3917,11 +3891,10 @@ static NTSTATUS fruit_streaminfo_rsrc_adouble(
|
||||
struct stream_struct **pstreams)
|
||||
{
|
||||
struct stream_struct *stream = *pstreams;
|
||||
unsigned int num_streams = *pnum_streams;
|
||||
unsigned int i, num_streams = *pnum_streams;
|
||||
struct adouble *ad = NULL;
|
||||
bool ok;
|
||||
size_t rlen;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Check if there's a AFPRESOURCE_STREAM from the VFS streams backend
|
||||
|
@ -48,15 +48,12 @@ struct stream_io {
|
||||
static ssize_t get_xattr_size_fsp(struct files_struct *fsp,
|
||||
const char *xattr_name)
|
||||
{
|
||||
NTSTATUS status;
|
||||
int ret;
|
||||
struct ea_struct ea;
|
||||
ssize_t result;
|
||||
|
||||
status = get_ea_value_fsp(talloc_tos(),
|
||||
fsp,
|
||||
xattr_name,
|
||||
&ea);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
ret = get_ea_value_fsp(talloc_tos(), fsp, xattr_name, &ea);
|
||||
if (ret != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -69,7 +66,7 @@ static ssize_t get_xattr_size_fsp(struct files_struct *fsp,
|
||||
* Given a stream name, populate xattr_name with the xattr name to use for
|
||||
* accessing the stream.
|
||||
*/
|
||||
static NTSTATUS streams_xattr_get_name(vfs_handle_struct *handle,
|
||||
static int streams_xattr_get_name(vfs_handle_struct *handle,
|
||||
TALLOC_CTX *ctx,
|
||||
const char *stream_name,
|
||||
char **xattr_name)
|
||||
@ -78,8 +75,10 @@ static NTSTATUS streams_xattr_get_name(vfs_handle_struct *handle,
|
||||
char *stype;
|
||||
struct streams_xattr_config *config;
|
||||
|
||||
SMB_VFS_HANDLE_GET_DATA(handle, config, struct streams_xattr_config,
|
||||
return NT_STATUS_UNSUCCESSFUL);
|
||||
SMB_VFS_HANDLE_GET_DATA(handle,
|
||||
config,
|
||||
struct streams_xattr_config,
|
||||
return EACCES);
|
||||
|
||||
SMB_ASSERT(stream_name[0] == ':');
|
||||
stream_name += 1;
|
||||
@ -105,7 +104,7 @@ static NTSTATUS streams_xattr_get_name(vfs_handle_struct *handle,
|
||||
* We only support one stream type: "$DATA"
|
||||
*/
|
||||
if (strcasecmp_m(stype, ":$DATA") != 0) {
|
||||
return NT_STATUS_INVALID_PARAMETER;
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* Split name and type */
|
||||
@ -118,18 +117,18 @@ static NTSTATUS streams_xattr_get_name(vfs_handle_struct *handle,
|
||||
stream_name,
|
||||
config->store_stream_type ? ":$DATA" : "");
|
||||
if (*xattr_name == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
DEBUG(10, ("xattr_name: %s, stream_name: %s\n", *xattr_name,
|
||||
stream_name));
|
||||
|
||||
return NT_STATUS_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool streams_xattr_recheck(struct stream_io *sio)
|
||||
{
|
||||
NTSTATUS status;
|
||||
int ret;
|
||||
char *xattr_name = NULL;
|
||||
|
||||
if (sio->fsp->fsp_name == sio->fsp_name_ptr) {
|
||||
@ -142,10 +141,11 @@ static bool streams_xattr_recheck(struct stream_io *sio)
|
||||
return false;
|
||||
}
|
||||
|
||||
status = streams_xattr_get_name(sio->handle, talloc_tos(),
|
||||
ret = streams_xattr_get_name(sio->handle,
|
||||
talloc_tos(),
|
||||
sio->fsp->fsp_name->stream_name,
|
||||
&xattr_name);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
if (ret != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -215,6 +215,7 @@ static int streams_xattr_stat(vfs_handle_struct *handle,
|
||||
struct smb_filename *smb_fname)
|
||||
{
|
||||
NTSTATUS status;
|
||||
int ret;
|
||||
int result = -1;
|
||||
char *xattr_name = NULL;
|
||||
char *tmp_stream_name = NULL;
|
||||
@ -241,10 +242,12 @@ static int streams_xattr_stat(vfs_handle_struct *handle,
|
||||
}
|
||||
|
||||
/* Derive the xattr name to lookup. */
|
||||
status = streams_xattr_get_name(handle, talloc_tos(),
|
||||
smb_fname->stream_name, &xattr_name);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
errno = map_errno_from_nt_status(status);
|
||||
ret = streams_xattr_get_name(handle,
|
||||
talloc_tos(),
|
||||
smb_fname->stream_name,
|
||||
&xattr_name);
|
||||
if (ret != 0) {
|
||||
errno = ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -313,7 +316,6 @@ static int streams_xattr_openat(struct vfs_handle_struct *handle,
|
||||
files_struct *fsp,
|
||||
const struct vfs_open_how *how)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct streams_xattr_config *config = NULL;
|
||||
struct stream_io *sio = NULL;
|
||||
struct ea_struct ea;
|
||||
@ -345,22 +347,20 @@ static int streams_xattr_openat(struct vfs_handle_struct *handle,
|
||||
SMB_ASSERT(fsp_is_alternate_stream(fsp));
|
||||
SMB_ASSERT(dirfsp == NULL);
|
||||
|
||||
status = streams_xattr_get_name(handle, talloc_tos(),
|
||||
smb_fname->stream_name, &xattr_name);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
errno = map_errno_from_nt_status(status);
|
||||
ret = streams_xattr_get_name(handle,
|
||||
talloc_tos(),
|
||||
smb_fname->stream_name,
|
||||
&xattr_name);
|
||||
if (ret != 0) {
|
||||
errno = ret;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
status = get_ea_value_fsp(talloc_tos(),
|
||||
fsp->base_fsp,
|
||||
xattr_name,
|
||||
&ea);
|
||||
ret = get_ea_value_fsp(talloc_tos(), fsp->base_fsp, xattr_name, &ea);
|
||||
if (ret != 0) {
|
||||
DBG_DEBUG("get_ea_value_fsp returned %s\n", strerror(ret));
|
||||
|
||||
DBG_DEBUG("get_ea_value_fsp returned %s\n", nt_errstr(status));
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
|
||||
if (ret != ENOATTR) {
|
||||
/*
|
||||
* The base file is not there. This is an error even if
|
||||
* we got O_CREAT, the higher levels should have created
|
||||
@ -373,7 +373,7 @@ static int streams_xattr_openat(struct vfs_handle_struct *handle,
|
||||
}
|
||||
|
||||
if (!(how->flags & O_CREAT)) {
|
||||
errno = ENOATTR;
|
||||
errno = ENOENT;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -492,10 +492,12 @@ static int streams_xattr_unlinkat(vfs_handle_struct *handle,
|
||||
/* A stream can never be rmdir'ed */
|
||||
SMB_ASSERT((flags & AT_REMOVEDIR) == 0);
|
||||
|
||||
status = streams_xattr_get_name(handle, talloc_tos(),
|
||||
smb_fname->stream_name, &xattr_name);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
errno = map_errno_from_nt_status(status);
|
||||
ret = streams_xattr_get_name(handle,
|
||||
talloc_tos(),
|
||||
smb_fname->stream_name,
|
||||
&xattr_name);
|
||||
if (ret != 0) {
|
||||
errno = ret;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -584,18 +586,20 @@ static int streams_xattr_renameat(vfs_handle_struct *handle,
|
||||
}
|
||||
|
||||
/* Get the xattr names. */
|
||||
status = streams_xattr_get_name(handle, talloc_tos(),
|
||||
ret = streams_xattr_get_name(handle,
|
||||
talloc_tos(),
|
||||
smb_fname_src->stream_name,
|
||||
&src_xattr_name);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
errno = map_errno_from_nt_status(status);
|
||||
if (ret != 0) {
|
||||
errno = ret;
|
||||
goto fail;
|
||||
}
|
||||
status = streams_xattr_get_name(handle, talloc_tos(),
|
||||
ret = streams_xattr_get_name(handle,
|
||||
talloc_tos(),
|
||||
smb_fname_dst->stream_name,
|
||||
&dst_xattr_name);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
errno = map_errno_from_nt_status(status);
|
||||
if (ret != 0) {
|
||||
errno = ret;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -629,12 +633,12 @@ static int streams_xattr_renameat(vfs_handle_struct *handle,
|
||||
}
|
||||
|
||||
/* Read the old stream from the base file fsp. */
|
||||
status = get_ea_value_fsp(talloc_tos(),
|
||||
ret = get_ea_value_fsp(talloc_tos(),
|
||||
pathref_src->fsp,
|
||||
src_xattr_name,
|
||||
&ea);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
errno = map_errno_from_nt_status(status);
|
||||
if (ret != 0) {
|
||||
errno = ret;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -716,6 +720,7 @@ static NTSTATUS walk_xattr_streams(vfs_handle_struct *handle,
|
||||
|
||||
for (i=0; i<num_names; i++) {
|
||||
struct ea_struct ea;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* We want to check with samba_private_attr_name()
|
||||
@ -740,15 +745,12 @@ static NTSTATUS walk_xattr_streams(vfs_handle_struct *handle,
|
||||
continue;
|
||||
}
|
||||
|
||||
status = get_ea_value_fsp(names,
|
||||
smb_fname->fsp,
|
||||
names[i],
|
||||
&ea);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DEBUG(10, ("Could not get ea %s for file %s: %s\n",
|
||||
ret = get_ea_value_fsp(names, smb_fname->fsp, names[i], &ea);
|
||||
if (ret != 0) {
|
||||
DBG_DEBUG("Could not get ea %s for file %s: %s\n",
|
||||
names[i],
|
||||
smb_fname->base_name,
|
||||
nt_errstr(status)));
|
||||
strerror(ret));
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -922,7 +924,6 @@ static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle,
|
||||
struct stream_io *sio =
|
||||
(struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
|
||||
struct ea_struct ea;
|
||||
NTSTATUS status;
|
||||
int ret;
|
||||
|
||||
DEBUG(10, ("streams_xattr_pwrite called for %d bytes\n", (int)n));
|
||||
@ -956,11 +957,12 @@ static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle,
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = get_ea_value_fsp(talloc_tos(),
|
||||
ret = get_ea_value_fsp(talloc_tos(),
|
||||
fsp->base_fsp,
|
||||
sio->xattr_name,
|
||||
&ea);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
if (ret != 0) {
|
||||
errno = ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1003,7 +1005,7 @@ static ssize_t streams_xattr_pread(vfs_handle_struct *handle,
|
||||
struct stream_io *sio =
|
||||
(struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
|
||||
struct ea_struct ea;
|
||||
NTSTATUS status;
|
||||
int ret;
|
||||
size_t length, overlap;
|
||||
|
||||
DEBUG(10, ("streams_xattr_pread: offset=%d, size=%d\n",
|
||||
@ -1017,11 +1019,12 @@ static ssize_t streams_xattr_pread(vfs_handle_struct *handle,
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = get_ea_value_fsp(talloc_tos(),
|
||||
ret = get_ea_value_fsp(talloc_tos(),
|
||||
fsp->base_fsp,
|
||||
sio->xattr_name,
|
||||
&ea);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
if (ret != 0) {
|
||||
errno = ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1209,7 +1212,6 @@ static int streams_xattr_ftruncate(struct vfs_handle_struct *handle,
|
||||
int ret;
|
||||
uint8_t *tmp;
|
||||
struct ea_struct ea;
|
||||
NTSTATUS status;
|
||||
struct stream_io *sio =
|
||||
(struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
|
||||
|
||||
@ -1224,11 +1226,12 @@ static int streams_xattr_ftruncate(struct vfs_handle_struct *handle,
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = get_ea_value_fsp(talloc_tos(),
|
||||
ret = get_ea_value_fsp(talloc_tos(),
|
||||
fsp->base_fsp,
|
||||
sio->xattr_name,
|
||||
&ea);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
if (ret != 0) {
|
||||
errno = ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -1183,12 +1183,7 @@ static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, struct files_struct *fsp)
|
||||
* files non-visible to the client. If not, fail the delete.
|
||||
*/
|
||||
|
||||
status = OpenDir(talloc_tos(),
|
||||
conn,
|
||||
smb_dname,
|
||||
NULL,
|
||||
0,
|
||||
&dir_hnd);
|
||||
status = OpenDir_from_pathref(talloc_tos(), fsp, NULL, 0, &dir_hnd);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
/*
|
||||
* Note, we deliberately squash the error here
|
||||
|
@ -1066,17 +1066,55 @@ NTSTATUS OpenDir_from_pathref(TALLOC_CTX *mem_ctx,
|
||||
uint32_t attr,
|
||||
struct smb_Dir **_dir_hnd)
|
||||
{
|
||||
struct files_struct *fsp = NULL;
|
||||
struct connection_struct *conn = dirfsp->conn;
|
||||
struct files_struct *new_fsp = NULL;
|
||||
struct smb_Dir *dir_hnd = NULL;
|
||||
const struct vfs_open_how how = {.flags = O_RDONLY | O_DIRECTORY};
|
||||
int old_fd;
|
||||
NTSTATUS status;
|
||||
|
||||
status = openat_internal_dir_from_pathref(dirfsp, O_RDONLY, &fsp);
|
||||
status = create_internal_dirfsp(conn, dirfsp->fsp_name, &new_fsp);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = OpenDir_fsp(mem_ctx, fsp->conn, fsp, mask, attr, &dir_hnd);
|
||||
if (dirfsp->fsp_flags.have_proc_fds &&
|
||||
((old_fd = fsp_get_pathref_fd(dirfsp)) != -1))
|
||||
{
|
||||
struct sys_proc_fd_path_buf buf;
|
||||
struct smb_filename proc_fname = {
|
||||
.base_name = sys_proc_fd_path(old_fd, &buf),
|
||||
};
|
||||
int new_fd;
|
||||
|
||||
new_fd = SMB_VFS_OPENAT(
|
||||
conn, conn->cwd_fsp, &proc_fname, new_fsp, &how);
|
||||
if (new_fd == -1) {
|
||||
status = map_nt_error_from_unix(errno);
|
||||
DBG_DEBUG("SMB_VFS_OPENAT(%s) returned %s\n",
|
||||
proc_fname.base_name, strerror(errno));
|
||||
file_free(NULL, new_fsp);
|
||||
return status;
|
||||
}
|
||||
fsp_set_fd(new_fsp, new_fd);
|
||||
} else {
|
||||
status = fd_openat(conn->cwd_fsp,
|
||||
dirfsp->fsp_name,
|
||||
new_fsp,
|
||||
&how);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DBG_DEBUG("fd_openat(%s) returned %s\n",
|
||||
dirfsp->fsp_name->base_name,
|
||||
nt_errstr(status));
|
||||
file_free(NULL, new_fsp);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
status = OpenDir_fsp(mem_ctx, conn, new_fsp, mask, attr, &dir_hnd);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
fd_close(new_fsp);
|
||||
file_free(NULL, new_fsp);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -1512,8 +1550,7 @@ NTSTATUS can_delete_directory_fsp(files_struct *fsp)
|
||||
struct connection_struct *conn = fsp->conn;
|
||||
struct smb_Dir *dir_hnd = NULL;
|
||||
|
||||
status = OpenDir(
|
||||
talloc_tos(), conn, fsp->fsp_name, NULL, 0, &dir_hnd);
|
||||
status = OpenDir_from_pathref(talloc_tos(), fsp, NULL, 0, &dir_hnd);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
@ -667,11 +667,13 @@ fail:
|
||||
static NTSTATUS filename_convert_dirfsp_nosymlink(
|
||||
TALLOC_CTX *mem_ctx,
|
||||
connection_struct *conn,
|
||||
struct files_struct *basedir,
|
||||
const char *name_in,
|
||||
uint32_t ucf_flags,
|
||||
NTTIME twrp,
|
||||
struct files_struct **_dirfsp,
|
||||
struct smb_filename **_smb_fname,
|
||||
struct smb_filename **_smb_fname_rel,
|
||||
struct reparse_data_buffer **_symlink_err)
|
||||
{
|
||||
struct smb_filename *smb_dirname = NULL;
|
||||
@ -704,7 +706,7 @@ static NTSTATUS filename_convert_dirfsp_nosymlink(
|
||||
.st_ex_ctime = omit,
|
||||
};
|
||||
|
||||
*_dirfsp = conn->cwd_fsp;
|
||||
*_dirfsp = basedir;
|
||||
*_smb_fname = smb_fname;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
@ -750,15 +752,19 @@ static NTSTATUS filename_convert_dirfsp_nosymlink(
|
||||
}
|
||||
|
||||
if (dirname[0] == '\0') {
|
||||
status = synthetic_pathref(
|
||||
smb_dirname = synthetic_smb_fname(
|
||||
mem_ctx,
|
||||
conn->cwd_fsp,
|
||||
".",
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
posix ? SMB_FILENAME_POSIX_PATH : 0,
|
||||
&smb_dirname);
|
||||
posix ? SMB_FILENAME_POSIX_PATH : 0);
|
||||
if (smb_dirname == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
status = openat_pathref_fsp_lcomp(basedir,
|
||||
smb_dirname,
|
||||
UCF_POSIX_PATHNAMES);
|
||||
} else {
|
||||
status = normalize_filename_case(conn, dirname, ucf_flags);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
@ -770,7 +776,7 @@ static NTSTATUS filename_convert_dirfsp_nosymlink(
|
||||
|
||||
status = openat_pathref_fsp_nosymlink(mem_ctx,
|
||||
conn,
|
||||
conn->cwd_fsp,
|
||||
basedir,
|
||||
dirname,
|
||||
twrp,
|
||||
posix,
|
||||
@ -1033,12 +1039,19 @@ static NTSTATUS filename_convert_dirfsp_nosymlink(
|
||||
}
|
||||
|
||||
done:
|
||||
if (S_ISLNK(smb_fname->st.st_ex_mode) &&
|
||||
!(ucf_flags & UCF_LCOMP_LNK_OK)) {
|
||||
status = NT_STATUS_STOPPED_ON_SYMLINK;
|
||||
*_symlink_err = symlink_err;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
*_dirfsp = smb_dirname->fsp;
|
||||
*_smb_fname = smb_fname;
|
||||
*_symlink_err = symlink_err;
|
||||
|
||||
smb_fname_fsp_unlink(smb_fname_rel);
|
||||
TALLOC_FREE(smb_fname_rel);
|
||||
*_smb_fname_rel = smb_fname_rel;
|
||||
return NT_STATUS_OK;
|
||||
|
||||
fail:
|
||||
@ -1059,19 +1072,21 @@ fail:
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS filename_convert_dirfsp(
|
||||
TALLOC_CTX *mem_ctx,
|
||||
NTSTATUS filename_convert_dirfsp_rel(TALLOC_CTX *mem_ctx,
|
||||
connection_struct *conn,
|
||||
struct files_struct *basedir,
|
||||
const char *name_in,
|
||||
uint32_t ucf_flags,
|
||||
NTTIME twrp,
|
||||
struct files_struct **_dirfsp,
|
||||
struct smb_filename **_smb_fname)
|
||||
struct smb_filename **_smb_fname,
|
||||
struct smb_filename **_smb_fname_rel)
|
||||
{
|
||||
struct reparse_data_buffer *symlink_err = NULL;
|
||||
struct symlink_reparse_struct *lnk = NULL;
|
||||
NTSTATUS status;
|
||||
char *target = NULL;
|
||||
char *base_name = NULL;
|
||||
char *safe_target = NULL;
|
||||
size_t symlink_redirects = 0;
|
||||
int ret;
|
||||
@ -1083,28 +1098,20 @@ next:
|
||||
|
||||
status = filename_convert_dirfsp_nosymlink(mem_ctx,
|
||||
conn,
|
||||
basedir,
|
||||
name_in,
|
||||
ucf_flags,
|
||||
twrp,
|
||||
_dirfsp,
|
||||
_smb_fname,
|
||||
_smb_fname_rel,
|
||||
&symlink_err);
|
||||
|
||||
if (NT_STATUS_IS_OK(status) && S_ISLNK((*_smb_fname)->st.st_ex_mode)) {
|
||||
/*
|
||||
* lcomp is a symlink
|
||||
*/
|
||||
if (ucf_flags & UCF_LCOMP_LNK_OK) {
|
||||
TALLOC_FREE(symlink_err);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
close_file_free(NULL, _dirfsp, ERROR_CLOSE);
|
||||
status = NT_STATUS_STOPPED_ON_SYMLINK;
|
||||
}
|
||||
|
||||
if (!NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
|
||||
return status;
|
||||
}
|
||||
TALLOC_FREE(*_smb_fname_rel);
|
||||
|
||||
lnk = &symlink_err->parsed.lnk;
|
||||
|
||||
/*
|
||||
@ -1150,9 +1157,13 @@ next:
|
||||
return map_nt_error_from_unix(ret);
|
||||
}
|
||||
|
||||
if (basedir != conn->cwd_fsp) {
|
||||
base_name = basedir->fsp_name->base_name;
|
||||
}
|
||||
|
||||
status = safe_symlink_target_path(mem_ctx,
|
||||
conn->connectpath,
|
||||
NULL,
|
||||
base_name,
|
||||
target,
|
||||
lnk->unparsed_path_length,
|
||||
&safe_target);
|
||||
@ -1161,12 +1172,37 @@ next:
|
||||
return status;
|
||||
}
|
||||
name_in = safe_target;
|
||||
basedir = conn->cwd_fsp;
|
||||
|
||||
symlink_redirects += 1;
|
||||
|
||||
goto next;
|
||||
}
|
||||
|
||||
NTSTATUS filename_convert_dirfsp(TALLOC_CTX *ctx,
|
||||
connection_struct *conn,
|
||||
const char *name_in,
|
||||
uint32_t ucf_flags,
|
||||
NTTIME twrp,
|
||||
struct files_struct **_dirfsp,
|
||||
struct smb_filename **_smb_name)
|
||||
{
|
||||
struct smb_filename *smb_fname_rel = NULL;
|
||||
NTSTATUS status;
|
||||
|
||||
status = filename_convert_dirfsp_rel(ctx,
|
||||
conn,
|
||||
conn->cwd_fsp,
|
||||
name_in,
|
||||
ucf_flags,
|
||||
twrp,
|
||||
_dirfsp,
|
||||
_smb_name,
|
||||
&smb_fname_rel);
|
||||
TALLOC_FREE(smb_fname_rel);
|
||||
return status;
|
||||
}
|
||||
|
||||
char *full_path_from_dirfsp_at_basename(TALLOC_CTX *mem_ctx,
|
||||
const struct files_struct *dirfsp,
|
||||
const char *at_base_name)
|
||||
|
@ -286,52 +286,6 @@ NTSTATUS open_internal_dirfsp(connection_struct *conn,
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a pathref dirfsp into a real fsp. No need to do any cwd
|
||||
* tricks, we just open ".".
|
||||
*/
|
||||
NTSTATUS openat_internal_dir_from_pathref(
|
||||
struct files_struct *dirfsp,
|
||||
int _open_flags,
|
||||
struct files_struct **_fsp)
|
||||
{
|
||||
struct connection_struct *conn = dirfsp->conn;
|
||||
struct smb_filename *smb_dname = dirfsp->fsp_name;
|
||||
struct files_struct *fsp = NULL;
|
||||
char dot[] = ".";
|
||||
struct smb_filename smb_dot = {
|
||||
.base_name = dot,
|
||||
.flags = smb_dname->flags,
|
||||
.twrp = smb_dname->twrp,
|
||||
};
|
||||
struct vfs_open_how how = { .flags = _open_flags, };
|
||||
NTSTATUS status;
|
||||
|
||||
status = create_internal_dirfsp(conn, smb_dname, &fsp);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Pointless for opening ".", but you never know...
|
||||
*/
|
||||
how.flags |= O_NOFOLLOW;
|
||||
|
||||
status = fd_openat(dirfsp, &smb_dot, fsp, &how);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DBG_INFO("fd_openat(\"%s\", \".\") failed: %s\n",
|
||||
fsp_str_dbg(dirfsp),
|
||||
nt_errstr(status));
|
||||
file_free(NULL, fsp);
|
||||
return status;
|
||||
}
|
||||
|
||||
fsp->fsp_name->st = smb_dname->st;
|
||||
fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
|
||||
*_fsp = fsp;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* The "link" in the name doesn't imply link in the filesystem
|
||||
* sense. It's a object that "links" together an fsp and an smb_fname
|
||||
@ -450,20 +404,16 @@ static int smb_fname_fsp_destructor(struct smb_filename *smb_fname)
|
||||
static NTSTATUS openat_pathref_fullname(
|
||||
struct connection_struct *conn,
|
||||
const struct files_struct *dirfsp,
|
||||
struct files_struct *basefsp,
|
||||
struct smb_filename **full_fname,
|
||||
struct smb_filename *smb_fname,
|
||||
const struct vfs_open_how *how)
|
||||
{
|
||||
struct files_struct *fsp = NULL;
|
||||
bool have_dirfsp = (dirfsp != NULL);
|
||||
bool have_basefsp = (basefsp != NULL);
|
||||
NTSTATUS status;
|
||||
|
||||
DBG_DEBUG("smb_fname [%s]\n", smb_fname_str_dbg(smb_fname));
|
||||
|
||||
SMB_ASSERT(smb_fname->fsp == NULL);
|
||||
SMB_ASSERT(have_dirfsp != have_basefsp);
|
||||
|
||||
status = fsp_new(conn, conn, &fsp);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
@ -480,7 +430,6 @@ static NTSTATUS openat_pathref_fullname(
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto fail;
|
||||
}
|
||||
fsp_set_base_fsp(fsp, basefsp);
|
||||
|
||||
status = fd_openat(dirfsp, smb_fname, fsp, how);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
@ -539,7 +488,6 @@ fail:
|
||||
smb_fname_str_dbg(smb_fname),
|
||||
nt_errstr(status));
|
||||
|
||||
fsp_set_base_fsp(fsp, NULL);
|
||||
fd_close(fsp);
|
||||
file_free(NULL, fsp);
|
||||
return status;
|
||||
@ -592,7 +540,7 @@ NTSTATUS openat_pathref_fsp(const struct files_struct *dirfsp,
|
||||
goto fail;
|
||||
}
|
||||
status = openat_pathref_fullname(
|
||||
conn, dirfsp, NULL, &full_fname, smb_fname, &how);
|
||||
conn, dirfsp, &full_fname, smb_fname, &how);
|
||||
TALLOC_FREE(full_fname);
|
||||
return status;
|
||||
}
|
||||
@ -615,7 +563,7 @@ NTSTATUS openat_pathref_fsp(const struct files_struct *dirfsp,
|
||||
}
|
||||
|
||||
status = openat_pathref_fullname(
|
||||
conn, dirfsp, NULL, &full_fname, base_fname, &how);
|
||||
conn, dirfsp, &full_fname, base_fname, &how);
|
||||
TALLOC_FREE(full_fname);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DBG_DEBUG("openat_pathref_fullname() failed: %s\n",
|
||||
@ -636,6 +584,62 @@ fail:
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS open_rootdir_pathref_fsp(connection_struct *conn,
|
||||
struct files_struct **_fsp)
|
||||
{
|
||||
struct smb_filename slash = { .base_name = discard_const_p(char, "/") };
|
||||
struct vfs_open_how how = { .flags = O_RDONLY|O_DIRECTORY, };
|
||||
struct files_struct *fsp = NULL;
|
||||
NTSTATUS status;
|
||||
int fd;
|
||||
|
||||
status = fsp_new(conn, conn, &fsp);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto fail;
|
||||
}
|
||||
GetTimeOfDay(&fsp->open_time);
|
||||
fsp_set_gen_id(fsp);
|
||||
ZERO_STRUCT(conn->sconn->fsp_fi_cache);
|
||||
fsp->fsp_flags.is_pathref = true;
|
||||
|
||||
status = fsp_set_smb_fname(fsp, &slash);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fd = SMB_VFS_OPENAT(conn,
|
||||
conn->cwd_fsp,
|
||||
fsp->fsp_name,
|
||||
fsp,
|
||||
&how);
|
||||
if (fd == -1) {
|
||||
status = map_nt_error_from_unix(errno);
|
||||
goto fail;
|
||||
}
|
||||
fsp_set_fd(fsp, fd);
|
||||
|
||||
status = vfs_stat_fsp(fsp);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DBG_DEBUG("vfs_stat_fsp(\"/\") failed: %s\n", nt_errstr(status));
|
||||
goto close_fail;
|
||||
}
|
||||
fsp->fsp_flags.is_directory = S_ISDIR(fsp->fsp_name->st.st_ex_mode);
|
||||
if (!fsp->fsp_flags.is_directory) {
|
||||
DBG_DEBUG("\"/\" not a directory\n");
|
||||
status = NT_STATUS_UNEXPECTED_IO_ERROR;
|
||||
goto close_fail;
|
||||
}
|
||||
fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
|
||||
*_fsp = fsp;
|
||||
return NT_STATUS_OK;
|
||||
|
||||
close_fail:
|
||||
fd_close(fsp);
|
||||
fail:
|
||||
file_free(NULL, fsp);
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a stream given an already opened base_fsp. Avoid
|
||||
* non_widelink_open: This is only valid for the case where we have a
|
||||
@ -646,11 +650,13 @@ NTSTATUS open_stream_pathref_fsp(
|
||||
struct smb_filename *smb_fname)
|
||||
{
|
||||
struct files_struct *base_fsp = *_base_fsp;
|
||||
struct files_struct *fsp = NULL;
|
||||
connection_struct *conn = base_fsp->conn;
|
||||
struct smb_filename *base_fname = base_fsp->fsp_name;
|
||||
struct smb_filename *full_fname = NULL;
|
||||
struct vfs_open_how how = { .flags = O_RDONLY|O_NONBLOCK, };
|
||||
NTSTATUS status;
|
||||
int fd;
|
||||
|
||||
SMB_ASSERT(smb_fname->fsp == NULL);
|
||||
SMB_ASSERT(is_named_stream(smb_fname));
|
||||
@ -666,9 +672,61 @@ NTSTATUS open_stream_pathref_fsp(
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
status = openat_pathref_fullname(
|
||||
conn, NULL, base_fsp, &full_fname, smb_fname, &how);
|
||||
status = fsp_new(conn, conn, &fsp);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
GetTimeOfDay(&fsp->open_time);
|
||||
fsp_set_gen_id(fsp);
|
||||
ZERO_STRUCT(conn->sconn->fsp_fi_cache);
|
||||
|
||||
fsp->fsp_flags.is_pathref = true;
|
||||
|
||||
status = fsp_attach_smb_fname(fsp, &full_fname);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto fail;
|
||||
}
|
||||
fsp_set_base_fsp(fsp, base_fsp);
|
||||
|
||||
fd = SMB_VFS_OPENAT(conn,
|
||||
NULL, /* stream open is relative to fsp->base_fsp */
|
||||
smb_fname,
|
||||
fsp,
|
||||
&how);
|
||||
if (fd == -1) {
|
||||
status = map_nt_error_from_unix(errno);
|
||||
goto fail;
|
||||
}
|
||||
fsp_set_fd(fsp, fd);
|
||||
|
||||
status = vfs_stat_fsp(fsp);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DBG_DEBUG("vfs_stat_fsp failed: %s\n", nt_errstr(status));
|
||||
fd_close(fsp);
|
||||
goto fail;
|
||||
}
|
||||
smb_fname->st = fsp->fsp_name->st;
|
||||
|
||||
fsp->fsp_flags.is_directory = S_ISDIR(fsp->fsp_name->st.st_ex_mode);
|
||||
fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
|
||||
|
||||
status = fsp_smb_fname_link(fsp, &smb_fname->fsp_link, &smb_fname->fsp);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
DBG_DEBUG("fsp [%s]: OK\n", fsp_str_dbg(fsp));
|
||||
|
||||
talloc_set_destructor(smb_fname, smb_fname_fsp_destructor);
|
||||
return NT_STATUS_OK;
|
||||
fail:
|
||||
TALLOC_FREE(full_fname);
|
||||
if (fsp != NULL) {
|
||||
fsp_set_base_fsp(fsp, NULL);
|
||||
fd_close(fsp);
|
||||
file_free(NULL, fsp);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -1477,7 +1535,8 @@ NTSTATUS openat_pathref_fsp_lcomp(struct files_struct *dirfsp,
|
||||
*/
|
||||
|
||||
SMB_ASSERT((smb_fname_rel->fsp == NULL) &&
|
||||
(dirfsp != dirfsp->conn->cwd_fsp) &&
|
||||
((dirfsp != dirfsp->conn->cwd_fsp) ||
|
||||
ISDOT(smb_fname_rel->base_name)) &&
|
||||
(strchr_m(smb_fname_rel->base_name, '/') == NULL) &&
|
||||
!is_named_stream(smb_fname_rel));
|
||||
|
||||
@ -2412,52 +2471,6 @@ struct files_struct *file_fsp_smb2(struct smbd_smb2_request *smb2req,
|
||||
return fsp;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Duplicate the file handle part for a DOS or FCB open.
|
||||
****************************************************************************/
|
||||
|
||||
NTSTATUS dup_file_fsp(
|
||||
files_struct *from,
|
||||
uint32_t access_mask,
|
||||
files_struct *to)
|
||||
{
|
||||
size_t new_refcount;
|
||||
|
||||
/* this can never happen for print files */
|
||||
SMB_ASSERT(from->print_file == NULL);
|
||||
|
||||
TALLOC_FREE(to->fh);
|
||||
|
||||
to->fh = from->fh;
|
||||
new_refcount = fh_get_refcount(to->fh) + 1;
|
||||
fh_set_refcount(to->fh, new_refcount);
|
||||
|
||||
to->file_id = from->file_id;
|
||||
to->initial_allocation_size = from->initial_allocation_size;
|
||||
to->file_pid = from->file_pid;
|
||||
to->vuid = from->vuid;
|
||||
to->open_time = from->open_time;
|
||||
to->access_mask = access_mask;
|
||||
to->oplock_type = from->oplock_type;
|
||||
to->fsp_flags.can_lock = from->fsp_flags.can_lock;
|
||||
to->fsp_flags.can_read = ((access_mask & FILE_READ_DATA) != 0);
|
||||
to->fsp_flags.can_write =
|
||||
CAN_WRITE(from->conn) &&
|
||||
((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0);
|
||||
if (from->fsp_name->twrp != 0) {
|
||||
to->fsp_flags.can_write = false;
|
||||
}
|
||||
to->fsp_flags.modified = from->fsp_flags.modified;
|
||||
to->fsp_flags.is_directory = from->fsp_flags.is_directory;
|
||||
to->fsp_flags.aio_write_behind = from->fsp_flags.aio_write_behind;
|
||||
to->fsp_flags.is_fsa = from->fsp_flags.is_fsa;
|
||||
to->fsp_flags.is_pathref = from->fsp_flags.is_pathref;
|
||||
to->fsp_flags.have_proc_fds = from->fsp_flags.have_proc_fds;
|
||||
to->fsp_flags.is_dirfsp = from->fsp_flags.is_dirfsp;
|
||||
|
||||
return fsp_set_smb_fname(to, from->fsp_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a jenkins hash of a pathname on a connection.
|
||||
*/
|
||||
|
@ -467,383 +467,6 @@ static NTSTATUS check_base_file_access(struct files_struct *fsp,
|
||||
access_mask);
|
||||
}
|
||||
|
||||
static NTSTATUS chdir_below_conn(
|
||||
TALLOC_CTX *mem_ctx,
|
||||
connection_struct *conn,
|
||||
const char *connectpath,
|
||||
size_t connectpath_len,
|
||||
struct smb_filename *dir_fname,
|
||||
struct smb_filename **_oldwd_fname)
|
||||
{
|
||||
struct smb_filename *oldwd_fname = NULL;
|
||||
struct smb_filename *smb_fname_dot = NULL;
|
||||
struct smb_filename *real_fname = NULL;
|
||||
const char *relative = NULL;
|
||||
NTSTATUS status;
|
||||
int ret;
|
||||
bool ok;
|
||||
|
||||
if (!ISDOT(dir_fname->base_name)) {
|
||||
|
||||
oldwd_fname = vfs_GetWd(talloc_tos(), conn);
|
||||
if (oldwd_fname == NULL) {
|
||||
status = map_nt_error_from_unix(errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Pin parent directory in place. */
|
||||
ret = vfs_ChDir(conn, dir_fname);
|
||||
if (ret == -1) {
|
||||
status = map_nt_error_from_unix(errno);
|
||||
DBG_DEBUG("chdir to %s failed: %s\n",
|
||||
dir_fname->base_name,
|
||||
strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
smb_fname_dot = synthetic_smb_fname(
|
||||
talloc_tos(),
|
||||
".",
|
||||
NULL,
|
||||
NULL,
|
||||
dir_fname->twrp,
|
||||
dir_fname->flags);
|
||||
if (smb_fname_dot == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
real_fname = SMB_VFS_REALPATH(conn, talloc_tos(), smb_fname_dot);
|
||||
if (real_fname == NULL) {
|
||||
status = map_nt_error_from_unix(errno);
|
||||
DBG_DEBUG("realpath in %s failed: %s\n",
|
||||
dir_fname->base_name,
|
||||
strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
TALLOC_FREE(smb_fname_dot);
|
||||
|
||||
ok = subdir_of(connectpath,
|
||||
connectpath_len,
|
||||
real_fname->base_name,
|
||||
&relative);
|
||||
if (ok) {
|
||||
TALLOC_FREE(real_fname);
|
||||
*_oldwd_fname = oldwd_fname;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
DBG_NOTICE("Bad access attempt: %s is a symlink "
|
||||
"outside the share path\n"
|
||||
"conn_rootdir =%s\n"
|
||||
"resolved_name=%s\n",
|
||||
dir_fname->base_name,
|
||||
connectpath,
|
||||
real_fname->base_name);
|
||||
TALLOC_FREE(real_fname);
|
||||
|
||||
status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
|
||||
out:
|
||||
if (oldwd_fname != NULL) {
|
||||
ret = vfs_ChDir(conn, oldwd_fname);
|
||||
SMB_ASSERT(ret == 0);
|
||||
TALLOC_FREE(oldwd_fname);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the symlink target of dirfsp/symlink_name, making sure the
|
||||
* target is below connection_path.
|
||||
*/
|
||||
|
||||
static NTSTATUS symlink_target_below_conn(
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const char *connection_path,
|
||||
struct files_struct *fsp,
|
||||
struct files_struct *dirfsp,
|
||||
struct smb_filename *symlink_name,
|
||||
char **_target)
|
||||
{
|
||||
char *target = NULL;
|
||||
char *absolute = NULL;
|
||||
NTSTATUS status;
|
||||
|
||||
if (fsp_get_pathref_fd(fsp) != -1) {
|
||||
/*
|
||||
* fsp is an O_PATH open, Linux does a "freadlink"
|
||||
* with an empty name argument to readlinkat
|
||||
*/
|
||||
status = readlink_talloc(talloc_tos(), fsp, NULL, &target);
|
||||
} else {
|
||||
status = readlink_talloc(
|
||||
talloc_tos(), dirfsp, symlink_name, &target);
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = safe_symlink_target_path(talloc_tos(),
|
||||
connection_path,
|
||||
dirfsp->fsp_name->base_name,
|
||||
target,
|
||||
0,
|
||||
&absolute);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DBG_DEBUG("safe_symlink_target_path() failed: %s\n",
|
||||
nt_errstr(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
if (absolute[0] == '\0') {
|
||||
/*
|
||||
* special case symlink to share root: "." is our
|
||||
* share root filename
|
||||
*/
|
||||
TALLOC_FREE(absolute);
|
||||
absolute = talloc_strdup(talloc_tos(), ".");
|
||||
if (absolute == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
*_target = absolute;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Non-widelink open.
|
||||
****************************************************************************/
|
||||
|
||||
static NTSTATUS non_widelink_open(const struct files_struct *dirfsp,
|
||||
files_struct *fsp,
|
||||
struct smb_filename *smb_fname,
|
||||
const struct vfs_open_how *_how)
|
||||
{
|
||||
struct connection_struct *conn = fsp->conn;
|
||||
const char *connpath = SMB_VFS_CONNECTPATH(conn, dirfsp, smb_fname);
|
||||
size_t connpath_len;
|
||||
NTSTATUS status = NT_STATUS_OK;
|
||||
int fd = -1;
|
||||
char *orig_smb_fname_base = smb_fname->base_name;
|
||||
struct smb_filename *orig_fsp_name = fsp->fsp_name;
|
||||
struct smb_filename *smb_fname_rel = NULL;
|
||||
struct smb_filename *oldwd_fname = NULL;
|
||||
struct smb_filename *parent_dir_fname = NULL;
|
||||
struct vfs_open_how how = *_how;
|
||||
char *target = NULL;
|
||||
size_t link_depth = 0;
|
||||
int ret;
|
||||
|
||||
SMB_ASSERT(!fsp_is_alternate_stream(fsp));
|
||||
|
||||
if (connpath == NULL) {
|
||||
/*
|
||||
* This can happen with shadow_copy2 if the snapshot
|
||||
* path is not found
|
||||
*/
|
||||
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
}
|
||||
connpath_len = strlen(connpath);
|
||||
|
||||
again:
|
||||
if (smb_fname->base_name[0] == '/') {
|
||||
int cmp = strcmp(connpath, smb_fname->base_name);
|
||||
if (cmp == 0) {
|
||||
smb_fname->base_name = talloc_strdup(smb_fname, "");
|
||||
if (smb_fname->base_name == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dirfsp == conn->cwd_fsp) {
|
||||
|
||||
status = SMB_VFS_PARENT_PATHNAME(fsp->conn,
|
||||
talloc_tos(),
|
||||
smb_fname,
|
||||
&parent_dir_fname,
|
||||
&smb_fname_rel);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = chdir_below_conn(
|
||||
talloc_tos(),
|
||||
conn,
|
||||
connpath,
|
||||
connpath_len,
|
||||
parent_dir_fname,
|
||||
&oldwd_fname);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Setup fsp->fsp_name to be relative to cwd */
|
||||
fsp->fsp_name = smb_fname_rel;
|
||||
} else {
|
||||
/*
|
||||
* fsp->fsp_name is unchanged as it is already correctly
|
||||
* relative to dirfsp.
|
||||
*/
|
||||
smb_fname_rel = smb_fname;
|
||||
}
|
||||
|
||||
{
|
||||
/*
|
||||
* Assert nobody can step in with a symlink on the
|
||||
* path, there is no path anymore and we'll use
|
||||
* O_NOFOLLOW to open.
|
||||
*/
|
||||
char *slash = strchr_m(smb_fname_rel->base_name, '/');
|
||||
SMB_ASSERT(slash == NULL);
|
||||
}
|
||||
|
||||
how.flags |= O_NOFOLLOW;
|
||||
|
||||
fd = SMB_VFS_OPENAT(conn,
|
||||
dirfsp,
|
||||
smb_fname_rel,
|
||||
fsp,
|
||||
&how);
|
||||
fsp_set_fd(fsp, fd); /* This preserves errno */
|
||||
|
||||
if (fd == -1) {
|
||||
status = map_nt_error_from_unix(errno);
|
||||
|
||||
if (errno == ENOENT) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* ENOENT makes it worthless retrying with a
|
||||
* stat, we know for sure the file does not
|
||||
* exist. For everything else we want to know
|
||||
* what's there.
|
||||
*/
|
||||
ret = SMB_VFS_FSTATAT(
|
||||
fsp->conn,
|
||||
dirfsp,
|
||||
smb_fname_rel,
|
||||
&fsp->fsp_name->st,
|
||||
AT_SYMLINK_NOFOLLOW);
|
||||
|
||||
if (ret == -1) {
|
||||
/*
|
||||
* Keep the original error. Otherwise we would
|
||||
* mask for example EROFS for open(O_CREAT),
|
||||
* turning it into ENOENT.
|
||||
*/
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
|
||||
}
|
||||
|
||||
if (ret == -1) {
|
||||
status = map_nt_error_from_unix(errno);
|
||||
DBG_DEBUG("fstat[at](%s) failed: %s\n",
|
||||
smb_fname_str_dbg(smb_fname),
|
||||
strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
fsp->fsp_flags.is_directory = S_ISDIR(fsp->fsp_name->st.st_ex_mode);
|
||||
orig_fsp_name->st = fsp->fsp_name->st;
|
||||
|
||||
if (!S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Found a symlink to follow in user space
|
||||
*/
|
||||
|
||||
if (fsp->fsp_name->flags & SMB_FILENAME_POSIX_PATH) {
|
||||
/* Never follow symlinks on posix open. */
|
||||
status = NT_STATUS_STOPPED_ON_SYMLINK;
|
||||
goto out;
|
||||
}
|
||||
if (!lp_follow_symlinks(SNUM(conn))) {
|
||||
/* Explicitly no symlinks. */
|
||||
status = NT_STATUS_STOPPED_ON_SYMLINK;
|
||||
goto out;
|
||||
}
|
||||
|
||||
link_depth += 1;
|
||||
if (link_depth >= 40) {
|
||||
status = NT_STATUS_STOPPED_ON_SYMLINK;
|
||||
goto out;
|
||||
}
|
||||
|
||||
fsp->fsp_name = orig_fsp_name;
|
||||
|
||||
status = symlink_target_below_conn(
|
||||
talloc_tos(),
|
||||
connpath,
|
||||
fsp,
|
||||
discard_const_p(files_struct, dirfsp),
|
||||
smb_fname_rel,
|
||||
&target);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DBG_DEBUG("symlink_target_below_conn() failed: %s\n",
|
||||
nt_errstr(status));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Close what openat(O_PATH) potentially left behind
|
||||
*/
|
||||
fd_close(fsp);
|
||||
|
||||
if (smb_fname->base_name != orig_smb_fname_base) {
|
||||
TALLOC_FREE(smb_fname->base_name);
|
||||
}
|
||||
smb_fname->base_name = target;
|
||||
|
||||
if (oldwd_fname != NULL) {
|
||||
ret = vfs_ChDir(conn, oldwd_fname);
|
||||
if (ret == -1) {
|
||||
smb_panic("unable to get back to old directory\n");
|
||||
}
|
||||
TALLOC_FREE(oldwd_fname);
|
||||
}
|
||||
|
||||
/*
|
||||
* And do it all again... As smb_fname is not relative to the passed in
|
||||
* dirfsp anymore, we pass conn->cwd_fsp as dirfsp to
|
||||
* non_widelink_open() to trigger the chdir(parentdir) logic.
|
||||
*/
|
||||
dirfsp = conn->cwd_fsp;
|
||||
|
||||
goto again;
|
||||
|
||||
out:
|
||||
fsp->fsp_name = orig_fsp_name;
|
||||
smb_fname->base_name = orig_smb_fname_base;
|
||||
|
||||
TALLOC_FREE(parent_dir_fname);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
fd_close(fsp);
|
||||
}
|
||||
|
||||
if (oldwd_fname != NULL) {
|
||||
ret = vfs_ChDir(conn, oldwd_fname);
|
||||
if (ret == -1) {
|
||||
smb_panic("unable to get back to old directory\n");
|
||||
}
|
||||
TALLOC_FREE(oldwd_fname);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
fd support routines - attempt to do a dos_open.
|
||||
****************************************************************************/
|
||||
@ -858,21 +481,16 @@ NTSTATUS fd_openat(const struct files_struct *dirfsp,
|
||||
NTSTATUS status = NT_STATUS_OK;
|
||||
bool fsp_is_stream = fsp_is_alternate_stream(fsp);
|
||||
bool smb_fname_is_stream = is_named_stream(smb_fname);
|
||||
struct files_struct *dirfsp_conv = NULL;
|
||||
struct smb_filename *smb_fname_conv = NULL;
|
||||
struct smb_filename *smb_fname_rel = NULL;
|
||||
struct files_struct *root_fsp = NULL;
|
||||
const char *name_in = smb_fname->base_name;
|
||||
int fd;
|
||||
|
||||
SMB_ASSERT(fsp_is_stream == smb_fname_is_stream);
|
||||
|
||||
/*
|
||||
* Never follow symlinks on a POSIX client. The
|
||||
* client should be doing this.
|
||||
*/
|
||||
|
||||
if (fsp->fsp_flags.posix_open || !lp_follow_symlinks(SNUM(conn))) {
|
||||
how.flags |= O_NOFOLLOW;
|
||||
}
|
||||
|
||||
if (fsp_is_stream) {
|
||||
int fd;
|
||||
|
||||
fd = SMB_VFS_OPENAT(
|
||||
conn,
|
||||
NULL, /* stream open is relative to fsp->base_fsp */
|
||||
@ -882,26 +500,100 @@ NTSTATUS fd_openat(const struct files_struct *dirfsp,
|
||||
if (fd == -1) {
|
||||
status = map_nt_error_from_unix(errno);
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
how.flags |= O_NOFOLLOW; /* just to be sure */
|
||||
|
||||
if (strchr(smb_fname->base_name, '/') == NULL) {
|
||||
/*
|
||||
* With O_NOFOLLOW and no intermediate path components
|
||||
* we can try directly.
|
||||
*/
|
||||
fd = SMB_VFS_OPENAT(conn, dirfsp, smb_fname, fsp, &how);
|
||||
if (fd >= 0) {
|
||||
fsp_set_fd(fsp, fd);
|
||||
|
||||
if (fd != -1) {
|
||||
status = vfs_stat_fsp(fsp);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DBG_DEBUG("vfs_stat_fsp failed: %s\n",
|
||||
nt_errstr(status));
|
||||
fd_close(fsp);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
if (NT_STATUS_IS_OK(status) &&
|
||||
!S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
|
||||
smb_fname->st = fsp->fsp_name->st;
|
||||
fsp->fsp_flags.is_directory = S_ISDIR(
|
||||
fsp->fsp_name->st.st_ex_mode);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only follow symlinks within a share
|
||||
* definition.
|
||||
* We found a symlink in the lcomp via O_PATH,
|
||||
* let filename_convert_dirfsp_rel follow
|
||||
* it. This means we're going to open the
|
||||
* symlink twice, but this is something to
|
||||
* optimize when it becomes a problem.
|
||||
*/
|
||||
status = non_widelink_open(dirfsp, fsp, smb_fname, &how);
|
||||
SMB_VFS_CLOSE(fsp);
|
||||
fsp_set_fd(fsp, -1);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (name_in[0] == '/') {
|
||||
/*
|
||||
* filename_convert_dirfsp can't deal with absolute
|
||||
* paths, make this relative to "/"
|
||||
*/
|
||||
name_in += 1;
|
||||
status = open_rootdir_pathref_fsp(conn, &root_fsp);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
dirfsp = root_fsp;
|
||||
}
|
||||
|
||||
if (ISDOT(name_in)) {
|
||||
/*
|
||||
* filename_convert_dirfsp does not like ".", use ""
|
||||
*/
|
||||
name_in += 1;
|
||||
}
|
||||
|
||||
status = filename_convert_dirfsp_rel(
|
||||
talloc_tos(),
|
||||
conn,
|
||||
discard_const_p(struct files_struct, dirfsp),
|
||||
name_in,
|
||||
UCF_POSIX_PATHNAMES, /* no case insensitive search */
|
||||
smb_fname->twrp,
|
||||
&dirfsp_conv,
|
||||
&smb_fname_conv,
|
||||
&smb_fname_rel);
|
||||
|
||||
dirfsp = NULL;
|
||||
if (root_fsp != NULL) {
|
||||
fd_close(root_fsp);
|
||||
file_free(NULL, root_fsp);
|
||||
root_fsp = NULL;
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DBG_DEBUG("filename_convert_dirfsp_rel returned %s\n",
|
||||
nt_errstr(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
fd = SMB_VFS_OPENAT(conn, dirfsp_conv, smb_fname_rel, fsp, &how);
|
||||
|
||||
if (fd == -1) {
|
||||
status = map_nt_error_from_unix(errno);
|
||||
}
|
||||
|
||||
fd_close(dirfsp_conv);
|
||||
file_free(NULL, dirfsp_conv);
|
||||
dirfsp_conv = NULL;
|
||||
TALLOC_FREE(smb_fname_conv);
|
||||
|
||||
done:
|
||||
fsp_set_fd(fsp, fd); /* This preserves errno */
|
||||
|
||||
if (fd == -1) {
|
||||
if (NT_STATUS_EQUAL(status, NT_STATUS_TOO_MANY_OPENED_FILES)) {
|
||||
static time_t last_warned = 0L;
|
||||
|
||||
@ -921,7 +613,18 @@ NTSTATUS fd_openat(const struct files_struct *dirfsp,
|
||||
fsp_get_pathref_fd(fsp),
|
||||
nt_errstr(status));
|
||||
return status;
|
||||
} else {
|
||||
status = vfs_stat_fsp(fsp);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DBG_DEBUG("vfs_stat_fsp failed: %s\n",
|
||||
nt_errstr(status));
|
||||
fd_close(fsp);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
smb_fname->st = fsp->fsp_name->st;
|
||||
fsp->fsp_flags.is_directory = S_ISDIR(fsp->fsp_name->st.st_ex_mode);
|
||||
|
||||
DBG_DEBUG("name %s, flags = 0%o mode = 0%o, fd = %d\n",
|
||||
smb_fname_str_dbg(smb_fname),
|
||||
@ -1153,7 +856,7 @@ static NTSTATUS fd_open_atomic(struct files_struct *dirfsp,
|
||||
return status;
|
||||
}
|
||||
|
||||
static NTSTATUS reopen_from_fsp(struct files_struct *dirfsp,
|
||||
NTSTATUS reopen_from_fsp(struct files_struct *dirfsp,
|
||||
struct smb_filename *smb_fname,
|
||||
struct files_struct *fsp,
|
||||
const struct vfs_open_how *how,
|
||||
@ -1172,8 +875,6 @@ static NTSTATUS reopen_from_fsp(struct files_struct *dirfsp,
|
||||
mode_t mode = fsp->fsp_name->st.st_ex_mode;
|
||||
int new_fd;
|
||||
|
||||
SMB_ASSERT(fsp->fsp_flags.is_pathref);
|
||||
|
||||
if (S_ISLNK(mode)) {
|
||||
return NT_STATUS_STOPPED_ON_SYMLINK;
|
||||
}
|
||||
|
@ -344,10 +344,6 @@ struct files_struct *file_fsp_get(struct smbd_smb2_request *smb2req,
|
||||
struct files_struct *file_fsp_smb2(struct smbd_smb2_request *smb2req,
|
||||
uint64_t persistent_id,
|
||||
uint64_t volatile_id);
|
||||
NTSTATUS dup_file_fsp(
|
||||
files_struct *from,
|
||||
uint32_t access_mask,
|
||||
files_struct *to);
|
||||
NTSTATUS file_name_hash(connection_struct *conn,
|
||||
const char *name, uint32_t *p_name_hash);
|
||||
NTSTATUS fsp_set_smb_fname(struct files_struct *fsp,
|
||||
@ -370,11 +366,9 @@ NTSTATUS open_internal_dirfsp(connection_struct *conn,
|
||||
const struct smb_filename *smb_dname,
|
||||
int open_flags,
|
||||
struct files_struct **_fsp);
|
||||
NTSTATUS openat_internal_dir_from_pathref(
|
||||
struct files_struct *dirfsp,
|
||||
int open_flags,
|
||||
struct files_struct **_fsp);
|
||||
|
||||
NTSTATUS open_rootdir_pathref_fsp(connection_struct *conn,
|
||||
struct files_struct **_fsp);
|
||||
NTSTATUS openat_pathref_fsp(const struct files_struct *dirfsp,
|
||||
struct smb_filename *smb_fname);
|
||||
NTSTATUS open_stream_pathref_fsp(
|
||||
@ -669,6 +663,11 @@ NTSTATUS fd_openat(const struct files_struct *dirfsp,
|
||||
files_struct *fsp,
|
||||
const struct vfs_open_how *how);
|
||||
NTSTATUS fd_close(files_struct *fsp);
|
||||
NTSTATUS reopen_from_fsp(struct files_struct *dirfsp,
|
||||
struct smb_filename *smb_fname,
|
||||
struct files_struct *fsp,
|
||||
const struct vfs_open_how *how,
|
||||
bool *p_file_created);
|
||||
bool is_oplock_stat_open(uint32_t access_mask);
|
||||
bool is_lease_stat_open(uint32_t access_mask);
|
||||
NTSTATUS send_break_message(struct messaging_context *msg_ctx,
|
||||
@ -1061,12 +1060,12 @@ NTSTATUS smb_set_file_disposition_info(connection_struct *conn,
|
||||
int total_data,
|
||||
files_struct *fsp,
|
||||
struct smb_filename *smb_fname);
|
||||
NTSTATUS refuse_symlink_fsp(const struct files_struct *fsp);
|
||||
bool refuse_symlink_fsp(const struct files_struct *fsp);
|
||||
NTSTATUS check_any_access_fsp(struct files_struct *fsp,
|
||||
uint32_t access_requested);
|
||||
uint64_t smb_roundup(connection_struct *conn, uint64_t val);
|
||||
bool samba_private_attr_name(const char *unix_ea_name);
|
||||
NTSTATUS get_ea_value_fsp(TALLOC_CTX *mem_ctx,
|
||||
int get_ea_value_fsp(TALLOC_CTX *mem_ctx,
|
||||
files_struct *fsp,
|
||||
const char *ea_name,
|
||||
struct ea_struct *pea);
|
||||
|
@ -133,8 +133,9 @@ static int set_sys_acl_conn(const char *fname,
|
||||
TALLOC_CTX *frame = talloc_stackframe();
|
||||
NTSTATUS status;
|
||||
|
||||
smb_fname = synthetic_smb_fname_split(frame,
|
||||
fname,
|
||||
smb_fname = synthetic_smb_fname_split(
|
||||
frame,
|
||||
canonicalize_absolute_path(talloc_tos(), fname),
|
||||
lp_posix_pathnames());
|
||||
if (smb_fname == NULL) {
|
||||
TALLOC_FREE(frame);
|
||||
@ -186,8 +187,9 @@ static NTSTATUS init_files_struct(TALLOC_CTX *mem_ctx,
|
||||
}
|
||||
fsp->conn = conn;
|
||||
|
||||
smb_fname = synthetic_smb_fname_split(fsp,
|
||||
fname,
|
||||
smb_fname = synthetic_smb_fname_split(
|
||||
fsp,
|
||||
canonicalize_absolute_path(talloc_tos(), fname),
|
||||
lp_posix_pathnames());
|
||||
if (smb_fname == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
@ -302,8 +304,9 @@ static NTSTATUS get_nt_acl_conn(TALLOC_CTX *mem_ctx,
|
||||
NTSTATUS status;
|
||||
struct smb_filename *smb_fname = NULL;
|
||||
|
||||
smb_fname = synthetic_smb_fname_split(frame,
|
||||
fname,
|
||||
smb_fname = synthetic_smb_fname_split(
|
||||
frame,
|
||||
canonicalize_absolute_path(talloc_tos(), fname),
|
||||
lp_posix_pathnames());
|
||||
|
||||
if (smb_fname == NULL) {
|
||||
@ -697,8 +700,9 @@ static PyObject *py_smbd_unlink(PyObject *self, PyObject *args, PyObject *kwargs
|
||||
return NULL;
|
||||
}
|
||||
|
||||
smb_fname = synthetic_smb_fname_split(frame,
|
||||
fname,
|
||||
smb_fname = synthetic_smb_fname_split(
|
||||
frame,
|
||||
canonicalize_absolute_path(talloc_tos(), fname),
|
||||
lp_posix_pathnames());
|
||||
if (smb_fname == NULL) {
|
||||
TALLOC_FREE(frame);
|
||||
@ -1038,8 +1042,9 @@ static PyObject *py_smbd_get_sys_acl(PyObject *self, PyObject *args, PyObject *k
|
||||
return NULL;
|
||||
}
|
||||
|
||||
smb_fname = synthetic_smb_fname_split(frame,
|
||||
fname,
|
||||
smb_fname = synthetic_smb_fname_split(
|
||||
frame,
|
||||
canonicalize_absolute_path(talloc_tos(), fname),
|
||||
lp_posix_pathnames());
|
||||
if (smb_fname == NULL) {
|
||||
TALLOC_FREE(frame);
|
||||
@ -1127,13 +1132,13 @@ static PyObject *py_smbd_mkdir(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
smb_fname = synthetic_smb_fname(talloc_tos(),
|
||||
fname,
|
||||
smb_fname = synthetic_smb_fname(
|
||||
talloc_tos(),
|
||||
canonicalize_absolute_path(talloc_tos(), fname),
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
lp_posix_pathnames() ?
|
||||
SMB_FILENAME_POSIX_PATH : 0);
|
||||
lp_posix_pathnames() ? SMB_FILENAME_POSIX_PATH : 0);
|
||||
|
||||
if (smb_fname == NULL) {
|
||||
TALLOC_FREE(frame);
|
||||
|
@ -2389,7 +2389,7 @@ static NTSTATUS smb_q_posix_acl(
|
||||
uint16_t num_def_acls = 0;
|
||||
unsigned int size_needed = 0;
|
||||
NTSTATUS status;
|
||||
bool ok;
|
||||
bool ok, refuse;
|
||||
bool close_fsp = false;
|
||||
|
||||
/*
|
||||
@ -2415,8 +2415,9 @@ static NTSTATUS smb_q_posix_acl(
|
||||
|
||||
SMB_ASSERT(fsp != NULL);
|
||||
|
||||
status = refuse_symlink_fsp(fsp);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
refuse = refuse_symlink_fsp(fsp);
|
||||
if (refuse) {
|
||||
status = NT_STATUS_ACCESS_DENIED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -4273,6 +4274,7 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn,
|
||||
unsigned int size_needed;
|
||||
unsigned int total_data;
|
||||
bool close_fsp = false;
|
||||
bool refuse;
|
||||
|
||||
if (total_data_in < 0) {
|
||||
status = NT_STATUS_INVALID_PARAMETER;
|
||||
@ -4359,8 +4361,9 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn,
|
||||
/* Here we know fsp != NULL */
|
||||
SMB_ASSERT(fsp != NULL);
|
||||
|
||||
status = refuse_symlink_fsp(fsp);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
refuse = refuse_symlink_fsp(fsp);
|
||||
if (refuse) {
|
||||
status = NT_STATUS_ACCESS_DENIED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,7 @@ struct files_struct *fcb_or_dos_open(
|
||||
struct connection_struct *conn = req->conn;
|
||||
struct file_id id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
|
||||
struct files_struct *fsp = NULL, *new_fsp = NULL;
|
||||
size_t new_refcount;
|
||||
NTSTATUS status;
|
||||
|
||||
if ((private_flags &
|
||||
@ -97,10 +98,35 @@ struct files_struct *fcb_or_dos_open(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
status = dup_file_fsp(fsp, access_mask, new_fsp);
|
||||
/*
|
||||
* Share the fsp->fh between old and new
|
||||
*/
|
||||
TALLOC_FREE(new_fsp->fh);
|
||||
new_fsp->fh = fsp->fh;
|
||||
new_refcount = fh_get_refcount(new_fsp->fh) + 1;
|
||||
fh_set_refcount(new_fsp->fh, new_refcount);
|
||||
|
||||
new_fsp->file_id = fsp->file_id;
|
||||
new_fsp->initial_allocation_size = fsp->initial_allocation_size;
|
||||
new_fsp->file_pid = fsp->file_pid;
|
||||
new_fsp->vuid = fsp->vuid;
|
||||
new_fsp->open_time = fsp->open_time;
|
||||
new_fsp->access_mask = access_mask;
|
||||
new_fsp->oplock_type = fsp->oplock_type;
|
||||
new_fsp->fsp_flags = fsp->fsp_flags;
|
||||
new_fsp->fsp_flags.can_read = ((access_mask & FILE_READ_DATA) != 0);
|
||||
new_fsp->fsp_flags.can_write = CAN_WRITE(fsp->conn) &&
|
||||
((access_mask & (FILE_WRITE_DATA |
|
||||
FILE_APPEND_DATA)) !=
|
||||
0);
|
||||
if (fsp->fsp_name->twrp != 0) {
|
||||
new_fsp->fsp_flags.can_write = false;
|
||||
}
|
||||
|
||||
status = fsp_set_smb_fname(new_fsp, fsp->fsp_name);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DBG_DEBUG("dup_file_fsp failed: %s\n", nt_errstr(status));
|
||||
DBG_DEBUG("fsp_set_smb_fname failed: %s\n", nt_errstr(status));
|
||||
file_free(req, new_fsp);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -83,6 +83,7 @@ NTSTATUS set_sd(files_struct *fsp, struct security_descriptor *psd,
|
||||
{
|
||||
files_struct *sd_fsp = NULL;
|
||||
NTSTATUS status;
|
||||
bool refuse;
|
||||
|
||||
if (!CAN_WRITE(fsp->conn)) {
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
@ -92,11 +93,11 @@ NTSTATUS set_sd(files_struct *fsp, struct security_descriptor *psd,
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
status = refuse_symlink_fsp(fsp);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
refuse = refuse_symlink_fsp(fsp);
|
||||
if (refuse) {
|
||||
DBG_DEBUG("ACL set on symlink %s denied.\n",
|
||||
fsp_str_dbg(fsp));
|
||||
return status;
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
if (psd->owner_sid == NULL) {
|
||||
@ -480,6 +481,7 @@ static NTSTATUS smbd_fetch_security_desc(connection_struct *conn,
|
||||
NTSTATUS status;
|
||||
struct security_descriptor *psd = NULL;
|
||||
bool need_to_read_sd = false;
|
||||
bool refuse;
|
||||
|
||||
/*
|
||||
* Get the permissions to return.
|
||||
@ -501,11 +503,11 @@ static NTSTATUS smbd_fetch_security_desc(connection_struct *conn,
|
||||
}
|
||||
}
|
||||
|
||||
status = refuse_symlink_fsp(fsp);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
refuse = refuse_symlink_fsp(fsp);
|
||||
if (refuse) {
|
||||
DBG_DEBUG("ACL get on symlink %s denied.\n",
|
||||
fsp_str_dbg(fsp));
|
||||
return status;
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
if (security_info_wanted & (SECINFO_DACL|SECINFO_OWNER|
|
||||
|
@ -381,21 +381,17 @@ static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx,
|
||||
|
||||
if (in_flags & SMB2_CONTINUE_FLAG_REOPEN) {
|
||||
struct vfs_open_how how = { .flags = O_RDONLY, };
|
||||
|
||||
status = fd_close(fsp);
|
||||
if (tevent_req_nterror(req, status)) {
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
/*
|
||||
* fd_close() will close and invalidate the fsp's file
|
||||
* descriptor. So we have to reopen it.
|
||||
*/
|
||||
bool file_was_created;
|
||||
|
||||
#ifdef O_DIRECTORY
|
||||
how.flags |= O_DIRECTORY;
|
||||
#endif
|
||||
status = fd_openat(conn->cwd_fsp, fsp->fsp_name, fsp, &how);
|
||||
|
||||
status = reopen_from_fsp(conn->cwd_fsp,
|
||||
fsp->fsp_name,
|
||||
fsp,
|
||||
&how,
|
||||
&file_was_created);
|
||||
if (tevent_req_nterror(req, status)) {
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
@ -785,22 +785,26 @@ NTSTATUS make_connection_snum(struct smbXsrv_connection *xconn,
|
||||
I have disabled this chdir check (tridge) */
|
||||
/* the alternative is just to check the directory exists */
|
||||
|
||||
if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 ||
|
||||
!S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
|
||||
if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
|
||||
DBG_ERR("'%s' is not a directory, when connecting to "
|
||||
"[%s]\n", conn->connectpath,
|
||||
lp_const_servicename(snum));
|
||||
} else {
|
||||
ret = SMB_VFS_STAT(conn, smb_fname_cpath);
|
||||
if (ret != 0) {
|
||||
DBG_ERR("'%s' does not exist or permission denied "
|
||||
"when connecting to [%s] Error was %s\n",
|
||||
conn->connectpath,
|
||||
lp_const_servicename(snum),
|
||||
strerror(errno));
|
||||
}
|
||||
status = NT_STATUS_BAD_NETWORK_NAME;
|
||||
goto err_root_exit;
|
||||
}
|
||||
|
||||
if (!S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
|
||||
DBG_ERR("'%s' is not a directory, when connecting to "
|
||||
"[%s]\n",
|
||||
conn->connectpath,
|
||||
lp_const_servicename(snum));
|
||||
status = NT_STATUS_BAD_NETWORK_NAME;
|
||||
goto err_root_exit;
|
||||
}
|
||||
|
||||
conn->base_share_dev = smb_fname_cpath->st.st_ex_dev;
|
||||
|
||||
/* Figure out the characteristics of the underlying filesystem. This
|
||||
|
@ -60,19 +60,19 @@ static uint32_t generate_volume_serial_number(
|
||||
Check if an open file handle is a symlink.
|
||||
****************************************************************************/
|
||||
|
||||
NTSTATUS refuse_symlink_fsp(const files_struct *fsp)
|
||||
bool refuse_symlink_fsp(const files_struct *fsp)
|
||||
{
|
||||
|
||||
if (!VALID_STAT(fsp->fsp_name->st)) {
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
return true;
|
||||
}
|
||||
if (S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
return true;
|
||||
}
|
||||
if (fsp_get_pathref_fd(fsp) == -1) {
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
return true;
|
||||
}
|
||||
return NT_STATUS_OK;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -184,7 +184,7 @@ bool samba_private_attr_name(const char *unix_ea_name)
|
||||
Get one EA value. Fill in a struct ea_struct.
|
||||
****************************************************************************/
|
||||
|
||||
NTSTATUS get_ea_value_fsp(TALLOC_CTX *mem_ctx,
|
||||
int get_ea_value_fsp(TALLOC_CTX *mem_ctx,
|
||||
files_struct *fsp,
|
||||
const char *ea_name,
|
||||
struct ea_struct *pea)
|
||||
@ -194,14 +194,14 @@ NTSTATUS get_ea_value_fsp(TALLOC_CTX *mem_ctx,
|
||||
char *val = NULL;
|
||||
ssize_t sizeret;
|
||||
size_t max_xattr_size = 0;
|
||||
NTSTATUS status;
|
||||
bool refuse;
|
||||
|
||||
if (fsp == NULL) {
|
||||
return NT_STATUS_INVALID_HANDLE;
|
||||
return EINVAL;
|
||||
}
|
||||
status = refuse_symlink_fsp(fsp);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return status;
|
||||
refuse = refuse_symlink_fsp(fsp);
|
||||
if (refuse) {
|
||||
return EACCES;
|
||||
}
|
||||
|
||||
max_xattr_size = lp_smbd_max_xattr_size(SNUM(fsp->conn));
|
||||
@ -210,7 +210,7 @@ NTSTATUS get_ea_value_fsp(TALLOC_CTX *mem_ctx,
|
||||
|
||||
val = talloc_realloc(mem_ctx, val, char, attr_size);
|
||||
if (!val) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
sizeret = SMB_VFS_FGETXATTR(fsp, ea_name, val, attr_size);
|
||||
@ -220,7 +220,7 @@ NTSTATUS get_ea_value_fsp(TALLOC_CTX *mem_ctx,
|
||||
}
|
||||
|
||||
if (sizeret == -1) {
|
||||
return map_nt_error_from_unix(errno);
|
||||
return errno;
|
||||
}
|
||||
|
||||
DBG_DEBUG("EA %s is of length %zd\n", ea_name, sizeret);
|
||||
@ -234,11 +234,11 @@ NTSTATUS get_ea_value_fsp(TALLOC_CTX *mem_ctx,
|
||||
}
|
||||
if (pea->name == NULL) {
|
||||
TALLOC_FREE(val);
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
return ENOMEM;
|
||||
}
|
||||
pea->value.data = (unsigned char *)val;
|
||||
pea->value.length = (size_t)sizeret;
|
||||
return NT_STATUS_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NTSTATUS get_ea_names_from_fsp(TALLOC_CTX *mem_ctx,
|
||||
@ -263,7 +263,7 @@ NTSTATUS get_ea_names_from_fsp(TALLOC_CTX *mem_ctx,
|
||||
}
|
||||
*pnum_names = 0;
|
||||
|
||||
if ((fsp == NULL) || !NT_STATUS_IS_OK(refuse_symlink_fsp(fsp))) {
|
||||
if ((fsp == NULL) || refuse_symlink_fsp(fsp)) {
|
||||
/*
|
||||
* Callers may pass fsp == NULL when passing smb_fname->fsp of a
|
||||
* symlink. This is ok, handle it here, by just return no EA's
|
||||
@ -410,6 +410,7 @@ static NTSTATUS get_ea_list_from_fsp(TALLOC_CTX *mem_ctx,
|
||||
for (i=0; i<num_names; i++) {
|
||||
struct ea_list *listp;
|
||||
fstring dos_ea_name;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* POSIX EA names are divided into several namespaces by
|
||||
@ -441,14 +442,11 @@ static NTSTATUS get_ea_list_from_fsp(TALLOC_CTX *mem_ctx,
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
status = get_ea_value_fsp(listp,
|
||||
fsp,
|
||||
names[i],
|
||||
&listp->ea);
|
||||
ret = get_ea_value_fsp(listp, fsp, names[i], &listp->ea);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
if (ret != 0) {
|
||||
TALLOC_FREE(listp);
|
||||
return status;
|
||||
return map_nt_error_from_unix(ret);
|
||||
}
|
||||
|
||||
if (listp->ea.value.length == 0) {
|
||||
@ -711,6 +709,7 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp,
|
||||
{
|
||||
NTSTATUS status;
|
||||
bool posix_pathnames = false;
|
||||
bool refuse;
|
||||
|
||||
if (!lp_ea_support(SNUM(conn))) {
|
||||
return NT_STATUS_EAS_NOT_SUPPORTED;
|
||||
@ -722,9 +721,9 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp,
|
||||
|
||||
posix_pathnames = (fsp->fsp_name->flags & SMB_FILENAME_POSIX_PATH);
|
||||
|
||||
status = refuse_symlink_fsp(fsp);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return status;
|
||||
refuse = refuse_symlink_fsp(fsp);
|
||||
if (refuse) {
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
status = check_any_access_fsp(fsp, FILE_WRITE_EA);
|
||||
|
@ -453,9 +453,8 @@ static void print_impersonation_info(connection_struct *conn)
|
||||
return;
|
||||
}
|
||||
|
||||
if (conn->tcon_done) {
|
||||
cwdfname = vfs_GetWd(talloc_tos(), conn);
|
||||
if (cwdfname == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
DBG_INFO("Impersonated user: uid=(%d,%d), gid=(%d,%d), cwd=[%s]\n",
|
||||
@ -463,7 +462,7 @@ static void print_impersonation_info(connection_struct *conn)
|
||||
(int)geteuid(),
|
||||
(int)getgid(),
|
||||
(int)getegid(),
|
||||
cwdfname->base_name);
|
||||
cwdfname ? cwdfname->base_name : "no cwd");
|
||||
TALLOC_FREE(cwdfname);
|
||||
}
|
||||
|
||||
|
@ -1022,6 +1022,9 @@ struct smb_filename *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
|
||||
if (!lp_getwd_cache()) {
|
||||
goto nocache;
|
||||
}
|
||||
if (fsp_get_pathref_fd(conn->cwd_fsp) == -1) {
|
||||
goto nocache;
|
||||
}
|
||||
|
||||
smb_fname_dot = synthetic_smb_fname(ctx,
|
||||
".",
|
||||
@ -1086,7 +1089,7 @@ struct smb_filename *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (lp_getwd_cache() && VALID_STAT(smb_fname_dot->st)) {
|
||||
if ((smb_fname_dot != NULL) && VALID_STAT(smb_fname_dot->st)) {
|
||||
key = vfs_file_id_from_sbuf(conn, &smb_fname_dot->st);
|
||||
|
||||
/*
|
||||
|
@ -144,6 +144,7 @@ static int net_vfs_init(struct net_context *c, int argc, const char **argv)
|
||||
sec_init();
|
||||
setup_logging("net", DEBUG_STDOUT);
|
||||
lpcfg_set_cmdline(c->lp_ctx, "log level", "0");
|
||||
mangle_change_to_posix();
|
||||
|
||||
ok = lp_load_with_registry_shares(get_dyn_CONFIGFILE());
|
||||
if (!ok) {
|
||||
|
@ -60,31 +60,27 @@
|
||||
|
||||
struct samr_Password *smbpasswd_gethexpwd(TALLOC_CTX *mem_ctx, const char *p)
|
||||
{
|
||||
int i;
|
||||
unsigned char lonybble, hinybble;
|
||||
const char *hexchars = "0123456789ABCDEF";
|
||||
const char *p1, *p2;
|
||||
struct samr_Password *pwd = talloc(mem_ctx, struct samr_Password);
|
||||
struct samr_Password *pwd = NULL;
|
||||
size_t len;
|
||||
|
||||
if (!p) return NULL;
|
||||
|
||||
for (i = 0; i < (sizeof(pwd->hash) * 2); i += 2)
|
||||
{
|
||||
hinybble = toupper(p[i]);
|
||||
lonybble = toupper(p[i + 1]);
|
||||
|
||||
p1 = strchr_m(hexchars, hinybble);
|
||||
p2 = strchr_m(hexchars, lonybble);
|
||||
|
||||
if (!p1 || !p2) {
|
||||
if (p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hinybble = PTR_DIFF(p1, hexchars);
|
||||
lonybble = PTR_DIFF(p2, hexchars);
|
||||
|
||||
pwd->hash[i / 2] = (hinybble << 4) | lonybble;
|
||||
pwd = talloc(mem_ctx, struct samr_Password);
|
||||
if (pwd == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = strhex_to_str((char *)pwd->hash,
|
||||
sizeof(pwd->hash),
|
||||
p,
|
||||
sizeof(pwd->hash) * 2);
|
||||
if (len != sizeof(pwd->hash)) {
|
||||
TALLOC_FREE(pwd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pwd;
|
||||
}
|
||||
|
||||
@ -93,14 +89,11 @@ char *smbpasswd_sethexpwd(TALLOC_CTX *mem_ctx, struct samr_Password *pwd, uint16
|
||||
{
|
||||
char *p;
|
||||
if (pwd != NULL) {
|
||||
int i;
|
||||
p = talloc_array(mem_ctx, char, 33);
|
||||
if (!p) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(pwd->hash); i++)
|
||||
slprintf(&p[i*2], 3, "%02X", pwd->hash[i]);
|
||||
hex_encode_buf(p, pwd->hash, sizeof(pwd->hash));
|
||||
} else {
|
||||
if (acb_info & ACB_PWNOTREQ)
|
||||
p = talloc_strdup(mem_ctx, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
|
||||
|
@ -28,7 +28,6 @@ interface ntp_signd
|
||||
uint16 packet_id;
|
||||
[flag(NDR_LITTLE_ENDIAN)] uint32 key_id;
|
||||
[flag(NDR_REMAINING)] DATA_BLOB packet_to_sign;
|
||||
|
||||
} sign_request;
|
||||
|
||||
typedef [flag(NDR_BIG_ENDIAN),public] struct samba_key_out {
|
||||
|
@ -3059,7 +3059,8 @@ static NTSTATUS dcesrv_lsa_AddRemoveAccountRights(struct dcesrv_call_state *dce_
|
||||
{
|
||||
struct auth_session_info *session_info =
|
||||
dcesrv_call_session_info(dce_call);
|
||||
const char *sidstr, *sidndrstr;
|
||||
struct dom_sid_buf sidbuf;
|
||||
const char *sidndrstr = NULL;
|
||||
struct ldb_message *msg;
|
||||
struct ldb_message_element *el;
|
||||
int ret;
|
||||
@ -3084,13 +3085,7 @@ static NTSTATUS dcesrv_lsa_AddRemoveAccountRights(struct dcesrv_call_state *dce_
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
sidstr = dom_sid_string(msg, sid);
|
||||
if (sidstr == NULL) {
|
||||
TALLOC_FREE(msg);
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
dnstr = talloc_asprintf(msg, "sid=%s", sidstr);
|
||||
dnstr = talloc_asprintf(msg, "sid=%s", dom_sid_str_buf(sid, &sidbuf));
|
||||
if (dnstr == NULL) {
|
||||
TALLOC_FREE(msg);
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
|
Loading…
Reference in New Issue
Block a user