/* * smb_query_by_fid * * Common code for querying file information by open file (or pipe) id. * Use the id to identify the node / pipe object and request the * smb_queryinfo_t data for that object. */ static int smb_query_by_fid(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev) { int rc; smb_queryinfo_t *qinfo; smb_node_t *node; smb_opipe_t *opipe; smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); return (-1); } if (infolev == SMB_INFO_IS_NAME_VALID) { smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_LEVEL); smbsr_release_file(sr); return (-1); } if ((sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE) && (!smb_query_pipe_valid_infolev(sr, infolev))) { smbsr_release_file(sr); return (-1); } sr->user_cr = smb_ofile_getcred(sr->fid_ofile); qinfo = kmem_alloc(sizeof (smb_queryinfo_t), KM_SLEEP); switch (sr->fid_ofile->f_ftype) { case SMB_FTYPE_DISK: node = sr->fid_ofile->f_node; rc = smb_query_fileinfo(sr, node, infolev, qinfo); break; case SMB_FTYPE_MESG_PIPE: opipe = sr->fid_ofile->f_pipe; rc = smb_query_pipeinfo(sr, opipe, infolev, qinfo); break; default: smbsr_error(sr, 0, ERRDOS, ERRbadfile); rc = -1; break; } if (rc == 0) rc = smb_query_encode_response(sr, xa, infolev, qinfo); kmem_free(qinfo, sizeof (smb_queryinfo_t)); smbsr_release_file(sr); return (rc); }
/* * 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_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. * * 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, char *path) { smb_queryinfo_t *qinfo; smb_node_t *node, *dnode; int rc; int len; /* VALID, but not yet supported */ if (infolev == SMB_FILE_ACCESS_INFORMATION) { smbsr_error(sr, 0, ERRDOS, ERRunknownlevel); return (-1); } /* * Some MS clients pass NULL file names. NT interprets this as "\". * Otherwise, if path is not "\\", remove the terminating slash. */ if ((len = strlen(path)) == 0) path = "\\"; else { if ((len > 1) && (path[len - 1] == '\\')) { path[len - 1] = 0; } } qinfo = kmem_alloc(sizeof (smb_queryinfo_t), KM_SLEEP); rc = smb_pathname_reduce(sr, sr->user_cr, 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); } 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); }