#include <smbsrv/smb_kproto.h>
#include <smbsrv/smbinfo.h>
#include <smbsrv/smb_fsops.h>
smb_sdrc_t
smb_pre_create_directory(smb_request_t *sr)
{
int rc;
rc = smbsr_decode_data(sr, "%S", sr,
&sr->arg.dirop.fqi.fq_path.pn_path);
DTRACE_SMB_START(op__CreateDirectory, smb_request_t *, sr);
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
void
smb_post_create_directory(smb_request_t *sr)
{
DTRACE_SMB_DONE(op__CreateDirectory, smb_request_t *, sr);
}
smb_sdrc_t
smb_com_create_directory(smb_request_t *sr)
{
int rc = 0;
smb_pathname_t *pn = &sr->arg.dirop.fqi.fq_path;
if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
ERRDOS, ERROR_ACCESS_DENIED);
return (SDRC_ERROR);
}
smb_pathname_init(sr, pn, pn->pn_path);
if (!smb_pathname_validate(sr, pn) ||
!smb_validate_dirname(sr, pn)) {
return (SDRC_ERROR);
}
if ((rc = smb_common_create_directory(sr)) != 0) {
smbsr_errno(sr, rc);
return (SDRC_ERROR);
}
rc = smbsr_encode_empty_result(sr);
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
int
smb_common_create_directory(smb_request_t *sr)
{
int rc;
smb_attr_t new_attr;
smb_fqi_t *fqi;
smb_node_t *tnode;
fqi = &sr->arg.dirop.fqi;
tnode = sr->tid_tree->t_snode;
rc = smb_pathname_reduce(sr, sr->user_cr, fqi->fq_path.pn_path,
tnode, tnode, &fqi->fq_dnode, fqi->fq_last_comp);
if (rc != 0)
return (rc);
if (smb_is_invalid_filename(fqi->fq_last_comp)) {
smb_node_release(fqi->fq_dnode);
return (EILSEQ);
}
rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode);
if (rc == 0) {
smb_node_release(fqi->fq_dnode);
smb_node_release(fqi->fq_fnode);
return (EEXIST);
}
if (rc != ENOENT) {
smb_node_release(fqi->fq_dnode);
return (rc);
}
rc = smb_fsop_access(sr, sr->user_cr, fqi->fq_dnode,
FILE_ADD_SUBDIRECTORY);
if (rc != NT_STATUS_SUCCESS) {
smb_node_release(fqi->fq_dnode);
return (EACCES);
}
bzero(&new_attr, sizeof (new_attr));
new_attr.sa_dosattr = FILE_ATTRIBUTE_DIRECTORY;
new_attr.sa_vattr.va_type = VDIR;
new_attr.sa_vattr.va_mode = 0777;
new_attr.sa_mask = SMB_AT_TYPE | SMB_AT_MODE | SMB_AT_DOSATTR;
rc = smb_fsop_mkdir(sr, sr->user_cr, fqi->fq_dnode, fqi->fq_last_comp,
&new_attr, &fqi->fq_fnode);
if (rc != 0) {
smb_node_release(fqi->fq_dnode);
return (rc);
}
sr->arg.open.create_options = FILE_DIRECTORY_FILE;
smb_node_release(fqi->fq_dnode);
smb_node_release(fqi->fq_fnode);
return (0);
}
smb_sdrc_t
smb_pre_delete_directory(smb_request_t *sr)
{
int rc;
rc = smbsr_decode_data(sr, "%S", sr,
&sr->arg.dirop.fqi.fq_path.pn_path);
DTRACE_SMB_START(op__DeleteDirectory, smb_request_t *, sr);
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
void
smb_post_delete_directory(smb_request_t *sr)
{
DTRACE_SMB_DONE(op__DeleteDirectory, smb_request_t *, sr);
}
smb_sdrc_t
smb_com_delete_directory(smb_request_t *sr)
{
int rc;
uint32_t flags = 0;
smb_fqi_t *fqi;
smb_node_t *tnode;
if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
ERRDOS, ERROR_ACCESS_DENIED);
return (SDRC_ERROR);
}
fqi = &sr->arg.dirop.fqi;
tnode = sr->tid_tree->t_snode;
smb_pathname_init(sr, &fqi->fq_path, fqi->fq_path.pn_path);
if (!smb_pathname_validate(sr, &fqi->fq_path) ||
!smb_validate_dirname(sr, &fqi->fq_path)) {
return (SDRC_ERROR);
}
rc = smb_pathname_reduce(sr, sr->user_cr, fqi->fq_path.pn_path,
tnode, tnode, &fqi->fq_dnode, fqi->fq_last_comp);
if (rc != 0) {
smbsr_errno(sr, rc);
return (SDRC_ERROR);
}
rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode);
if (rc != 0) {
smbsr_errno(sr, rc);
smb_node_release(fqi->fq_dnode);
return (SDRC_ERROR);
}
if ((fqi->fq_fnode == tnode) || smb_node_is_dfslink(fqi->fq_fnode)) {
smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
ERRDOS, ERROR_ACCESS_DENIED);
smb_node_release(fqi->fq_dnode);
smb_node_release(fqi->fq_fnode);
return (SDRC_ERROR);
}
if (!smb_node_is_dir(fqi->fq_fnode)) {
smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
ERRDOS, ERROR_PATH_NOT_FOUND);
smb_node_release(fqi->fq_dnode);
smb_node_release(fqi->fq_fnode);
return (SDRC_ERROR);
}
fqi->fq_fattr.sa_mask = SMB_AT_DOSATTR;
rc = smb_node_getattr(sr, fqi->fq_fnode, zone_kcred(), NULL,
&fqi->fq_fattr);
if (rc != 0) {
smbsr_errno(sr, rc);
smb_node_release(fqi->fq_dnode);
smb_node_release(fqi->fq_fnode);
return (SDRC_ERROR);
}
if ((fqi->fq_fattr.sa_dosattr & FILE_ATTRIBUTE_READONLY) ||
(smb_fsop_access(sr, sr->user_cr, fqi->fq_fnode, DELETE)
!= NT_STATUS_SUCCESS)) {
smbsr_error(sr, NT_STATUS_CANNOT_DELETE,
ERRDOS, ERROR_ACCESS_DENIED);
smb_node_release(fqi->fq_dnode);
smb_node_release(fqi->fq_fnode);
return (SDRC_ERROR);
}
if (SMB_TREE_SUPPORTS_CATIA(sr))
flags |= SMB_CATIA;
rc = smb_fsop_rmdir(sr, sr->user_cr, fqi->fq_dnode,
fqi->fq_fnode->od_name, flags);
smb_node_release(fqi->fq_fnode);
smb_node_release(fqi->fq_dnode);
if (rc != 0) {
if (rc == EEXIST)
smbsr_error(sr, NT_STATUS_DIRECTORY_NOT_EMPTY,
ERRDOS, ERROR_DIR_NOT_EMPTY);
else
smbsr_errno(sr, rc);
return (SDRC_ERROR);
}
rc = smbsr_encode_empty_result(sr);
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
smb_sdrc_t
smb_pre_check_directory(smb_request_t *sr)
{
int rc;
rc = smbsr_decode_data(sr, "%S", sr,
&sr->arg.dirop.fqi.fq_path.pn_path);
DTRACE_SMB_START(op__CheckDirectory, smb_request_t *, sr);
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
void
smb_post_check_directory(smb_request_t *sr)
{
DTRACE_SMB_DONE(op__CheckDirectory, smb_request_t *, sr);
}
smb_sdrc_t
smb_com_check_directory(smb_request_t *sr)
{
int rc;
smb_fqi_t *fqi;
smb_node_t *tnode;
smb_node_t *node;
char *path;
smb_pathname_t *pn;
if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
ERROR_ACCESS_DENIED);
return (SDRC_ERROR);
}
fqi = &sr->arg.dirop.fqi;
pn = &fqi->fq_path;
if (pn->pn_path[0] == '\0') {
rc = smbsr_encode_empty_result(sr);
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
smb_pathname_init(sr, pn, pn->pn_path);
if (!smb_pathname_validate(sr, pn) ||
!smb_validate_dirname(sr, pn)) {
return (SDRC_ERROR);
}
path = pn->pn_path;
tnode = sr->tid_tree->t_snode;
rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
&fqi->fq_dnode, fqi->fq_last_comp);
if (rc != 0) {
smbsr_errno(sr, rc);
return (SDRC_ERROR);
}
rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode);
smb_node_release(fqi->fq_dnode);
if (rc != 0) {
smbsr_errno(sr, rc);
return (SDRC_ERROR);
}
node = fqi->fq_fnode;
if (!smb_node_is_dir(node)) {
smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
ERRDOS, ERROR_PATH_NOT_FOUND);
smb_node_release(node);
return (SDRC_ERROR);
}
if ((sr->smb_flg2 & SMB_FLAGS2_DFS) && smb_node_is_dfslink(node)) {
smbsr_error(sr, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
smb_node_release(node);
return (SDRC_ERROR);
}
rc = smb_fsop_access(sr, sr->user_cr, node, FILE_TRAVERSE);
smb_node_release(node);
if (rc != 0) {
smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
ERRDOS, ERROR_ACCESS_DENIED);
return (SDRC_ERROR);
}
rc = smbsr_encode_empty_result(sr);
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}