1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-03 01:18:10 +03:00

Compare commits

..

No commits in common. "e0aab377bdc86884d460ef9b4515484f4282b31e" and "86cdaf5a2eeb9252fe16dfa4d215065cf1c748c2" have entirely different histories.

38 changed files with 1416 additions and 542 deletions

View File

@ -1548,33 +1548,12 @@ to show in the result.
<title>ADS KEYTAB <replaceable>CREATE</replaceable></title>
<para>
Since Samba 4.21.0, keytab file is created as specified in <smbconfoption
name="sync machine password to keytab"/>. The keytab is created only for
<smbconfoption name="kerberos method">secrets only</smbconfoption> and
<smbconfoption name="kerberos method">secrets and keytab</smbconfoption>. With
the smb.conf default values for <smbconfoption name="kerberos method"> secrets
only</smbconfoption> and <smbconfoption name="sync machine password to keytab"/>
(default is empty) the keytab is not generated at all. Keytab with a default
name and SPNs synced from AD is created for <smbconfoption name="kerberos
method">secrets and keytab</smbconfoption> if <smbconfoption name="sync machine
password to keytab"/> is missing.
</para>
<para>
Till Samba 4.20.0, two more entries were created by default: the machinename of
the client (ending with '$') and the UPN (host/domain@REALM). If these two
entries are still needed, each must be specified in an own keytab file.
Example below will generate three keytab files that contain SPNs synced from
AD, host UPN and machine$ SPN:
</para>
<programlisting>
<smbconfoption name="sync machine password to keytab">
/etc/krb5.keytab0:sync_spns:machine_password,
/etc/krb5.keytab1:spns=host/smb.com@SMB.COM:machine_password,
/etc/krb5.keytab2:account_name:machine_password
</smbconfoption>
</programlisting>
<para>
No changes are made to the computer AD account.
Creates a new keytab file if one doesn't exist with default entries. Default
entries are kerberos principals created from the machinename of the
client, the UPN (if it exists) and any Windows SPN(s) associated with the
computer AD account for the client. If a keytab file already exists then only
missing kerberos principals from the default entries are added. No changes
are made to the computer AD account.
</para>
</refsect2>

View File

@ -62,10 +62,7 @@
</varlistentry>
</variablelist>
<para> This module is not fully stackable. It can be combined with other
modules, but should be the last module in the <command>vfs objects</command>
list. It directly access the files in the OS filesystem.
</para>
<para>This module is stackable.</para>
</refsect1>

View File

@ -62,6 +62,7 @@
<arg choice="opt">--remove-uid-mapping uid,sid</arg>
<arg choice="opt">-s sid</arg>
<arg choice="opt">--separator</arg>
<arg choice="opt">--sequence</arg>
<arg choice="opt">--set-auth-user user%password</arg>
<arg choice="opt">--set-gid-mapping gid,sid</arg>
<arg choice="opt">--set-uid-mapping uid,sid</arg>
@ -457,6 +458,13 @@
</para></listitem>
</varlistentry>
<varlistentry>
<term>--sequence</term>
<listitem><para>This command has been deprecated. Please use
the --online-status option instead.
</para></listitem>
</varlistentry>
<varlistentry>
<term>--set-auth-user <replaceable>username%password</replaceable></term>
<listitem><para>Store username and password used by <citerefentry>

View File

@ -245,9 +245,8 @@ static uint32_t access_check_max_allowed(const struct security_descriptor *sd,
if (security_token_has_sid(token, sd->owner_sid)) {
switch (implicit_owner_rights) {
case IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS:
granted |= (SEC_STD_READ_CONTROL |
SEC_STD_WRITE_DAC);
break;
granted |= SEC_STD_WRITE_DAC;
FALL_THROUGH;
case IMPLICIT_OWNER_READ_CONTROL_RIGHTS:
granted |= SEC_STD_READ_CONTROL;
break;
@ -283,8 +282,8 @@ static uint32_t access_check_max_allowed(const struct security_descriptor *sd,
if (am_owner && !have_owner_rights_ace) {
switch (implicit_owner_rights) {
case IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS:
granted |= (SEC_STD_READ_CONTROL | SEC_STD_WRITE_DAC);
break;
granted |= SEC_STD_WRITE_DAC;
FALL_THROUGH;
case IMPLICIT_OWNER_READ_CONTROL_RIGHTS:
granted |= SEC_STD_READ_CONTROL;
break;
@ -437,9 +436,8 @@ static NTSTATUS se_access_check_implicit_owner(const struct security_descriptor
if (am_owner && !have_owner_rights_ace) {
switch (implicit_owner_rights) {
case IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS:
bits_remaining &= ~(SEC_STD_WRITE_DAC |
SEC_STD_READ_CONTROL);
break;
bits_remaining &= ~SEC_STD_WRITE_DAC;
FALL_THROUGH;
case IMPLICIT_OWNER_READ_CONTROL_RIGHTS:
bits_remaining &= ~SEC_STD_READ_CONTROL;
break;
@ -598,10 +596,10 @@ NTSTATUS se_file_access_check(const struct security_descriptor *sd,
access_desired |= SEC_RIGHTS_PRIV_RESTORE;
}
DBG_DEBUG("MAX desired = 0x%0" PRIx32 " mapped to 0x%" PRIx32
"\n ",
orig_access_desired,
access_desired);
DEBUG(10,("se_file_access_check: MAX desired = 0x%x "
"mapped to 0x%x\n",
orig_access_desired,
access_desired));
}
status = se_access_check_implicit_owner(sd,
@ -753,9 +751,8 @@ NTSTATUS sec_access_check_ds_implicit_owner(const struct security_descriptor *sd
security_token_has_sid(token, sd->owner_sid)) {
switch (implicit_owner_rights) {
case IMPLICIT_OWNER_READ_CONTROL_AND_WRITE_DAC_RIGHTS:
bits_remaining &= ~(SEC_STD_WRITE_DAC |
SEC_STD_READ_CONTROL);
break;
bits_remaining &= ~SEC_STD_WRITE_DAC;
FALL_THROUGH;
case IMPLICIT_OWNER_READ_CONTROL_RIGHTS:
bits_remaining &= ~SEC_STD_READ_CONTROL;
break;

View File

@ -109,23 +109,26 @@ static bool check_integer_range(const struct ace_condition_token *tok)
return true;
}
static ssize_t pull_integer(uint8_t *data,
size_t length,
struct ace_condition_int *tok)
{
size_t consumed;
enum ndr_err_code ndr_err;
ndr_err = ndr_pull_struct_blob_noalloc(
data,
length,
tok,
(ndr_pull_flags_fn_t)ndr_pull_ace_condition_int,
&consumed);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
static ssize_t pull_integer(TALLOC_CTX *mem_ctx,
uint8_t *data, size_t length,
struct ace_condition_int *tok)
{
ssize_t bytes_used;
enum ndr_err_code ndr_err;
DATA_BLOB v = data_blob_const(data, length);
struct ndr_pull *ndr = ndr_pull_init_blob(&v, mem_ctx);
if (ndr == NULL) {
return -1;
}
return consumed;
ndr_err = ndr_pull_ace_condition_int(ndr, NDR_SCALARS|NDR_BUFFERS, tok);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
TALLOC_FREE(ndr);
return -1;
}
bytes_used = ndr->offset;
TALLOC_FREE(ndr);
return bytes_used;
}
static ssize_t push_integer(uint8_t *data, size_t available,
@ -332,7 +335,8 @@ static ssize_t pull_composite(TALLOC_CTX *mem_ctx,
case CONDITIONAL_ACE_TOKEN_INT16:
case CONDITIONAL_ACE_TOKEN_INT32:
case CONDITIONAL_ACE_TOKEN_INT64:
consumed = pull_integer(el_data,
consumed = pull_integer(mem_ctx,
el_data,
available,
&el->data.int64);
ok = check_integer_range(el);
@ -503,7 +507,7 @@ static ssize_t pull_end_padding(uint8_t *data, size_t length)
*
* zero is also called CONDITIONAL_ACE_TOKEN_INVALID_OR_PADDING.
*/
size_t i;
ssize_t i;
if (length > 2) {
return -1;
}
@ -588,7 +592,8 @@ struct ace_condition_script *parse_conditional_ace(TALLOC_CTX *mem_ctx,
case CONDITIONAL_ACE_TOKEN_INT16:
case CONDITIONAL_ACE_TOKEN_INT32:
case CONDITIONAL_ACE_TOKEN_INT64:
consumed = pull_integer(tok_data,
consumed = pull_integer(program,
tok_data,
available,
&tok->data.int64);
ok = check_integer_range(tok);

View File

@ -110,18 +110,20 @@ void display_sec_ace_flags(uint8_t flags)
****************************************************************************/
static void disp_sec_ace_object(struct security_ace_object *object)
{
struct GUID_txt_buf buf;
char *str;
if (object->flags & SEC_ACE_OBJECT_TYPE_PRESENT) {
str = GUID_string(NULL, &object->type.type);
if (str == NULL) return;
printf("Object type: SEC_ACE_OBJECT_TYPE_PRESENT\n");
printf("Object GUID: %s\n",
GUID_buf_string(&object->type.type, &buf));
printf("Object GUID: %s\n", str);
talloc_free(str);
}
if (object->flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT) {
str = GUID_string(NULL, &object->inherited_type.inherited_type);
if (str == NULL) return;
printf("Object type: SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT\n");
printf("Object GUID: %s\n",
GUID_buf_string(&object->inherited_type.inherited_type,
&buf));
printf("Object GUID: %s\n", str);
talloc_free(str);
}
}
@ -184,9 +186,8 @@ void display_sec_acl(struct security_acl *sec_acl)
{
uint32_t i;
printf("\tACL\tNum ACEs:\t%" PRIu32 "\trevision:\t%x\n",
sec_acl->num_aces,
sec_acl->revision);
printf("\tACL\tNum ACEs:\t%u\trevision:\t%x\n",
sec_acl->num_aces, sec_acl->revision);
printf("\t---\n");
if (sec_acl->size != 0 && sec_acl->num_aces != 0) {

View File

@ -298,8 +298,7 @@ static NTSTATUS security_descriptor_acl_add(struct security_descriptor *sd,
if (idx < 0) {
return NT_STATUS_ARRAY_BOUNDS_EXCEEDED;
}
if (idx > acl->num_aces) {
} else if (idx > acl->num_aces) {
return NT_STATUS_ARRAY_BOUNDS_EXCEEDED;
}

View File

@ -51,27 +51,52 @@ struct security_token *security_token_initialise(TALLOC_CTX *mem_ctx,
struct security_token *security_token_duplicate(TALLOC_CTX *mem_ctx, const struct security_token *src)
{
TALLOC_CTX *frame = NULL;
struct security_token *dst = NULL;
DATA_BLOB blob;
enum ndr_err_code ndr_err;
if (src == NULL) {
return NULL;
}
frame = talloc_stackframe();
ndr_err = ndr_push_struct_blob(
&blob,
frame,
src,
(ndr_push_flags_fn_t)ndr_push_security_token);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
DBG_ERR("Failed to duplicate security_token ndr_push_security_token failed: %s\n",
ndr_errstr(ndr_err));
TALLOC_FREE(frame);
return NULL;
}
dst = talloc_zero(mem_ctx, struct security_token);
if (dst == NULL) {
DBG_ERR("talloc failed\n");
TALLOC_FREE(frame);
return NULL;
}
ndr_err = ndr_deepcopy_struct(security_token, src, dst, dst);
ndr_err = ndr_pull_struct_blob(
&blob,
dst,
dst,
(ndr_pull_flags_fn_t)ndr_pull_security_token);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
DBG_ERR("Failed to duplicate security_token: %s\n",
DBG_ERR("Failed to duplicate security_token ndr_pull_security_token "
"failed: %s\n",
ndr_errstr(ndr_err));
TALLOC_FREE(dst);
TALLOC_FREE(frame);
return NULL;
}
TALLOC_FREE(frame);
return dst;
}

View File

@ -323,17 +323,16 @@ bool sid_peek_check_rid(const struct dom_sid *exp_dom_sid, const struct dom_sid
void sid_copy(struct dom_sid *dst, const struct dom_sid *src)
{
const int8_t num_auths = MIN(15, MAX(0, src->num_auths));
int8_t i;
int i;
*dst = (struct dom_sid) {
.sid_rev_num = src->sid_rev_num,
.num_auths = num_auths,
.num_auths = src->num_auths,
};
memcpy(&dst->id_auth[0], &src->id_auth[0], sizeof(src->id_auth));
for (i = 0; i < num_auths; i++)
for (i = 0; i < src->num_auths; i++)
dst->sub_auths[i] = src->sub_auths[i];
}

View File

@ -36,6 +36,24 @@ testfail()
fi
}
knownfail()
{
name="$1"
shift
cmdline="$*"
echo "test: $name"
$cmdline
status=$?
if [ x$status = x0 ]; then
echo "failure: $name [unexpected success]"
status=1
else
echo "knownfail: $name"
status=0
fi
return $status
}
KRB5CCNAME_PATH="$PREFIX/test_wbinfo_krb5ccache"
rm -f $KRB5CCNAME_PATH
@ -200,6 +218,9 @@ else
failed=$(expr $failed + 1)
fi
# this does not work
knownfail "wbinfo --sequence against $TARGET" $wbinfo --sequence
# this is stubbed out now
testit "wbinfo -D against $TARGET" $wbinfo -D $DOMAIN || failed=$(expr $failed + 1)

View File

@ -605,6 +605,14 @@ static bool wbinfo_list_own_domain(void)
return true;
}
/* show sequence numbers */
static bool wbinfo_show_sequence(const char *domain)
{
d_printf("This command has been deprecated. Please use the "
"--online-status option instead.\n");
return false;
}
/* show sequence numbers */
static bool wbinfo_show_onlinestatus(const char *domain)
{
@ -2287,6 +2295,7 @@ enum {
OPT_SET_AUTH_USER = 1000,
OPT_GET_AUTH_USER,
OPT_DOMAIN_NAME,
OPT_SEQUENCE,
OPT_GETDCNAME,
OPT_DSGETDCNAME,
OPT_DC_INFO,
@ -2572,6 +2581,12 @@ int main(int argc, const char **argv, char **envp)
.val = OPT_LIST_OWN_DOMAIN,
.descrip = "List own domain",
},
{
.longName = "sequence",
.argInfo = POPT_ARG_NONE,
.val = OPT_SEQUENCE,
.descrip = "Deprecated command, see --online-status",
},
{
.longName = "online-status",
.argInfo = POPT_ARG_NONE,
@ -3084,6 +3099,13 @@ int main(int argc, const char **argv, char **envp)
goto done;
}
break;
case OPT_SEQUENCE:
if (!wbinfo_show_sequence(opt_domain_name)) {
d_fprintf(stderr,
"Could not show sequence numbers\n");
goto done;
}
break;
case OPT_ONLINESTATUS:
if (!wbinfo_show_onlinestatus(opt_domain_name)) {
d_fprintf(stderr,

View File

@ -63,9 +63,8 @@ typedef char fstring[FSTRING_LEN];
* 31: added "client_name" to the request
* 32: added "traceid" to the request
* removed WINBINDD_INIT_CONNECTION
* 33: removed WINBINDD_SHOW_SEQUENCE
*/
#define WINBIND_INTERFACE_VERSION 33
#define WINBIND_INTERFACE_VERSION 32
/* Have to deal with time_t being 4 or 8 bytes due to structure alignment.
On a 64bit Linux box, we have to support a constant structure size
@ -142,6 +141,8 @@ enum winbindd_cmd {
WINBINDD_DSGETDCNAME, /* Issue a DsGetDCName Request */
WINBINDD_DC_INFO, /* Which DC are we connected to? */
WINBINDD_SHOW_SEQUENCE, /* display sequence numbers of domains */
/* WINS commands */
WINBINDD_WINS_BYIP,

View File

@ -2783,9 +2783,6 @@ sub provision($$)
my $recycle_shrdir="$shrdir/recycle";
push(@dirs,$recycle_shrdir);
my $recycle_shrdir2="$shrdir/recycle2";
push(@dirs,$recycle_shrdir2);
my $fakedircreatetimes_shrdir="$shrdir/fakedircreatetimes";
push(@dirs,$fakedircreatetimes_shrdir);
@ -3721,15 +3718,6 @@ sub provision($$)
recycle : exclude = *.tmp
recycle : directory_mode = 755
[recycle2]
copy = tmp
path = $recycle_shrdir2
vfs objects = recycle crossrename
recycle : repository = .trash
recycle : exclude = *.tmp
recycle : directory_mode = 755
wide links = yes
[fakedircreatetimes]
copy = tmp
path = $fakedircreatetimes_shrdir

View File

@ -2584,8 +2584,11 @@ static struct adouble *ad_get_internal(TALLOC_CTX *ctx,
int mode;
if (fsp != NULL) {
struct files_struct *meta_fsp = metadata_fsp(fsp);
smb_fname = meta_fsp->fsp_name;
if (fsp_is_alternate_stream(fsp)) {
smb_fname = fsp->base_fsp->fsp_name;
} else {
smb_fname = fsp->fsp_name;
}
}
DEBUG(10, ("ad_get(%s) called for %s\n",

View File

@ -274,20 +274,23 @@ static int connect_acl_tdb(struct vfs_handle_struct *handle,
if (config->ignore_system_acls) {
mode_t create_mask = lp_create_mask(SNUM(handle->conn));
char *create_mask_str = NULL;
if ((create_mask & 0666) != 0666) {
char create_mask_str[16];
create_mask |= 0666;
snprintf(create_mask_str,
sizeof(create_mask_str),
"0%o",
create_mask);
create_mask_str = talloc_asprintf(handle, "0%o",
create_mask);
if (create_mask_str == NULL) {
DBG_ERR("talloc_asprintf failed\n");
return -1;
}
DBG_NOTICE("setting 'create mask = %s'\n", create_mask_str);
lp_do_parameter (SNUM(handle->conn),
"create mask", create_mask_str);
TALLOC_FREE(create_mask_str);
}
DBG_NOTICE("setting 'directory mask = 0777', "

View File

@ -218,21 +218,23 @@ static int connect_acl_xattr(struct vfs_handle_struct *handle,
if (config->ignore_system_acls) {
mode_t create_mask = lp_create_mask(SNUM(handle->conn));
char *create_mask_str = NULL;
if ((create_mask & 0666) != 0666) {
char create_mask_str[16];
create_mask |= 0666;
snprintf(create_mask_str,
sizeof(create_mask_str),
"0%o",
create_mask);
create_mask_str = talloc_asprintf(handle, "0%o",
create_mask);
if (create_mask_str == NULL) {
DBG_ERR("talloc_asprintf failed\n");
return -1;
}
DBG_NOTICE("setting 'create mask = %s'\n", create_mask_str);
lp_do_parameter(SNUM(handle->conn),
"create mask",
create_mask_str);
lp_do_parameter (SNUM(handle->conn),
"create mask", create_mask_str);
TALLOC_FREE(create_mask_str);
}
DBG_NOTICE("setting 'directory mask = 0777', "

View File

@ -54,12 +54,10 @@ static NTSTATUS copy_reg(vfs_handle_struct *handle,
struct files_struct *dstfsp,
const struct smb_filename *dest)
{
NTSTATUS status = NT_STATUS_OK;
NTSTATUS status;
struct smb_filename *full_fname_src = NULL;
struct smb_filename *full_fname_dst = NULL;
int ret;
off_t off;
int ifd = -1;
int ofd = -1;
struct timespec ts[2];
if (!VALID_STAT(source->st)) {
status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
@ -81,105 +79,64 @@ static NTSTATUS copy_reg(vfs_handle_struct *handle,
goto out;
}
full_fname_src = full_path_from_dirfsp_atname(talloc_tos(),
srcfsp,
source);
if (full_fname_src == NULL) {
status = NT_STATUS_NO_MEMORY;
goto out;
}
full_fname_dst = full_path_from_dirfsp_atname(talloc_tos(),
dstfsp,
dest);
if (full_fname_dst == NULL) {
status = NT_STATUS_NO_MEMORY;
goto out;
}
ret = SMB_VFS_NEXT_UNLINKAT(handle,
dstfsp,
dest,
0);
if (ret == -1 && errno != ENOENT) {
status = map_nt_error_from_unix(errno);
goto out;
}
ifd = openat(fsp_get_pathref_fd(srcfsp),
source->base_name,
O_RDONLY,
0);
if (ifd < 0) {
status = map_nt_error_from_unix(errno);
goto out;
}
ofd = openat(fsp_get_pathref_fd(dstfsp),
dest->base_name,
O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW,
0600);
if (ofd < 0) {
status = map_nt_error_from_unix(errno);
goto out;
}
off = transfer_file(ifd, ofd, source->st.st_ex_size);
if (off == -1) {
status = map_nt_error_from_unix(errno);
goto out;
}
ret = fchown(ofd, source->st.st_ex_uid, source->st.st_ex_gid);
if (ret == -1 && errno != EPERM) {
if (ret == -1) {
status = map_nt_error_from_unix(errno);
goto out;
}
/*
* fchown turns off set[ug]id bits for non-root,
* so do the chmod last.
* copy_internals() takes attribute values from the NTrename call.
*
* From MS-CIFS:
*
* "If the attribute is 0x0000, then only normal files are renamed.
* If the system file or hidden attributes are specified, then the
* rename is inclusive of both special types."
*/
ret = fchmod(ofd, source->st.st_ex_mode & 07777);
if (ret == -1 && errno != EPERM) {
status = copy_internals(talloc_tos(),
handle->conn,
NULL,
srcfsp, /* src_dirfsp */
full_fname_src,
dstfsp, /* dst_dirfsp */
full_fname_dst,
FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
if (!NT_STATUS_IS_OK(status)) {
goto out;
}
ret = SMB_VFS_NEXT_UNLINKAT(handle,
srcfsp,
source,
0);
if (ret == -1) {
status = map_nt_error_from_unix(errno);
goto out;
}
/* Try to copy the old file's modtime and access time. */
ts[0] = source->st.st_ex_atime;
ts[1] = source->st.st_ex_mtime;
ret = futimens(ofd, ts);
if (ret == -1) {
DBG_DEBUG("Updating the time stamp on destinaton '%s' failed "
"with '%s'. Rename operation can continue.\n",
dest->base_name,
strerror(errno));
}
ret = close(ifd);
if (ret == -1) {
status = map_nt_error_from_unix(errno);
goto out;
}
ifd = -1;
ret = close(ofd);
if (ret == -1) {
status = map_nt_error_from_unix(errno);
goto out;
}
ofd = -1;
ret = SMB_VFS_NEXT_UNLINKAT(handle, srcfsp, source, 0);
if (ret == -1) {
status = map_nt_error_from_unix(errno);
}
out:
if (ifd != -1) {
ret = close(ifd);
if (ret == -1) {
DBG_DEBUG("Failed to close %s (%d): %s.\n",
source->base_name,
ifd,
strerror(errno));
}
}
if (ofd != -1) {
ret = close(ofd);
if (ret == -1) {
DBG_DEBUG("Failed to close %s (%d): %s.\n",
dest->base_name,
ofd,
strerror(errno));
}
}
out:
TALLOC_FREE(full_fname_src);
TALLOC_FREE(full_fname_dst);
return status;
}
@ -213,7 +170,6 @@ static int crossrename_renameat(vfs_handle_struct *handle,
smb_fname_src,
dstfsp,
smb_fname_dst);
result = 0;
if (!NT_STATUS_IS_OK(status)) {
errno = map_errno_from_nt_status(status);
result = -1;

View File

@ -829,6 +829,12 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
goto error_exit;
}
status = openat_pathref_fsp(conn->cwd_fsp, smb_fname);
if (!NT_STATUS_IS_OK(status)) {
ret = 1;
goto done;
}
status = SMB_VFS_CREATE_FILE(
conn, /* conn */
NULL, /* req */
@ -885,6 +891,13 @@ static int file_version_is_newer(connection_struct *conn, fstring new_file, fstr
goto error_exit;
}
status = openat_pathref_fsp(conn->cwd_fsp, smb_fname);
if (!NT_STATUS_IS_OK(status)) {
DBG_NOTICE("Can't open new file [%s], errno = %d\n",
smb_fname_str_dbg(smb_fname), errno);
goto error_exit;
}
status = SMB_VFS_CREATE_FILE(
conn, /* conn */
NULL, /* req */
@ -1097,6 +1110,15 @@ static uint32_t get_correct_cversion(const struct auth_session_info *session_inf
goto error_exit;
}
nt_status = openat_pathref_fsp(conn->cwd_fsp, smb_fname);
if (!NT_STATUS_IS_OK(nt_status)) {
DBG_NOTICE("Can't open file [%s]: %s\n",
smb_fname_str_dbg(smb_fname),
nt_errstr(nt_status));
*perr = WERR_ACCESS_DENIED;
goto error_exit;
}
nt_status = SMB_VFS_CREATE_FILE(
conn, /* conn */
NULL, /* req */

View File

@ -176,8 +176,8 @@ static void display_sam_dom_info_2(struct samr_DomGeneralInformation *general)
static void display_sam_dom_info_3(struct samr_DomInfo3 *info3)
{
printf("Force Logoff:\t%" PRIu64 "\n",
(uint64_t)nt_time_to_unix_abs(&info3->force_logoff_time));
printf("Force Logoff:\t%d\n",
(int)nt_time_to_unix_abs(&info3->force_logoff_time));
}
static void display_sam_dom_info_4(struct samr_DomOEMInformation *oem)

View File

@ -29,8 +29,7 @@ export SAMBA_DEPRECATED_SUPPRESS
# Define the test environment/filenames.
#
share_test_dir="$LOCAL_PATH/recycle"
share_test_dir2="$LOCAL_PATH/recycle2"
share_test_dir="$LOCAL_PATH"
#
# Cleanup function.
@ -44,13 +43,6 @@ do_cleanup()
rm -f testfile2.tmp
rm -rf .trash
)
(
#subshell.
cd "$share_test_dir2" || return
rm -f testfile3
rm -f testfile4.tmp
rm -rf .trash
)
}
#
@ -58,25 +50,6 @@ do_cleanup()
#
do_cleanup
# Setup .trash on a different filesystem to test crossrename
# /tmp or /dev/shm should provide tmpfs
#
for T in /tmp /dev/shm
do
if df --portability --print-type $T 2>/dev/null | grep -q tmpfs; then
TRASHDIR=$T
break
fi
done
if [ -z $TRASHDIR ]; then
echo "No tmpfs filesystem found."
exit 1
fi
TRASHDIR=$(mktemp -d /$TRASHDIR/.trash_XXXXXX)
chmod 0755 $TRASHDIR
ln -s $TRASHDIR $share_test_dir2/.trash
test_recycle()
{
@ -117,61 +90,12 @@ quit
return 0
}
test_recycle_crossrename()
{
tmpfile=$PREFIX/smbclient_interactive_prompt_commands
echo "
put $tmpfile testfile3
put $tmpfile testfile4.tmp
del testfile3
del testfile4.tmp
quit
" > $tmpfile
cmd='CLI_FORCE_INTERACTIVE=yes $SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/recycle2 -I$SERVER_IP $ADDARGS < $tmpfile 2>&1'
eval echo "$cmd"
out=$(eval "$cmd")
ret=$?
rm -f "$tmpfile"
if [ $ret != 0 ]; then
printf "%s\n" "$out"
printf "failed recycle smbclient run with error %s\n" "$ret"
return 1
fi
test -e "$share_test_dir2/.trash/testfile3" || {
printf ".trash/testfile3 expected to exist but does NOT exist\n"
return 1
}
test -e "$share_test_dir2/.trash/testfile4.tmp" && {
printf ".trash/testfile4.tmp not expected to exist but DOES exist\n"
return 1
}
deviceid1=`stat -c '%d' "$share_test_dir2/"`
deviceid2=`stat -c '%d' "$share_test_dir2/.trash/"`
test "$deviceid1=" != "$deviceid2" || {
printf ".trash/ should be on a different filesystem!\n"
return 1
}
perm_want=755
perm_is=`stat -c '%a' "$share_test_dir2/.trash/"`
test "$perm_is" = "$perm_want" || {
printf ".trash/ permission should be $perm_want but is $perm_is\n"
return 1
}
return 0
}
panic_count_0=$(grep -c PANIC $SMBD_TEST_LOG)
testit "recycle" \
test_recycle ||
failed=$((failed + 1))
testit "recycle_crossrename" \
test_recycle_crossrename ||
failed=$((failed + 1))
panic_count_1=$(grep -c PANIC $SMBD_TEST_LOG)
testit "check_panic" test $panic_count_0 -eq $panic_count_1 || failed=$(expr $failed + 1)
@ -179,7 +103,5 @@ testit "check_panic" test $panic_count_0 -eq $panic_count_1 || failed=$(expr $fa
#
# Cleanup.
do_cleanup
# Cleanup above only deletes a symlink, delete also /tmp/.trash_XXXXXX dir
rm -rf "$TRASHDIR"
testok "$0" "$failed"

View File

@ -784,7 +784,7 @@ for env in ["fileserver"]:
plantestsuite("samba3.blackbox.force_create_mode", env, [os.path.join(samba3srcdir, "script/tests/test_force_create_mode.sh"), '$SERVER', '$DOMAIN', '$USERNAME', '$PASSWORD', '$PREFIX', env, smbclient3])
plantestsuite("samba3.blackbox.dropbox", env, [os.path.join(samba3srcdir, "script/tests/test_dropbox.sh"), '$SERVER', '$DOMAIN', 'gooduser', '$PASSWORD', '$PREFIX', env, smbclient3])
plantestsuite("samba3.blackbox.offline", env, [os.path.join(samba3srcdir, "script/tests/test_offline.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/offline', smbclient3])
plantestsuite("samba3.blackbox.recycle", env, [os.path.join(samba3srcdir, "script/tests/test_recycle.sh"), '$SERVER', '$SERVER_IP', '$USERNAME', '$PASSWORD', '$LOCAL_PATH', '$PREFIX', smbclient3])
plantestsuite("samba3.blackbox.recycle", env, [os.path.join(samba3srcdir, "script/tests/test_recycle.sh"), '$SERVER', '$SERVER_IP', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/recycle', '$PREFIX', smbclient3])
plantestsuite("samba3.blackbox.fakedircreatetimes", env, [os.path.join(samba3srcdir, "script/tests/test_fakedircreatetimes.sh"), '$SERVER', '$SERVER_IP', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/fakedircreatetimes', '$PREFIX', smbclient3])
plantestsuite("samba3.blackbox.shadow_copy2.NT1", env + "_smb1_done", [os.path.join(samba3srcdir, "script/tests/test_shadow_copy.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/shadow', smbclient3, '-m', 'NT1'])
plantestsuite("samba3.blackbox.shadow_copy2.SMB3", env, [os.path.join(samba3srcdir, "script/tests/test_shadow_copy.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/shadow', smbclient3, '-m', 'SMB3'])

View File

@ -973,10 +973,15 @@ static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp,
return status;
}
/****************************************************************************
Function used by reply_rmdir to delete an entire directory
tree recursively. Return True on ok, False on fail.
****************************************************************************/
static NTSTATUS recursive_rmdir_fsp(struct files_struct *fsp)
NTSTATUS recursive_rmdir(TALLOC_CTX *ctx,
connection_struct *conn,
struct smb_filename *smb_dname)
{
struct connection_struct *conn = fsp->conn;
const char *dname = NULL;
char *talloced = NULL;
struct smb_Dir *dir_hnd = NULL;
@ -984,7 +989,14 @@ static NTSTATUS recursive_rmdir_fsp(struct files_struct *fsp)
int retval;
NTSTATUS status = NT_STATUS_OK;
status = OpenDir_from_pathref(talloc_tos(), fsp, NULL, 0, &dir_hnd);
SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));
status = OpenDir(talloc_tos(),
conn,
smb_dname,
NULL,
0,
&dir_hnd);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@ -993,6 +1005,9 @@ static NTSTATUS recursive_rmdir_fsp(struct files_struct *fsp)
while ((dname = ReadDirName(dir_hnd, &talloced))) {
struct smb_filename *atname = NULL;
struct smb_filename *smb_dname_full = NULL;
char *fullname = NULL;
bool do_break = true;
int unlink_flags = 0;
if (ISDOT(dname) || ISDOTDOT(dname)) {
@ -1000,56 +1015,56 @@ static NTSTATUS recursive_rmdir_fsp(struct files_struct *fsp)
continue;
}
atname = synthetic_smb_fname(talloc_tos(),
dname,
NULL,
NULL,
dirfsp->fsp_name->twrp,
dirfsp->fsp_name->flags);
TALLOC_FREE(talloced);
dname = NULL;
if (atname == NULL) {
/* Construct the full name. */
fullname = talloc_asprintf(ctx,
"%s/%s",
smb_dname->base_name,
dname);
if (!fullname) {
status = NT_STATUS_NO_MEMORY;
break;
goto err_break;
}
{
struct name_compare_entry *veto_list = conn->veto_list;
/*
* Sneaky hack to be able to open veto files
* with openat_pathref_fsp
*/
conn->veto_list = NULL;
status = openat_pathref_fsp_lcomp(
dirfsp,
atname,
UCF_POSIX_PATHNAMES /* no ci fallback */);
conn->veto_list = veto_list;
smb_dname_full = synthetic_smb_fname(talloc_tos(),
fullname,
NULL,
NULL,
smb_dname->twrp,
smb_dname->flags);
if (smb_dname_full == NULL) {
status = NT_STATUS_NO_MEMORY;
goto err_break;
}
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(atname);
if (NT_STATUS_EQUAL(status,
NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
/* race between readdir and unlink */
continue;
}
break;
if (SMB_VFS_LSTAT(conn, smb_dname_full) != 0) {
status = map_nt_error_from_unix(errno);
goto err_break;
}
if (atname->st.st_ex_mode & S_IFDIR) {
status = recursive_rmdir_fsp(atname->fsp);
if (smb_dname_full->st.st_ex_mode & S_IFDIR) {
status = recursive_rmdir(ctx, conn, smb_dname_full);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(atname);
break;
goto err_break;
}
unlink_flags = AT_REMOVEDIR;
}
status = synthetic_pathref(talloc_tos(),
dirfsp,
dname,
NULL,
&smb_dname_full->st,
smb_dname_full->twrp,
smb_dname_full->flags,
&atname);
if (!NT_STATUS_IS_OK(status)) {
goto err_break;
}
if (!is_visible_fsp(atname->fsp)) {
TALLOC_FREE(smb_dname_full);
TALLOC_FREE(fullname);
TALLOC_FREE(talloced);
TALLOC_FREE(atname);
continue;
}
@ -1060,34 +1075,25 @@ static NTSTATUS recursive_rmdir_fsp(struct files_struct *fsp)
unlink_flags);
if (retval != 0) {
status = map_nt_error_from_unix(errno);
TALLOC_FREE(atname);
break;
goto err_break;
}
/* Successful iteration. */
do_break = false;
err_break:
TALLOC_FREE(smb_dname_full);
TALLOC_FREE(fullname);
TALLOC_FREE(talloced);
TALLOC_FREE(atname);
}
if (do_break) {
break;
}
}
TALLOC_FREE(dir_hnd);
return status;
}
NTSTATUS recursive_rmdir(TALLOC_CTX *ctx,
connection_struct *conn,
struct smb_filename *smb_dname)
{
NTSTATUS status;
SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));
status = openat_pathref_fsp(conn->cwd_fsp, smb_dname);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
status = recursive_rmdir_fsp(smb_dname->fsp);
return status;
}
/****************************************************************************
The internals of the rmdir code - called elsewhere.
****************************************************************************/
@ -1098,6 +1104,8 @@ static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, struct files_struct *fsp)
struct smb_filename *smb_dname = fsp->fsp_name;
struct smb_filename *parent_fname = NULL;
struct smb_filename *at_fname = NULL;
const char *dname = NULL;
char *talloced = NULL;
struct smb_Dir *dir_hnd = NULL;
struct files_struct *dirfsp = NULL;
int unlink_flags = 0;
@ -1171,7 +1179,7 @@ static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, struct files_struct *fsp)
}
/*
* Check to see if the only things in this directory are
* Check to see if the only thing in this directory are
* files non-visible to the client. If not, fail the delete.
*/
@ -1188,18 +1196,271 @@ static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, struct files_struct *fsp)
dirfsp = dir_hnd_fetch_fsp(dir_hnd);
status = can_delete_directory_hnd(dir_hnd);
if (!NT_STATUS_IS_OK(status)) {
while ((dname = ReadDirName(dir_hnd, &talloced)) != NULL) {
struct smb_filename *smb_dname_full = NULL;
struct smb_filename *direntry_fname = NULL;
char *fullname = NULL;
int retval;
if (ISDOT(dname) || ISDOTDOT(dname)) {
TALLOC_FREE(talloced);
continue;
}
if (IS_VETO_PATH(conn, dname)) {
TALLOC_FREE(talloced);
continue;
}
fullname = talloc_asprintf(talloc_tos(),
"%s/%s",
smb_dname->base_name,
dname);
if (fullname == NULL) {
TALLOC_FREE(talloced);
status = NT_STATUS_NO_MEMORY;
goto err;
}
smb_dname_full = synthetic_smb_fname(talloc_tos(),
fullname,
NULL,
NULL,
smb_dname->twrp,
smb_dname->flags);
if (smb_dname_full == NULL) {
TALLOC_FREE(talloced);
TALLOC_FREE(fullname);
status = NT_STATUS_NO_MEMORY;
goto err;
}
retval = SMB_VFS_LSTAT(conn, smb_dname_full);
if (retval != 0) {
status = map_nt_error_from_unix(errno);
TALLOC_FREE(talloced);
TALLOC_FREE(fullname);
TALLOC_FREE(smb_dname_full);
goto err;
}
if (S_ISLNK(smb_dname_full->st.st_ex_mode)) {
/* Could it be an msdfs link ? */
if (lp_host_msdfs() &&
lp_msdfs_root(SNUM(conn))) {
struct smb_filename *smb_atname;
smb_atname = synthetic_smb_fname(talloc_tos(),
dname,
NULL,
&smb_dname_full->st,
fsp->fsp_name->twrp,
fsp->fsp_name->flags);
if (smb_atname == NULL) {
TALLOC_FREE(talloced);
TALLOC_FREE(fullname);
TALLOC_FREE(smb_dname_full);
status = NT_STATUS_NO_MEMORY;
goto err;
}
if (is_msdfs_link(fsp, smb_atname)) {
TALLOC_FREE(talloced);
TALLOC_FREE(fullname);
TALLOC_FREE(smb_dname_full);
TALLOC_FREE(smb_atname);
DBG_DEBUG("got msdfs link name %s "
"- can't delete directory %s\n",
dname,
fsp_str_dbg(fsp));
status = NT_STATUS_DIRECTORY_NOT_EMPTY;
goto err;
}
TALLOC_FREE(smb_atname);
}
/* Not a DFS link - could it be a dangling symlink ? */
retval = SMB_VFS_STAT(conn, smb_dname_full);
if (retval == -1 && (errno == ENOENT || errno == ELOOP)) {
/*
* Dangling symlink.
* Allow delete as "delete veto files = yes"
*/
TALLOC_FREE(talloced);
TALLOC_FREE(fullname);
TALLOC_FREE(smb_dname_full);
continue;
}
DBG_DEBUG("got symlink name %s - "
"can't delete directory %s\n",
dname,
fsp_str_dbg(fsp));
TALLOC_FREE(talloced);
TALLOC_FREE(fullname);
TALLOC_FREE(smb_dname_full);
status = NT_STATUS_DIRECTORY_NOT_EMPTY;
goto err;
}
/* Not a symlink, get a pathref. */
status = synthetic_pathref(talloc_tos(),
dirfsp,
dname,
NULL,
&smb_dname_full->st,
smb_dname->twrp,
smb_dname->flags,
&direntry_fname);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(talloced);
TALLOC_FREE(fullname);
TALLOC_FREE(smb_dname_full);
goto err;
}
if (!is_visible_fsp(direntry_fname->fsp)) {
TALLOC_FREE(talloced);
TALLOC_FREE(fullname);
TALLOC_FREE(smb_dname_full);
TALLOC_FREE(direntry_fname);
continue;
}
/*
* We found a client visible name.
* We cannot delete this directory.
*/
DBG_DEBUG("got name %s - "
"can't delete directory %s\n",
dname,
fsp_str_dbg(fsp));
TALLOC_FREE(talloced);
TALLOC_FREE(fullname);
TALLOC_FREE(smb_dname_full);
TALLOC_FREE(direntry_fname);
status = NT_STATUS_DIRECTORY_NOT_EMPTY;
goto err;
}
status = recursive_rmdir_fsp(dirfsp);
if (!NT_STATUS_IS_OK(status)) {
status = NT_STATUS_DIRECTORY_NOT_EMPTY;
goto err;
/* Do a recursive delete. */
RewindDir(dir_hnd);
while ((dname = ReadDirName(dir_hnd, &talloced)) != NULL) {
struct smb_filename *direntry_fname = NULL;
struct smb_filename *smb_dname_full = NULL;
char *fullname = NULL;
bool do_break = true;
int retval;
if (ISDOT(dname) || ISDOTDOT(dname)) {
TALLOC_FREE(talloced);
continue;
}
fullname = talloc_asprintf(ctx,
"%s/%s",
smb_dname->base_name,
dname);
if (fullname == NULL) {
status = NT_STATUS_NO_MEMORY;
goto err_break;
}
smb_dname_full = synthetic_smb_fname(talloc_tos(),
fullname,
NULL,
NULL,
smb_dname->twrp,
smb_dname->flags);
if (smb_dname_full == NULL) {
status = NT_STATUS_NO_MEMORY;
goto err_break;
}
/*
* Todo: use SMB_VFS_STATX() once that's available.
*/
retval = SMB_VFS_LSTAT(conn, smb_dname_full);
if (retval != 0) {
status = map_nt_error_from_unix(errno);
goto err_break;
}
/*
* We are only dealing with VETO'ed objects
* here. If it's a symlink, just delete the
* link without caring what it is pointing
* to.
*/
if (S_ISLNK(smb_dname_full->st.st_ex_mode)) {
direntry_fname = synthetic_smb_fname(talloc_tos(),
dname,
NULL,
&smb_dname_full->st,
smb_dname->twrp,
smb_dname->flags);
if (direntry_fname == NULL) {
status = NT_STATUS_NO_MEMORY;
goto err_break;
}
} else {
status = synthetic_pathref(talloc_tos(),
dirfsp,
dname,
NULL,
&smb_dname_full->st,
smb_dname->twrp,
smb_dname->flags,
&direntry_fname);
if (!NT_STATUS_IS_OK(status)) {
goto err_break;
}
if (!is_visible_fsp(direntry_fname->fsp)) {
TALLOC_FREE(fullname);
TALLOC_FREE(smb_dname_full);
TALLOC_FREE(talloced);
TALLOC_FREE(direntry_fname);
continue;
}
}
unlink_flags = 0;
if (smb_dname_full->st.st_ex_mode & S_IFDIR) {
status = recursive_rmdir(ctx, conn, smb_dname_full);
if (!NT_STATUS_IS_OK(status)) {
goto err_break;
}
unlink_flags = AT_REMOVEDIR;
}
retval = SMB_VFS_UNLINKAT(conn,
dirfsp,
direntry_fname,
unlink_flags);
if (retval != 0) {
status = map_nt_error_from_unix(errno);
goto err_break;
}
/* Successful iteration. */
do_break = false;
err_break:
TALLOC_FREE(fullname);
TALLOC_FREE(smb_dname_full);
TALLOC_FREE(talloced);
TALLOC_FREE(direntry_fname);
if (do_break) {
break;
}
}
/* If we get here, we know NT_STATUS_IS_OK(status) */
SMB_ASSERT(NT_STATUS_IS_OK(status));
/* Retry the rmdir */
ret = SMB_VFS_UNLINKAT(conn,
parent_fname->fsp,

View File

@ -1222,12 +1222,11 @@ const char *ReadDirName(struct smb_Dir *dir_hnd, char **ptalloced)
continue;
}
/*
* ignore tmp directories, see mkdir_internal()
* ignore tmp directories, see mkdir_internals()
*/
if (IS_SMBD_TMPNAME(n, &unlink_flags)) {
struct files_struct *dirfsp = dir_hnd->fsp;
const char *dirname = dirfsp->fsp_name->base_name;
struct smb_filename *atname = NULL;
const char *fp = NULL;
int ret;
atname = synthetic_smb_fname(talloc_tos(),
@ -1240,9 +1239,17 @@ const char *ReadDirName(struct smb_Dir *dir_hnd, char **ptalloced)
TALLOC_FREE(talloced);
continue;
}
fp = full_path_from_dirfsp_at_basename(atname,
dir_hnd->fsp,
n);
if (fp == NULL) {
TALLOC_FREE(atname);
TALLOC_FREE(talloced);
continue;
}
if (unlink_flags == INT_MAX) {
DBG_NOTICE("ignoring %s/%s\n", dirname, n);
DBG_NOTICE("ignoring %s\n", fp);
TALLOC_FREE(atname);
TALLOC_FREE(talloced);
continue;
@ -1252,23 +1259,18 @@ const char *ReadDirName(struct smb_Dir *dir_hnd, char **ptalloced)
* We remove the stale tmpname
* as root and ignore any errors
*/
DBG_NOTICE("unlink stale %s/%s\n", dirname, n);
DBG_NOTICE("unlink stale %s\n", fp);
become_root();
ret = SMB_VFS_UNLINKAT(conn,
dirfsp,
dir_hnd->fsp,
atname,
unlink_flags);
unbecome_root();
if (ret == 0) {
DBG_NOTICE("unlinked stale %s/%s\n",
dirname,
n);
DBG_NOTICE("unlinked stale %s\n", fp);
} else {
DBG_WARNING(
"failed to unlink stale %s/%s: %s\n",
dirname,
n,
strerror(errno));
DBG_WARNING("failed to unlink stale %s: %s\n",
fp, strerror(errno));
}
TALLOC_FREE(atname);
TALLOC_FREE(talloced);
@ -1539,96 +1541,137 @@ bool opens_below_forall(struct connection_struct *conn,
Is this directory empty ?
*****************************************************************/
NTSTATUS can_delete_directory_hnd(struct smb_Dir *dir_hnd)
NTSTATUS can_delete_directory_fsp(files_struct *fsp)
{
NTSTATUS status = NT_STATUS_OK;
const char *dname = NULL;
char *talloced = NULL;
struct files_struct *dirfsp = dir_hnd_fetch_fsp(dir_hnd);
struct connection_struct *conn = dirfsp->conn;
bool delete_veto = lp_delete_veto_files(SNUM(conn));
struct connection_struct *conn = fsp->conn;
struct smb_Dir *dir_hnd = NULL;
status = OpenDir_from_pathref(talloc_tos(), fsp, NULL, 0, &dir_hnd);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
while ((dname = ReadDirName(dir_hnd, &talloced))) {
struct smb_filename *smb_dname_full = NULL;
struct smb_filename *direntry_fname = NULL;
char *fullname = NULL;
int ret;
if (ISDOT(dname) || (ISDOTDOT(dname))) {
TALLOC_FREE(talloced);
continue;
}
if (delete_veto && IS_VETO_PATH(conn, dname)) {
if (IS_VETO_PATH(conn, dname)) {
TALLOC_FREE(talloced);
continue;
}
direntry_fname = synthetic_smb_fname(talloc_tos(),
dname,
NULL,
NULL,
dirfsp->fsp_name->twrp,
dirfsp->fsp_name->flags);
TALLOC_FREE(talloced);
dname = NULL;
fullname = talloc_asprintf(talloc_tos(),
"%s/%s",
fsp->fsp_name->base_name,
dname);
if (fullname == NULL) {
status = NT_STATUS_NO_MEMORY;
break;
}
if (direntry_fname == NULL) {
smb_dname_full = synthetic_smb_fname(talloc_tos(),
fullname,
NULL,
NULL,
fsp->fsp_name->twrp,
fsp->fsp_name->flags);
if (smb_dname_full == NULL) {
TALLOC_FREE(talloced);
TALLOC_FREE(fullname);
status = NT_STATUS_NO_MEMORY;
break;
}
status = openat_pathref_fsp_lcomp(
dirfsp,
direntry_fname,
UCF_POSIX_PATHNAMES /* no ci fallback */);
if (!NT_STATUS_IS_OK(status)) {
DBG_DEBUG("Could not open %s: %s\n",
direntry_fname->base_name,
nt_errstr(status));
TALLOC_FREE(direntry_fname);
if (NT_STATUS_EQUAL(status,
NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
/* race between readdir and unlink */
continue;
}
status = NT_STATUS_DIRECTORY_NOT_EMPTY;
ret = SMB_VFS_LSTAT(conn, smb_dname_full);
if (ret != 0) {
status = map_nt_error_from_unix(errno);
TALLOC_FREE(talloced);
TALLOC_FREE(fullname);
TALLOC_FREE(smb_dname_full);
break;
}
if (S_ISLNK(direntry_fname->st.st_ex_mode)) {
int ret;
if (lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) &&
is_msdfs_link(dirfsp, direntry_fname))
{
DBG_DEBUG("got msdfs link name %s "
"- can't delete directory %s\n",
direntry_fname->base_name,
fsp_str_dbg(dirfsp));
status = NT_STATUS_DIRECTORY_NOT_EMPTY;
TALLOC_FREE(direntry_fname);
break;
if (S_ISLNK(smb_dname_full->st.st_ex_mode)) {
/* Could it be an msdfs link ? */
if (lp_host_msdfs() &&
lp_msdfs_root(SNUM(conn))) {
struct smb_filename *smb_dname;
smb_dname = synthetic_smb_fname(talloc_tos(),
dname,
NULL,
&smb_dname_full->st,
fsp->fsp_name->twrp,
fsp->fsp_name->flags);
if (smb_dname == NULL) {
TALLOC_FREE(talloced);
TALLOC_FREE(fullname);
TALLOC_FREE(smb_dname_full);
status = NT_STATUS_NO_MEMORY;
break;
}
if (is_msdfs_link(fsp, smb_dname)) {
TALLOC_FREE(talloced);
TALLOC_FREE(fullname);
TALLOC_FREE(smb_dname_full);
TALLOC_FREE(smb_dname);
DBG_DEBUG("got msdfs link name %s "
"- can't delete directory %s\n",
dname,
fsp_str_dbg(fsp));
status = NT_STATUS_DIRECTORY_NOT_EMPTY;
break;
}
TALLOC_FREE(smb_dname);
}
/* Not a DFS link - could it be a dangling symlink ? */
ret = SMB_VFS_FSTATAT(conn,
dirfsp,
direntry_fname,
&direntry_fname->st,
0 /* 0 means follow symlink */);
ret = SMB_VFS_STAT(conn, smb_dname_full);
if (ret == -1 && (errno == ENOENT || errno == ELOOP)) {
/*
* Dangling symlink.
* Allow if "delete veto files = yes"
*/
if (lp_delete_veto_files(SNUM(conn))) {
TALLOC_FREE(direntry_fname);
TALLOC_FREE(talloced);
TALLOC_FREE(fullname);
TALLOC_FREE(smb_dname_full);
continue;
}
}
DBG_DEBUG("got symlink name %s - "
"can't delete directory %s\n",
dname,
fsp_str_dbg(fsp));
TALLOC_FREE(talloced);
TALLOC_FREE(fullname);
TALLOC_FREE(smb_dname_full);
status = NT_STATUS_DIRECTORY_NOT_EMPTY;
break;
}
/* Not a symlink, get a pathref. */
status = synthetic_pathref(talloc_tos(),
fsp,
dname,
NULL,
&smb_dname_full->st,
fsp->fsp_name->twrp,
fsp->fsp_name->flags,
&direntry_fname);
if (!NT_STATUS_IS_OK(status)) {
status = map_nt_error_from_unix(errno);
TALLOC_FREE(talloced);
TALLOC_FREE(fullname);
TALLOC_FREE(smb_dname_full);
break;
}
if (!is_visible_fsp(direntry_fname->fsp)) {
@ -1637,40 +1680,33 @@ NTSTATUS can_delete_directory_hnd(struct smb_Dir *dir_hnd)
* Allow if "delete veto files = yes"
*/
if (lp_delete_veto_files(SNUM(conn))) {
TALLOC_FREE(talloced);
TALLOC_FREE(fullname);
TALLOC_FREE(smb_dname_full);
TALLOC_FREE(direntry_fname);
continue;
}
}
DBG_DEBUG("got name %s - can't delete\n",
direntry_fname->base_name);
TALLOC_FREE(talloced);
TALLOC_FREE(fullname);
TALLOC_FREE(smb_dname_full);
TALLOC_FREE(direntry_fname);
DBG_DEBUG("got name %s - can't delete\n", dname);
status = NT_STATUS_DIRECTORY_NOT_EMPTY;
break;
}
TALLOC_FREE(talloced);
TALLOC_FREE(dir_hnd);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
if (have_file_open_below(dirfsp)) {
if (have_file_open_below(fsp)) {
return NT_STATUS_ACCESS_DENIED;
}
return NT_STATUS_OK;
}
NTSTATUS can_delete_directory_fsp(files_struct *fsp)
{
struct smb_Dir *dir_hnd = NULL;
NTSTATUS status;
status = OpenDir_from_pathref(talloc_tos(), fsp, NULL, 0, &dir_hnd);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
status = can_delete_directory_hnd(dir_hnd);
TALLOC_FREE(dir_hnd);
return status;
}

View File

@ -23,7 +23,6 @@
struct smb_Dir;
struct dptr_struct;
NTSTATUS can_delete_directory_hnd(struct smb_Dir *dir_hnd);
NTSTATUS can_delete_directory_fsp(files_struct *fsp);
struct files_struct *dir_hnd_fetch_fsp(struct smb_Dir *dir_hnd);
uint16_t dptr_attr(struct smbd_server_connection *sconn, int key);

View File

@ -4749,7 +4749,7 @@ mkdir_first:
&rhow);
if (ret == -1 && errno == EINVAL) {
/*
* This is the strategy we use without having
* This is the strategie we use without having
* renameat2(RENAME_NOREPLACE):
*
* renameat() is able to replace a directory if the source is
@ -5423,7 +5423,6 @@ void msg_file_was_renamed(struct messaging_context *msg_ctx,
*/
static NTSTATUS open_streams_for_delete(connection_struct *conn,
struct files_struct *dirfsp,
const struct smb_filename *smb_fname)
{
struct stream_struct *stream_info = NULL;
@ -5476,7 +5475,8 @@ static NTSTATUS open_streams_for_delete(connection_struct *conn,
goto fail;
}
DBG_DEBUG("open_streams_for_delete found %u streams\n", num_streams);
DEBUG(10, ("open_streams_for_delete found %d streams\n",
num_streams));
if (num_streams == 0) {
TALLOC_FREE(frame);
@ -5522,7 +5522,7 @@ static NTSTATUS open_streams_for_delete(connection_struct *conn,
status = SMB_VFS_CREATE_FILE(
conn, /* conn */
NULL, /* req */
dirfsp, /* dirfsp */
NULL, /* dirfsp */
smb_fname_cp, /* fname */
DELETE_ACCESS, /* access_mask */
(FILE_SHARE_READ | /* share_access */
@ -6222,7 +6222,7 @@ static NTSTATUS create_file_unixpath(connection_struct *conn,
* We can't open a file with DELETE access if any of the
* streams is open without FILE_SHARE_DELETE
*/
status = open_streams_for_delete(conn, dirfsp, smb_fname);
status = open_streams_for_delete(conn, smb_fname);
if (!NT_STATUS_IS_OK(status)) {
goto fail;

View File

@ -2181,18 +2181,22 @@ static NTSTATUS smb_q_unix_info2(
return NT_STATUS_OK;
}
#if defined(HAVE_POSIX_ACLS)
/****************************************************************************
Utility function to open a fsp for a POSIX handle operation.
****************************************************************************/
static NTSTATUS get_posix_fsp(connection_struct *conn,
struct smb_request *req,
struct files_struct *dirfsp,
struct smb_filename *smb_fname,
uint32_t access_mask,
files_struct **ret_fsp)
{
NTSTATUS status;
uint32_t create_disposition = FILE_OPEN;
uint32_t share_access = FILE_SHARE_READ|
FILE_SHARE_WRITE|
FILE_SHARE_DELETE;
struct smb2_create_blobs *posx = NULL;
/*
@ -2200,6 +2204,7 @@ static NTSTATUS get_posix_fsp(connection_struct *conn,
* but set reasonable defaults.
*/
uint32_t file_attributes = 0664;
uint32_t oplock = NO_OPLOCK;
uint32_t create_options = FILE_NON_DIRECTORY_FILE;
/* File or directory must exist. */
@ -2229,34 +2234,31 @@ static NTSTATUS get_posix_fsp(connection_struct *conn,
}
status = SMB_VFS_CREATE_FILE(
conn, /* conn */
req, /* req */
dirfsp, /* dirfsp */
smb_fname, /* fname */
access_mask, /* access_mask */
FILE_SHARE_READ | FILE_SHARE_WRITE |
FILE_SHARE_DELETE, /* share_access */
FILE_OPEN, /* create_disposition*/
create_options, /* create_options */
file_attributes, /* file_attributes */
NO_OPLOCK, /* oplock_request */
NULL, /* lease */
0, /* allocation_size */
0, /* private_flags */
NULL, /* sd */
NULL, /* ea_list */
ret_fsp, /* result */
NULL, /* pinfo */
posx, /* in_context */
NULL); /* out_context */
conn, /* conn */
req, /* req */
NULL, /* dirfsp */
smb_fname, /* fname */
access_mask, /* access_mask */
share_access, /* share_access */
create_disposition,/* create_disposition*/
create_options, /* create_options */
file_attributes,/* file_attributes */
oplock, /* oplock_request */
NULL, /* lease */
0, /* allocation_size */
0, /* private_flags */
NULL, /* sd */
NULL, /* ea_list */
ret_fsp, /* result */
NULL, /* pinfo */
posx, /* in_context */
NULL); /* out_context */
done:
TALLOC_FREE(posx);
return status;
}
#if defined(HAVE_POSIX_ACLS)
/****************************************************************************
Utility function to count the number of entries in a POSIX acl.
****************************************************************************/
@ -2386,6 +2388,30 @@ static NTSTATUS smb_q_posix_acl(
unsigned int size_needed = 0;
NTSTATUS status;
bool ok, refuse;
bool close_fsp = false;
/*
* Ensure we always operate on a file descriptor, not just
* the filename.
*/
if (fsp == NULL || !fsp->fsp_flags.is_fsa) {
uint32_t access_mask = SEC_STD_READ_CONTROL|
FILE_READ_ATTRIBUTES|
FILE_WRITE_ATTRIBUTES;
status = get_posix_fsp(conn,
req,
smb_fname,
access_mask,
&fsp);
if (!NT_STATUS_IS_OK(status)) {
goto out;
}
close_fsp = true;
}
SMB_ASSERT(fsp != NULL);
refuse = refuse_symlink_fsp(fsp);
if (refuse) {
@ -2483,6 +2509,16 @@ static NTSTATUS smb_q_posix_acl(
status = NT_STATUS_OK;
out:
if (close_fsp) {
/*
* Ensure the stat struct in smb_fname is up to
* date. Structure copy.
*/
smb_fname->st = fsp->fsp_name->st;
(void)close_file_free(req, &fsp, NORMAL_CLOSE);
}
TALLOC_FREE(file_acl);
TALLOC_FREE(def_acl);
return status;
@ -2726,25 +2762,15 @@ static void call_trans2qpathinfo(
&total_data);
break;
case SMB_QUERY_POSIX_ACL: {
struct files_struct *posix_fsp = NULL;
status = get_posix_fsp(conn,
req,
dirfsp,
smb_fname,
SEC_STD_READ_CONTROL |
FILE_READ_ATTRIBUTES |
FILE_WRITE_ATTRIBUTES,
&posix_fsp);
if (!NT_STATUS_IS_OK(status)) {
break;
}
case SMB_QUERY_POSIX_ACL:
status = smb_q_posix_acl(
conn, req, smb_fname, posix_fsp, ppdata, &total_data);
(void)close_file_free(req, &posix_fsp, NORMAL_CLOSE);
conn,
req,
smb_fname,
smb_fname->fsp,
ppdata,
&total_data);
break;
}
case SMB_QUERY_FILE_UNIX_LINK:
status = smb_q_posix_symlink(conn,
@ -3120,7 +3146,6 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn,
struct smb_request *req,
char **ppdata,
int total_data,
struct files_struct *dirfsp,
struct smb_filename *smb_fname,
int *pdata_return_size)
{
@ -3162,7 +3187,7 @@ static NTSTATUS smb_posix_mkdir(connection_struct *conn,
status = SMB_VFS_CREATE_FILE(
conn, /* conn */
req, /* req */
dirfsp, /* dirfsp */
NULL, /* dirfsp */
smb_fname, /* fname */
FILE_READ_ATTRIBUTES, /* access_mask */
FILE_SHARE_NONE, /* share_access */
@ -3275,13 +3300,11 @@ static NTSTATUS smb_posix_open(connection_struct *conn,
wire_open_mode = IVAL(pdata,4);
if (wire_open_mode == (SMB_O_CREAT|SMB_O_DIRECTORY)) {
return smb_posix_mkdir(conn,
req,
ppdata,
total_data,
dirfsp,
smb_fname,
pdata_return_size);
return smb_posix_mkdir(conn, req,
ppdata,
total_data,
smb_fname,
pdata_return_size);
}
switch (wire_open_mode & SMB_ACCMODE) {
@ -3408,10 +3431,10 @@ static NTSTATUS smb_posix_open(connection_struct *conn,
create_options |= FILE_DIRECTORY_FILE;
}
DBG_DEBUG("file %s, smb_posix_flags = %" PRIu32 ", mode 0%o\n",
smb_fname_str_dbg(smb_fname),
wire_open_mode,
(unsigned int)unixmode);
DEBUG(10,("smb_posix_open: file %s, smb_posix_flags = %u, mode 0%o\n",
smb_fname_str_dbg(smb_fname),
(unsigned int)wire_open_mode,
(unsigned int)unixmode ));
status = SMB_VFS_CREATE_FILE(
conn, /* conn */
@ -3971,9 +3994,9 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
}
DBG_DEBUG("SMB_SET_FILE_UNIX_BASIC: name = "
"%s size = %jd, uid = %u, gid = %u, raw perms = 0%o\n",
"%s size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
smb_fname_str_dbg(smb_fname),
(intmax_t)size,
(double)size,
(unsigned int)set_owner,
(unsigned int)set_grp,
(int)raw_unixmode);
@ -4021,10 +4044,10 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
DBG_DEBUG("SMB_SET_FILE_UNIX_BASIC "
DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC "
"setting mode 0%o for file %s\n",
(unsigned int)unixmode,
smb_fname_str_dbg(smb_fname));
smb_fname_str_dbg(smb_fname)));
ret = SMB_VFS_FCHMOD(fsp, unixmode);
if (ret != 0) {
return map_nt_error_from_unix(errno);
@ -4244,6 +4267,7 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn,
NTSTATUS status;
unsigned int size_needed;
unsigned int total_data;
bool close_fsp = false;
bool refuse;
if (total_data_in < 0) {
@ -4305,6 +4329,32 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn,
goto out;
}
/*
* Ensure we always operate on a file descriptor, not just
* the filename.
*/
if (fsp == NULL || !fsp->fsp_flags.is_fsa) {
uint32_t access_mask = SEC_STD_WRITE_OWNER|
SEC_STD_WRITE_DAC|
SEC_STD_READ_CONTROL|
FILE_READ_ATTRIBUTES|
FILE_WRITE_ATTRIBUTES;
status = get_posix_fsp(conn,
req,
smb_fname,
access_mask,
&fsp);
if (!NT_STATUS_IS_OK(status)) {
goto out;
}
close_fsp = true;
}
/* Here we know fsp != NULL */
SMB_ASSERT(fsp != NULL);
refuse = refuse_symlink_fsp(fsp);
if (refuse) {
status = NT_STATUS_ACCESS_DENIED;
@ -4354,6 +4404,10 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn,
status = NT_STATUS_OK;
out:
if (close_fsp) {
(void)close_file_free(req, &fsp, NORMAL_CLOSE);
}
return status;
#endif
}
@ -4514,34 +4568,21 @@ static void call_trans2setpathinfo(
smb_fname->fsp,
smb_fname);
break;
case SMB_SET_POSIX_ACL: {
struct files_struct *posix_fsp = NULL;
status = get_posix_fsp(conn,
req,
dirfsp,
smb_fname,
SEC_STD_WRITE_OWNER |
SEC_STD_WRITE_DAC |
SEC_STD_READ_CONTROL |
FILE_READ_ATTRIBUTES |
FILE_WRITE_ATTRIBUTES,
&posix_fsp);
if (!NT_STATUS_IS_OK(status)) {
break;
}
case SMB_SET_POSIX_ACL:
status = smb_set_posix_acl(
conn, req, *ppdata, total_data, posix_fsp, smb_fname);
(void)close_file_free(req, &posix_fsp, NORMAL_CLOSE);
conn, req, *ppdata, total_data, NULL, smb_fname);
break;
}
}
if (info_level_handled) {
goto done;
}
/*
* smb_fname->fsp may be NULL if smb_fname points at a symlink
* and we're in POSIX context, so be careful when using fsp
* below, it can still be NULL.
*/
fsp = smb_fname->fsp;
if (fsp == NULL) {
status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
@ -4661,10 +4702,10 @@ static void call_trans2setfileinfo(
*ppdata, 0,
max_data_bytes);
return;
} else {
reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
return;
}
reply_nterror(req, NT_STATUS_OBJECT_PATH_NOT_FOUND);
return;
} else {
/*
* Original code - this is an open file.

View File

@ -5052,10 +5052,11 @@ static NTSTATUS smb_set_file_end_of_file_info(connection_struct *conn,
return NT_STATUS_INVALID_PARAMETER;
}
size = (off_t)PULL_LE_U64(pdata, 0);
DBG_DEBUG("Set end of file info for file %s to %ju\n",
smb_fname_str_dbg(smb_fname),
(uintmax_t)size);
size = IVAL(pdata,0);
size |= (((off_t)IVAL(pdata,4)) << 32);
DEBUG(10,("smb_set_file_end_of_file_info: Set end of file info for "
"file %s to %.0f\n", smb_fname_str_dbg(smb_fname),
(double)size));
return smb_set_file_size(conn, req,
fsp,

View File

@ -342,12 +342,8 @@ static int DoWriteCommand( int argc, char **argv, bool debugflag, char *exename
fixup_eventlog_record_tdb( &ee );
if ( opt_debug )
printf("record number [%" PRIu32 "], "
"tg [%" PRIu64 "] , "
"tw [%" PRIu64 "]\n",
ee.record_number,
(uint64_t)ee.time_generated,
(uint64_t)ee.time_written);
printf( "record number [%d], tg [%d] , tw [%d]\n",
ee.record_number, (int)ee.time_generated, (int)ee.time_written );
if ( ee.time_generated != 0 ) {

View File

@ -355,9 +355,8 @@ static int account_set_minpwage(struct net_context *c,
}
unix_to_nt_time_abs((NTTIME *)&i1->min_password_age, atoi(argv[0]));
d_printf(_("Setting minimum password age to %" PRIu64 " seconds\n"),
(uint64_t)nt_time_to_unix_abs(
(NTTIME *)&i1->min_password_age));
d_printf(_("Setting minimum password age to %d seconds\n"),
(int)nt_time_to_unix_abs((NTTIME *)&i1->min_password_age));
return 1;
}

View File

@ -0,0 +1,78 @@
/*
Unix SMB/CIFS implementation.
async seqnum
Copyright (C) Volker Lendecke 2009
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "winbindd.h"
#include "librpc/gen_ndr/ndr_winbind_c.h"
struct wb_seqnum_state {
uint32_t seqnum;
};
static void wb_seqnum_done(struct tevent_req *subreq);
struct tevent_req *wb_seqnum_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct winbindd_domain *domain)
{
struct tevent_req *req, *subreq;
struct wb_seqnum_state *state;
req = tevent_req_create(mem_ctx, &state, struct wb_seqnum_state);
if (req == NULL) {
return NULL;
}
subreq = dcerpc_wbint_QuerySequenceNumber_send(
state, ev, dom_child_handle(domain), &state->seqnum);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
tevent_req_set_callback(subreq, wb_seqnum_done, req);
return req;
}
static void wb_seqnum_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct wb_seqnum_state *state = tevent_req_data(
req, struct wb_seqnum_state);
NTSTATUS status, result;
status = dcerpc_wbint_QuerySequenceNumber_recv(subreq, state, &result);
TALLOC_FREE(subreq);
if (any_nt_status_not_ok(status, result, &status)) {
tevent_req_nterror(req, status);
return;
}
tevent_req_done(req);
}
NTSTATUS wb_seqnum_recv(struct tevent_req *req, uint32_t *seqnum)
{
struct wb_seqnum_state *state = tevent_req_data(
req, struct wb_seqnum_state);
NTSTATUS status;
if (tevent_req_is_nterror(req, &status)) {
return status;
}
*seqnum = state->seqnum;
return NT_STATUS_OK;
}

View File

@ -0,0 +1,153 @@
/*
Unix SMB/CIFS implementation.
async seqnums, update the seqnums in winbindd_cache.c
Copyright (C) Volker Lendecke 2009
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "winbindd.h"
#include "librpc/gen_ndr/ndr_winbind_c.h"
struct wb_seqnums_state {
int num_domains;
int num_received;
struct tevent_req **subreqs;
struct winbindd_domain **domains;
NTSTATUS *statuses;
uint32_t *seqnums;
};
static void wb_seqnums_done(struct tevent_req *subreq);
struct tevent_req *wb_seqnums_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev)
{
struct tevent_req *req;
struct wb_seqnums_state *state;
struct winbindd_domain *domain;
int i;
req = tevent_req_create(mem_ctx, &state, struct wb_seqnums_state);
if (req == NULL) {
return NULL;
}
state->num_received = 0;
state->num_domains = 0;
for (domain = domain_list(); domain != NULL; domain = domain->next) {
state->num_domains += 1;
}
state->subreqs = talloc_array(state, struct tevent_req *,
state->num_domains);
state->domains = talloc_zero_array(state, struct winbindd_domain *,
state->num_domains);
state->statuses = talloc_array(state, NTSTATUS, state->num_domains);
state->seqnums = talloc_array(state, uint32_t, state->num_domains);
if ((state->subreqs == NULL) || (state->domains == NULL) ||
(state->statuses == NULL) || (state->seqnums == NULL)) {
tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
return tevent_req_post(req, ev);
}
i = 0;
for (domain = domain_list(); domain != NULL; domain = domain->next) {
state->domains[i] = domain;
state->subreqs[i] = wb_seqnum_send(state->subreqs, ev, domain);
if (tevent_req_nomem(state->subreqs[i], req)) {
/* Don't even start all the other requests */
TALLOC_FREE(state->subreqs);
return tevent_req_post(req, ev);
}
tevent_req_set_callback(state->subreqs[i], wb_seqnums_done,
req);
i += 1;
}
return req;
}
static void wb_seqnums_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct wb_seqnums_state *state = tevent_req_data(
req, struct wb_seqnums_state);
NTSTATUS status;
uint32_t seqnum;
int i;
status = wb_seqnum_recv(subreq, &seqnum);
for (i=0; i<state->num_domains; i++) {
if (subreq == state->subreqs[i]) {
break;
}
}
if (i < state->num_domains) {
/* found one */
state->subreqs[i] = NULL;
state->statuses[i] = status;
if (NT_STATUS_IS_OK(status)) {
state->seqnums[i] = seqnum;
/*
* This first assignment might be removed
* later
*/
state->domains[i]->sequence_number = seqnum;
if (!wcache_store_seqnum(state->domains[i]->name,
state->seqnums[i],
time(NULL))) {
DEBUG(1, ("wcache_store_seqnum failed for "
"domain %s\n",
state->domains[i]->name));
}
}
}
TALLOC_FREE(subreq);
state->num_received += 1;
if (state->num_received >= state->num_domains) {
tevent_req_done(req);
}
}
NTSTATUS wb_seqnums_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
int *num_domains, struct winbindd_domain ***domains,
NTSTATUS **statuses, uint32_t **seqnums)
{
struct wb_seqnums_state *state = tevent_req_data(
req, struct wb_seqnums_state);
NTSTATUS status;
if (tevent_req_is_nterror(req, &status)) {
return status;
}
*num_domains = state->num_domains;
*domains = talloc_move(mem_ctx, &state->domains);
*statuses = talloc_move(mem_ctx, &state->statuses);
*seqnums = talloc_move(mem_ctx, &state->seqnums);
return NT_STATUS_OK;
}

View File

@ -338,6 +338,8 @@ static struct winbindd_async_dispatch_table async_nonpriv_table[] = {
winbindd_getuserdomgroups_send, winbindd_getuserdomgroups_recv },
{ WINBINDD_GETGROUPS, "GETGROUPS",
winbindd_getgroups_send, winbindd_getgroups_recv },
{ WINBINDD_SHOW_SEQUENCE, "SHOW_SEQUENCE",
winbindd_show_sequence_send, winbindd_show_sequence_recv },
{ WINBINDD_GETGRGID, "GETGRGID",
winbindd_getgrgid_send, winbindd_getgrgid_recv },
{ WINBINDD_GETGRNAM, "GETGRNAM",

View File

@ -59,11 +59,9 @@ static void ads_cached_connection_reuse(ADS_STRUCT **adsp)
expire = nt_time_to_unix(ads->auth.expire_time);
DBG_INFO("Current tickets expire in %" PRIu64 " seconds "
"(at %" PRIu64 ", time is now %" PRIu64 ")\n",
(uint64_t)expire - (uint64_t)now,
(uint64_t)expire,
(uint64_t)now);
DEBUG(7, ("Current tickets expire in %d seconds (at %d, time "
"is now %d)\n", (uint32_t)expire - (uint32_t)now,
(uint32_t) expire, (uint32_t) now));
if ( ads->config.realm && (expire > now)) {
return;

View File

@ -502,6 +502,8 @@ NTSTATUS winbind_dual_SamLogon(struct winbindd_domain *domain,
struct winbindd_domain *domain_list(void);
struct winbindd_domain *wb_next_domain(struct winbindd_domain *domain);
bool set_routing_domain(struct winbindd_domain *domain,
struct winbindd_domain *routing_domain);
bool add_trusted_domain_from_auth(uint16_t validation_level,
struct info3_text *info3,
struct info6_text *info6);
@ -740,6 +742,24 @@ struct tevent_req *winbindd_getgroups_send(TALLOC_CTX *mem_ctx,
NTSTATUS winbindd_getgroups_recv(struct tevent_req *req,
struct winbindd_response *response);
struct tevent_req *wb_seqnum_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct winbindd_domain *domain);
NTSTATUS wb_seqnum_recv(struct tevent_req *req, uint32_t *seqnum);
struct tevent_req *wb_seqnums_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev);
NTSTATUS wb_seqnums_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
int *num_domains, struct winbindd_domain ***domains,
NTSTATUS **statuses, uint32_t **seqnums);
struct tevent_req *winbindd_show_sequence_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct winbindd_cli_state *cli,
struct winbindd_request *request);
NTSTATUS winbindd_show_sequence_recv(struct tevent_req *req,
struct winbindd_response *response);
struct tevent_req *wb_group_members_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
const struct dom_sid *sid,

View File

@ -0,0 +1,167 @@
/*
Unix SMB/CIFS implementation.
async implementation of WINBINDD_SHOW_SEQUENCE
Copyright (C) Volker Lendecke 2009
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "winbindd.h"
struct winbindd_show_sequence_state {
bool one_domain;
/* One domain */
uint32_t seqnum;
/* All domains */
int num_domains;
NTSTATUS *statuses;
struct winbindd_domain **domains;
uint32_t *seqnums;
};
static void winbindd_show_sequence_done_one(struct tevent_req *subreq);
static void winbindd_show_sequence_done_all(struct tevent_req *subreq);
struct tevent_req *winbindd_show_sequence_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct winbindd_cli_state *cli,
struct winbindd_request *request)
{
struct tevent_req *req, *subreq;
struct winbindd_show_sequence_state *state;
req = tevent_req_create(mem_ctx, &state,
struct winbindd_show_sequence_state);
if (req == NULL) {
return NULL;
}
state->one_domain = false;
state->domains = NULL;
state->statuses = NULL;
state->seqnums = NULL;
/* Ensure null termination */
request->domain_name[sizeof(request->domain_name)-1]='\0';
DEBUG(3, ("show_sequence %s\n", request->domain_name));
if (request->domain_name[0] != '\0') {
struct winbindd_domain *domain;
state->one_domain = true;
domain = find_domain_from_name_noinit(
request->domain_name);
if (domain == NULL) {
tevent_req_nterror(req, NT_STATUS_NO_SUCH_DOMAIN);
return tevent_req_post(req, ev);
}
subreq = wb_seqnum_send(state, ev, domain);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
tevent_req_set_callback(
subreq, winbindd_show_sequence_done_one, req);
return req;
}
subreq = wb_seqnums_send(state, ev);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
tevent_req_set_callback(subreq, winbindd_show_sequence_done_all, req);
return req;
}
static void winbindd_show_sequence_done_one(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct winbindd_show_sequence_state *state = tevent_req_data(
req, struct winbindd_show_sequence_state);
NTSTATUS status;
status = wb_seqnum_recv(subreq, &state->seqnum);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
tevent_req_done(req);
}
static void winbindd_show_sequence_done_all(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct winbindd_show_sequence_state *state = tevent_req_data(
req, struct winbindd_show_sequence_state);
NTSTATUS status;
status = wb_seqnums_recv(subreq, state, &state->num_domains,
&state->domains, &state->statuses,
&state->seqnums);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
tevent_req_done(req);
}
NTSTATUS winbindd_show_sequence_recv(struct tevent_req *req,
struct winbindd_response *response)
{
struct winbindd_show_sequence_state *state = tevent_req_data(
req, struct winbindd_show_sequence_state);
NTSTATUS status;
char *extra_data;
int i;
if (tevent_req_is_nterror(req, &status)) {
return status;
}
if (state->one_domain) {
response->data.sequence_number = state->seqnum;
return NT_STATUS_OK;
}
extra_data = talloc_strdup(response, "");
if (extra_data == NULL) {
return NT_STATUS_NO_MEMORY;
}
for (i=0; i<state->num_domains; i++) {
if (!NT_STATUS_IS_OK(state->statuses[i])
|| (state->seqnums[i] == DOM_SEQUENCE_NONE)) {
extra_data = talloc_asprintf_append_buffer(
extra_data, "%s : DISCONNECTED\n",
state->domains[i]->name);
} else {
extra_data = talloc_asprintf_append_buffer(
extra_data, "%s : %d\n",
state->domains[i]->name,
(int)state->seqnums[i]);
}
if (extra_data == NULL) {
return NT_STATUS_NO_MEMORY;
}
}
response->extra_data.data = extra_data;
response->length += talloc_get_size(extra_data);
return NT_STATUS_OK;
}

View File

@ -302,6 +302,19 @@ static NTSTATUS add_trusted_domain(const char *domain_name,
return NT_STATUS_OK;
}
bool set_routing_domain(struct winbindd_domain *domain,
struct winbindd_domain *routing_domain)
{
if (domain->routing_domain == NULL) {
domain->routing_domain = routing_domain;
return true;
}
if (domain->routing_domain != routing_domain) {
return false;
}
return true;
}
bool add_trusted_domain_from_auth(uint16_t validation_level,
struct info3_text *info3,
struct info6_text *info6)

View File

@ -208,6 +208,8 @@ bld.SAMBA3_SUBSYSTEM('winbindd-lib',
wb_lookupusergroups.c
wb_getpwsid.c
wb_gettoken.c
wb_seqnum.c
wb_seqnums.c
wb_group_members.c
wb_alias_members.c
wb_getgrsid.c
@ -229,6 +231,7 @@ bld.SAMBA3_SUBSYSTEM('winbindd-lib',
winbindd_getsidaliases.c
winbindd_getuserdomgroups.c
winbindd_getgroups.c
winbindd_show_sequence.c
winbindd_getgrgid.c
winbindd_getgrnam.c
winbindd_getusersids.c

View File

@ -736,6 +736,162 @@ static bool torture_winbind_struct_list_groups(struct torture_context *torture)
return true;
}
struct torture_domain_sequence {
const char *netbios_name;
uint32_t seq;
};
static bool get_sequence_numbers(struct torture_context *torture,
struct torture_domain_sequence **seqs)
{
struct winbindd_request req;
struct winbindd_response rep;
const char *extra_data;
char line[256];
uint32_t count = 0;
struct torture_domain_sequence *s = NULL;
ZERO_STRUCT(req);
ZERO_STRUCT(rep);
DO_STRUCT_REQ_REP(WINBINDD_SHOW_SEQUENCE, &req, &rep);
extra_data = (char *)rep.extra_data.data;
torture_assert(torture, extra_data, "NULL sequence list");
while (next_token(&extra_data, line, "\n", sizeof(line))) {
char *p, *lp;
uint32_t seq;
s = talloc_realloc(torture, s, struct torture_domain_sequence,
count + 2);
ZERO_STRUCT(s[count+1]);
lp = line;
p = strchr(lp, ' ');
torture_assert(torture, p, "invalid line format");
*p = 0;
s[count].netbios_name = talloc_strdup(s, lp);
lp = p+1;
torture_assert(torture, strncmp(lp, ": ", 2) == 0,
"invalid line format");
lp += 2;
if (strcmp(lp, "DISCONNECTED") == 0) {
seq = (uint32_t)-1;
} else {
seq = (uint32_t)strtol(lp, &p, 10);
torture_assert(torture, (*p == '\0'),
"invalid line format");
torture_assert(torture, (seq != (uint32_t)-1),
"sequence number -1 encountered");
}
s[count].seq = seq;
count++;
}
SAFE_FREE(rep.extra_data.data);
torture_assert(torture, count >= 2, "The list of domain sequence "
"numbers should contain 2 entries");
*seqs = s;
return true;
}
static bool torture_winbind_struct_show_sequence(struct torture_context *torture)
{
bool ok;
uint32_t i;
struct torture_trust_domain *domlist = NULL;
struct torture_domain_sequence *s = NULL;
torture_comment(torture, "Running WINBINDD_SHOW_SEQUENCE (struct based)\n");
ok = get_sequence_numbers(torture, &s);
torture_assert(torture, ok, "failed to get list of sequence numbers");
ok = get_trusted_domains(torture, &domlist);
torture_assert(torture, ok, "failed to get trust list");
for (i=0; domlist[i].netbios_name; i++) {
struct winbindd_request req;
struct winbindd_response rep;
uint32_t seq;
torture_assert(torture, s[i].netbios_name,
"more domains received in second run");
torture_assert_str_equal(torture, domlist[i].netbios_name,
s[i].netbios_name,
"inconsistent order of domain lists");
ZERO_STRUCT(req);
ZERO_STRUCT(rep);
fstrcpy(req.domain_name, domlist[i].netbios_name);
ok = true;
DO_STRUCT_REQ_REP_EXT(WINBINDD_SHOW_SEQUENCE, &req, &rep,
NSS_STATUS_SUCCESS,
false, ok = false,
"WINBINDD_SHOW_SEQUENCE");
if (ok == false) {
torture_warning(torture,
"WINBINDD_SHOW_SEQUENCE on "
"domain %s failed\n",
req.domain_name);
/*
* Only fail for the first two domain that we
* check specially below, otherwise we fail on
* trusts generated by the LSA torture test
* that do not really exist.
*/
if (i > 1) {
/*
* Do not confirm the sequence numbers
* below
*/
return true;
}
torture_comment(torture,
"Full trust list for "
"WINBINDD_SHOW_SEQUENCE "
"test was:\n");
for (i=0; domlist[i].netbios_name; i++) {
torture_comment(torture,
"%s\n",
domlist[i].netbios_name);
}
return false;
}
seq = rep.data.sequence_number;
if (i == 0) {
torture_assert(torture, (seq != (uint32_t)-1),
"BUILTIN domain disconnected");
} else if (i == 1) {
torture_assert(torture, (seq != (uint32_t)-1),
"local domain disconnected");
}
if (seq == (uint32_t)-1) {
torture_comment(torture, " * %s : DISCONNECTED\n",
req.domain_name);
} else {
torture_comment(torture, " * %s : %d\n",
req.domain_name, seq);
}
torture_assert(torture, (seq >= s[i].seq),
"illegal sequence number encountered");
}
return true;
}
static bool torture_winbind_struct_setpwent(struct torture_context *torture)
{
struct winbindd_request req;
@ -1018,6 +1174,7 @@ struct torture_suite *torture_winbind_struct_init(TALLOC_CTX *ctx)
torture_suite_add_simple_test(suite, "dsgetdcname", torture_winbind_struct_dsgetdcname);
torture_suite_add_simple_test(suite, "list_users", torture_winbind_struct_list_users);
torture_suite_add_simple_test(suite, "list_groups", torture_winbind_struct_list_groups);
torture_suite_add_simple_test(suite, "show_sequence", torture_winbind_struct_show_sequence);
torture_suite_add_simple_test(suite, "setpwent", torture_winbind_struct_setpwent);
torture_suite_add_simple_test(suite, "getpwent", torture_winbind_struct_getpwent);
torture_suite_add_simple_test(suite, "endpwent", torture_winbind_struct_endpwent);