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) { if (rc == ENOENT) smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, ERRDOS, ERROR_PATH_NOT_FOUND); else 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); }
/* * smb_query_by_path * * Common code for querying file information by file name. * Use the file name to identify the node object and request the * smb_queryinfo_t data for that node. * * Path should be set in sr->arg.dirop.fqi.fq_path prior to * calling smb_query_by_path. * * Querying attributes on a named pipe by name is an error and * is handled in the calling functions so that they can return * the appropriate error status code (which differs by caller). */ static int smb_query_by_path(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev) { smb_queryinfo_t *qinfo; smb_node_t *node, *dnode; smb_pathname_t *pn; int rc; /* * The function smb_query_fileinfo is used here and in * smb_query_by_fid. That common function needs this * one to call it with a NULL fid_ofile, so check here. * Note: smb_query_by_fid enforces the opposite. * * In theory we could ASSERT this, but whether we have * fid_ofile set here depends on what sequence of SMB * commands the client has sent in this message, so * let's be cautious and handle it as an error. */ if (sr->fid_ofile != NULL) return (-1); /* VALID, but not yet supported */ if (infolev == SMB_FILE_ACCESS_INFORMATION) { smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_LEVEL); return (-1); } pn = &sr->arg.dirop.fqi.fq_path; smb_pathname_init(sr, pn, pn->pn_path); if (!smb_pathname_validate(sr, pn)) return (-1); qinfo = kmem_alloc(sizeof (smb_queryinfo_t), KM_SLEEP); rc = smb_pathname_reduce(sr, sr->user_cr, pn->pn_path, sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dnode, qinfo->qi_name); if (rc == 0) { rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS, sr->tid_tree->t_snode, dnode, qinfo->qi_name, &node); smb_node_release(dnode); } if (rc != 0) { if (rc == ENOENT) smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, ERRDOS, ERROR_FILE_NOT_FOUND); else smbsr_errno(sr, rc); kmem_free(qinfo, sizeof (smb_queryinfo_t)); return (-1); } if ((sr->smb_flg2 & SMB_FLAGS2_DFS) && smb_node_is_dfslink(node)) { smbsr_error(sr, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath); kmem_free(qinfo, sizeof (smb_queryinfo_t)); smb_node_release(node); return (-1); } rc = smb_query_fileinfo(sr, node, infolev, qinfo); if (rc != 0) { kmem_free(qinfo, sizeof (smb_queryinfo_t)); smb_node_release(node); return (rc); } /* If delete_on_close - NT_STATUS_DELETE_PENDING */ if (qinfo->qi_delete_on_close) { smbsr_error(sr, NT_STATUS_DELETE_PENDING, ERRDOS, ERROR_ACCESS_DENIED); kmem_free(qinfo, sizeof (smb_queryinfo_t)); smb_node_release(node); return (-1); } rc = smb_query_encode_response(sr, xa, infolev, qinfo); kmem_free(qinfo, sizeof (smb_queryinfo_t)); smb_node_release(node); return (rc); }
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) { if (rc == ENOENT) smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, ERRDOS, ERROR_FILE_NOT_FOUND); else smbsr_errno(sr, rc); smb_node_release(fqi->fq_dnode); return (SDRC_ERROR); } /* * Delete should fail if this is the root of a share * or a DFS link */ 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); } /* * Using kcred because we just want the DOS attrs * and don't want access errors for this. */ 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); }