#include <smbsrv/smb_kproto.h>
#define SMB_NAME83_BUFLEN 12
static void smb_name83(const char *, char *, size_t);
smb_sdrc_t
smb_pre_search(smb_request_t *sr)
{
DTRACE_SMB_START(op__Search, smb_request_t *, sr);
return (SDRC_SUCCESS);
}
void
smb_post_search(smb_request_t *sr)
{
DTRACE_SMB_DONE(op__Search, smb_request_t *, sr);
}
smb_sdrc_t
smb_com_search(smb_request_t *sr)
{
int rc;
uint16_t count, maxcount, index;
uint16_t sattr, odid;
uint16_t key_len;
uint32_t client_key;
char name[SMB_SHORTNAMELEN];
char name83[SMB_SHORTNAMELEN];
smb_pathname_t *pn;
unsigned char resume_char;
unsigned char type;
boolean_t find_first, to_upper;
smb_tree_t *tree;
smb_odir_t *od;
smb_fileinfo_t fileinfo;
smb_odir_resume_t odir_resume;
uint32_t status;
uint16_t eos;
to_upper = B_FALSE;
if ((sr->session->dialect <= LANMAN1_0) ||
((sr->smb_flg2 & SMB_FLAGS2_KNOWS_LONG_NAMES) == 0)) {
to_upper = B_TRUE;
}
sr->smb_flg2 &= ~SMB_FLAGS2_KNOWS_LONG_NAMES;
sr->smb_flg &= ~SMB_FLAGS_CASE_INSENSITIVE;
if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0)
return (SDRC_ERROR);
pn = &sr->arg.dirop.fqi.fq_path;
rc = smbsr_decode_data(sr, "%Abw", sr, &pn->pn_path, &type, &key_len);
if ((rc != 0) || (type != 0x05))
return (SDRC_ERROR);
smb_pathname_init(sr, pn, pn->pn_path);
if (!smb_pathname_validate(sr, pn) ||
smb_is_stream_name(pn->pn_path)) {
smbsr_warn(sr, NT_STATUS_NO_MORE_FILES,
ERRDOS, ERROR_NO_MORE_FILES);
return (SDRC_ERROR);
}
tree = sr->tid_tree;
if ((sattr == FILE_ATTRIBUTE_VOLUME) && (key_len != 21)) {
(void) memset(name, ' ', sizeof (name));
(void) strncpy(name, tree->t_volume, sizeof (name));
if (key_len >= 21) {
(void) smb_mbc_decodef(&sr->smb_data, "17.l",
&client_key);
} else {
client_key = 0;
}
(void) smb_mbc_encodef(&sr->reply, "bwwbwb11c5.lb8.13c",
1, 0, VAR_BCC, 5, 0, 0, pn->pn_path+1,
client_key, sattr, name);
rc = (sr->reply.chain_offset - sr->cur_reply_offset) - 8;
(void) smb_mbc_poke(&sr->reply, sr->cur_reply_offset, "bwwbw",
1, 1, rc+3, 5, rc);
return (SDRC_SUCCESS);
}
if ((key_len != 0) && (key_len != 21))
return (SDRC_ERROR);
find_first = (key_len == 0);
resume_char = 0;
client_key = 0;
if (find_first) {
status = smb_odir_openpath(sr, pn->pn_path, sattr, 0, &od);
if (status != 0) {
if (status == NT_STATUS_ACCESS_DENIED)
smbsr_warn(sr, NT_STATUS_NO_MORE_FILES,
ERRDOS, ERROR_NO_MORE_FILES);
return (SDRC_ERROR);
}
odid = od->d_odid;
} else {
if (smb_mbc_decodef(&sr->smb_data, "b12.wwl",
&resume_char, &index, &odid, &client_key) != 0) {
return (SDRC_ERROR);
}
od = smb_tree_lookup_odir(sr, odid);
}
if (od == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
ERRDOS, ERROR_INVALID_HANDLE);
return (SDRC_ERROR);
}
if (!find_first) {
if ((od->d_flags & SMB_ODIR_FLAG_WILDCARDS) == 0) {
od->d_eof = B_TRUE;
} else {
odir_resume.or_type = SMB_ODIR_RESUME_IDX;
odir_resume.or_idx = index;
smb_odir_resume_at(od, &odir_resume);
}
}
(void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0);
rc = 0;
index = 0;
count = 0;
if (maxcount > SMB_MAX_SEARCH)
maxcount = SMB_MAX_SEARCH;
while (count < maxcount) {
rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &eos);
if (rc != 0 || eos != 0)
break;
if (*fileinfo.fi_shortname == '\0') {
if (smb_needs_mangled(fileinfo.fi_name))
continue;
(void) strlcpy(fileinfo.fi_shortname, fileinfo.fi_name,
SMB_SHORTNAMELEN - 1);
if (to_upper)
(void) smb_strupr(fileinfo.fi_shortname);
}
smb_name83(fileinfo.fi_shortname, name83, SMB_SHORTNAMELEN);
(void) smb_mbc_encodef(&sr->reply, "b11c.wwlbYl13c",
resume_char, name83, index, odid, client_key,
fileinfo.fi_dosattr & 0xff,
smb_time_gmt_to_local(sr, fileinfo.fi_mtime.tv_sec),
(int32_t)fileinfo.fi_size,
fileinfo.fi_shortname);
smb_odir_save_cookie(od, index, fileinfo.fi_cookie);
count++;
index++;
}
if (eos && rc == ENOENT)
rc = 0;
if (rc != 0) {
smb_odir_close(od);
smb_odir_release(od);
return (SDRC_ERROR);
}
if (count == 0 && find_first) {
smb_odir_close(od);
smb_odir_release(od);
smbsr_warn(sr, NT_STATUS_NO_MORE_FILES,
ERRDOS, ERROR_NO_MORE_FILES);
return (SDRC_ERROR);
}
rc = (sr->reply.chain_offset - sr->cur_reply_offset) - 8;
if (smb_mbc_poke(&sr->reply, sr->cur_reply_offset, "bwwbw",
1, count, rc+3, 5, rc) < 0) {
smb_odir_close(od);
smb_odir_release(od);
return (SDRC_ERROR);
}
smb_odir_release(od);
return (SDRC_SUCCESS);
}
smb_sdrc_t
smb_pre_find(smb_request_t *sr)
{
DTRACE_SMB_START(op__Find, smb_request_t *, sr);
return (SDRC_SUCCESS);
}
void
smb_post_find(smb_request_t *sr)
{
DTRACE_SMB_DONE(op__Find, smb_request_t *, sr);
}
smb_sdrc_t
smb_com_find(smb_request_t *sr)
{
int rc;
uint16_t count, maxcount, index;
uint16_t sattr, odid;
uint16_t key_len;
uint32_t client_key;
char name83[SMB_SHORTNAMELEN];
smb_odir_t *od;
smb_fileinfo_t fileinfo;
uint32_t status;
uint16_t eos;
smb_pathname_t *pn;
unsigned char resume_char;
unsigned char type;
boolean_t find_first = B_TRUE;
smb_odir_resume_t odir_resume;
if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0)
return (SDRC_ERROR);
pn = &sr->arg.dirop.fqi.fq_path;
rc = smbsr_decode_data(sr, "%Abw", sr, &pn->pn_path, &type, &key_len);
if ((rc != 0) || (type != 0x05))
return (SDRC_ERROR);
if ((key_len != 0) && (key_len != 21))
return (SDRC_ERROR);
smb_pathname_init(sr, pn, pn->pn_path);
if (!smb_pathname_validate(sr, pn))
return (SDRC_ERROR);
if (smb_is_stream_name(pn->pn_path)) {
smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
ERRDOS, ERROR_INVALID_NAME);
return (SDRC_ERROR);
}
find_first = (key_len == 0);
resume_char = 0;
client_key = 0;
if (find_first) {
status = smb_odir_openpath(sr, pn->pn_path, sattr, 0, &od);
if (status != 0) {
smbsr_error(sr, status, 0, 0);
return (SDRC_ERROR);
}
odid = od->d_odid;
} else {
if (smb_mbc_decodef(&sr->smb_data, "b12.wwl",
&resume_char, &index, &odid, &client_key) != 0) {
return (SDRC_ERROR);
}
od = smb_tree_lookup_odir(sr, odid);
}
if (od == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
ERRDOS, ERROR_INVALID_HANDLE);
return (SDRC_ERROR);
}
if (!find_first) {
if ((od->d_flags & SMB_ODIR_FLAG_WILDCARDS) == 0) {
od->d_eof = B_TRUE;
} else {
odir_resume.or_type = SMB_ODIR_RESUME_IDX;
odir_resume.or_idx = index;
smb_odir_resume_at(od, &odir_resume);
}
}
(void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0);
rc = 0;
index = 0;
count = 0;
if (maxcount > SMB_MAX_SEARCH)
maxcount = SMB_MAX_SEARCH;
while (count < maxcount) {
rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &eos);
if (rc != 0 || eos != 0)
break;
if (*fileinfo.fi_shortname == '\0') {
if (smb_needs_mangled(fileinfo.fi_name))
continue;
(void) strlcpy(fileinfo.fi_shortname, fileinfo.fi_name,
SMB_SHORTNAMELEN - 1);
}
smb_name83(fileinfo.fi_shortname, name83, SMB_SHORTNAMELEN);
(void) smb_mbc_encodef(&sr->reply, "b11c.wwlbYl13c",
resume_char, name83, index, odid, client_key,
fileinfo.fi_dosattr & 0xff,
smb_time_gmt_to_local(sr, fileinfo.fi_mtime.tv_sec),
(int32_t)fileinfo.fi_size,
fileinfo.fi_shortname);
smb_odir_save_cookie(od, index, fileinfo.fi_cookie);
count++;
index++;
}
if (eos && rc == ENOENT)
rc = 0;
if (rc != 0) {
smb_odir_close(od);
smb_odir_release(od);
return (SDRC_ERROR);
}
if (count == 0 && find_first) {
smb_odir_close(od);
smb_odir_release(od);
smbsr_warn(sr, NT_STATUS_NO_MORE_FILES,
ERRDOS, ERROR_NO_MORE_FILES);
return (SDRC_ERROR);
}
rc = (MBC_LENGTH(&sr->reply) - sr->cur_reply_offset) - 8;
if (smb_mbc_poke(&sr->reply, sr->cur_reply_offset, "bwwbw",
1, count, rc+3, 5, rc) < 0) {
smb_odir_close(od);
smb_odir_release(od);
return (SDRC_ERROR);
}
smb_odir_release(od);
return (SDRC_SUCCESS);
}
smb_sdrc_t
smb_pre_find_close(smb_request_t *sr)
{
DTRACE_SMB_START(op__FindClose, smb_request_t *, sr);
return (SDRC_SUCCESS);
}
void
smb_post_find_close(smb_request_t *sr)
{
DTRACE_SMB_DONE(op__FindClose, smb_request_t *, sr);
}
smb_sdrc_t
smb_com_find_close(smb_request_t *sr)
{
int rc;
uint16_t maxcount, index;
uint16_t sattr, odid;
uint16_t key_len;
uint32_t client_key;
char *path;
unsigned char resume_char;
unsigned char type;
smb_odir_t *od;
if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0)
return (SDRC_ERROR);
rc = smbsr_decode_data(sr, "%Abw", sr, &path, &type, &key_len);
if ((rc != 0) || (type != 0x05))
return (SDRC_ERROR);
if (key_len == 0) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
ERRDOS, ERROR_INVALID_HANDLE);
return (SDRC_ERROR);
} else if (key_len != 21) {
return (SDRC_ERROR);
}
odid = 0;
if (smb_mbc_decodef(&sr->smb_data, "b12.wwl",
&resume_char, &index, &odid, &client_key) != 0) {
return (SDRC_ERROR);
}
od = smb_tree_lookup_odir(sr, odid);
if (od == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
ERRDOS, ERROR_INVALID_HANDLE);
return (SDRC_ERROR);
}
smb_odir_close(od);
smb_odir_release(od);
if (smbsr_encode_result(sr, 1, 3, "bwwbw", 1, 0, 3, 5, 0))
return (SDRC_ERROR);
return (SDRC_SUCCESS);
}
smb_sdrc_t
smb_pre_find_unique(smb_request_t *sr)
{
DTRACE_SMB_START(op__FindUnique, smb_request_t *, sr);
return (SDRC_SUCCESS);
}
void
smb_post_find_unique(smb_request_t *sr)
{
DTRACE_SMB_DONE(op__FindUnique, smb_request_t *, sr);
}
smb_sdrc_t
smb_com_find_unique(struct smb_request *sr)
{
int rc;
uint16_t count, maxcount, index;
uint16_t sattr;
smb_pathname_t *pn;
unsigned char resume_char = '\0';
uint32_t client_key = 0;
char name83[SMB_SHORTNAMELEN];
smb_odir_t *od;
smb_fileinfo_t fileinfo;
uint32_t status;
uint16_t eos;
smb_vdb_t *vdb;
if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0)
return (SDRC_ERROR);
pn = &sr->arg.dirop.fqi.fq_path;
vdb = kmem_alloc(sizeof (smb_vdb_t), KM_SLEEP);
if ((smbsr_decode_data(sr, "%AV", sr, &pn->pn_path, vdb) != 0) ||
(vdb->vdb_len != 0)) {
kmem_free(vdb, sizeof (smb_vdb_t));
return (SDRC_ERROR);
}
kmem_free(vdb, sizeof (smb_vdb_t));
smb_pathname_init(sr, pn, pn->pn_path);
if (!smb_pathname_validate(sr, pn))
return (SDRC_ERROR);
if (smb_is_stream_name(pn->pn_path)) {
smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
ERRDOS, ERROR_INVALID_NAME);
return (SDRC_ERROR);
}
(void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0);
status = smb_odir_openpath(sr, pn->pn_path, sattr, 0, &od);
if (status != 0) {
smbsr_error(sr, status, 0, 0);
return (SDRC_ERROR);
}
if (od == NULL)
return (SDRC_ERROR);
rc = 0;
count = 0;
index = 0;
if (maxcount > SMB_MAX_SEARCH)
maxcount = SMB_MAX_SEARCH;
while (count < maxcount) {
rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &eos);
if (rc != 0 || eos != 0)
break;
if (*fileinfo.fi_shortname == '\0') {
if (smb_needs_mangled(fileinfo.fi_name))
continue;
(void) strlcpy(fileinfo.fi_shortname, fileinfo.fi_name,
SMB_SHORTNAMELEN - 1);
}
smb_name83(fileinfo.fi_shortname, name83, SMB_SHORTNAMELEN);
(void) smb_mbc_encodef(&sr->reply, "b11c.wwlbYl13c",
resume_char, name83, index, od->d_odid, client_key,
fileinfo.fi_dosattr & 0xff,
smb_time_gmt_to_local(sr, fileinfo.fi_mtime.tv_sec),
(int32_t)fileinfo.fi_size,
fileinfo.fi_shortname);
count++;
index++;
}
if (eos && rc == ENOENT)
rc = 0;
smb_odir_close(od);
smb_odir_release(od);
if (rc != 0)
return (SDRC_ERROR);
if (count == 0) {
smbsr_warn(sr, NT_STATUS_NO_MORE_FILES,
ERRDOS, ERROR_NO_MORE_FILES);
return (SDRC_ERROR);
}
rc = (MBC_LENGTH(&sr->reply) - sr->cur_reply_offset) - 8;
if (smb_mbc_poke(&sr->reply, sr->cur_reply_offset,
"bwwbw", 1, count, rc+3, 5, rc) < 0) {
return (SDRC_ERROR);
}
return (SDRC_SUCCESS);
}
static void
smb_name83(const char *name, char *buf, size_t buflen)
{
const char *p;
char *pbuf;
int i;
ASSERT(name && buf && (buflen >= SMB_NAME83_BUFLEN));
(void) strlcpy(buf, " ", SMB_NAME83_BUFLEN);
if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0)) {
(void) strncpy(buf, name, strlen(name));
return;
}
ASSERT(smb_needs_mangled(name) == B_FALSE);
for (i = 0, p = name, pbuf = buf;
(i < SMB_NAME83_BASELEN) && (*p != '\0') && (*p != '.'); ++i)
*pbuf++ = *p++;
if ((p = strchr(name, '.')) != NULL) {
++p;
pbuf = &buf[SMB_NAME83_BASELEN];
for (i = 0; (i < SMB_NAME83_EXTLEN) && (*p != '\0'); ++i)
*pbuf++ = *p++;
}
(void) smb_strupr(buf);
}