#include <smbsrv/smb2_kproto.h>
#include <smbsrv/smb2_aapl.h>
#include <smbsrv/smb_fsops.h>
int smb2_aapl_extensions = 1;
uint64_t smb2_aapl_server_caps =
kAAPL_SUPPORTS_READ_DIR_ATTR;
uint64_t smb2_aapl_volume_caps = kAAPL_SUPPORTS_FULL_SYNC;
int smb2_aapl_use_file_ids = 0;
static uint32_t smb2_aapl_srv_query(smb_request_t *,
mbuf_chain_t *, mbuf_chain_t *);
static int smb_aapl_ext_maxlen = 512;
uint32_t
smb2_aapl_crctx(smb_request_t *sr,
mbuf_chain_t *mbcin,
mbuf_chain_t *mbcout)
{
uint32_t cmdcode;
uint32_t status;
int rc;
if (smb2_aapl_extensions == 0)
return (NT_STATUS_NOT_SUPPORTED);
rc = smb_mbc_decodef(mbcin, "l4.", &cmdcode);
if (rc != 0)
return (NT_STATUS_INFO_LENGTH_MISMATCH);
mbcout->max_bytes = smb_aapl_ext_maxlen;
(void) smb_mbc_encodef(mbcout, "ll", cmdcode, 0);
switch (cmdcode) {
case kAAPL_SERVER_QUERY:
status = smb2_aapl_srv_query(sr, mbcin, mbcout);
break;
case kAAPL_RESOLVE_ID:
default:
status = NT_STATUS_INVALID_INFO_CLASS;
break;
}
return (status);
}
static uint32_t
smb2_aapl_srv_query(smb_request_t *sr,
mbuf_chain_t *mbcin, mbuf_chain_t *mbcout)
{
uint64_t client_bitmap;
uint64_t client_caps;
uint64_t server_bitmap;
int rc;
rc = smb_mbc_decodef(
mbcin, "qq",
&client_bitmap,
&client_caps);
if (rc != 0)
return (NT_STATUS_INFO_LENGTH_MISMATCH);
smb_rwx_rwenter(&sr->session->s_lock, RW_WRITER);
sr->session->native_os = NATIVE_OS_MACOS;
sr->session->s_flags |= SMB_SSN_AAPL_CCEXT;
server_bitmap = client_bitmap &
(kAAPL_SERVER_CAPS | kAAPL_VOLUME_CAPS);
(void) smb_mbc_encodef(mbcout, "q", server_bitmap);
if ((server_bitmap & kAAPL_SERVER_CAPS) != 0) {
uint64_t server_caps =
smb2_aapl_server_caps & client_caps;
if (server_caps & kAAPL_SUPPORTS_READ_DIR_ATTR)
sr->session->s_flags |= SMB_SSN_AAPL_READDIR;
(void) smb_mbc_encodef(mbcout, "q", server_caps);
}
if ((server_bitmap & kAAPL_VOLUME_CAPS) != 0) {
(void) smb_mbc_encodef(mbcout, "q", smb2_aapl_volume_caps);
}
(void) smb_mbc_encodef(mbcout, "ll", 0, 0);
smb_rwx_rwexit(&sr->session->s_lock);
return (0);
}
int
smb2_aapl_get_macinfo(smb_request_t *sr, smb_odir_t *od,
smb_fileinfo_t *fileinfo, smb_macinfo_t *mi,
char *tbuf, size_t tbuflen)
{
int rc;
cred_t *kcr = zone_kcred();
smb_node_t *fnode, *snode;
smb_attr_t attr;
uint32_t AfpInfo[15];
bzero(mi, sizeof (*mi));
rc = smb_fsop_lookup(sr, od->d_cred, SMB_CASE_SENSITIVE,
od->d_tree->t_snode, od->d_dnode, fileinfo->fi_name, &fnode);
if (rc != 0)
return (rc);
smb_fsop_eaccess(sr, od->d_cred, fnode, &mi->mi_maxaccess);
(void) snprintf(tbuf, tbuflen, "%s:AFP_Resource", fileinfo->fi_name);
rc = smb_fsop_lookup_name(sr, kcr, 0, sr->tid_tree->t_snode,
od->d_dnode, tbuf, &snode);
if (rc == 0) {
bzero(&attr, sizeof (attr));
attr.sa_mask = SMB_AT_SIZE | SMB_AT_ALLOCSZ;
rc = smb_node_getattr(NULL, snode, kcr, NULL, &attr);
if (rc == 0) {
mi->mi_rforksize = attr.sa_vattr.va_size;
}
smb_node_release(snode);
snode = NULL;
}
(void) snprintf(tbuf, tbuflen, "%s:AFP_AfpInfo", fileinfo->fi_name);
rc = smb_fsop_lookup_name(sr, kcr, 0, sr->tid_tree->t_snode,
od->d_dnode, tbuf, &snode);
if (rc == 0) {
iovec_t iov;
uio_t uio;
bzero(&AfpInfo, sizeof (AfpInfo));
bzero(&uio, sizeof (uio));
iov.iov_base = (void *) &AfpInfo;
iov.iov_len = sizeof (AfpInfo);
uio.uio_iov = &iov;
uio.uio_iovcnt = 1;
uio.uio_resid = sizeof (AfpInfo);
uio.uio_segflg = UIO_SYSSPACE;
uio.uio_extflg = UIO_COPY_DEFAULT;
rc = smb_fsop_read(sr, kcr, snode, NULL, &uio, 0);
if (rc == 0 && uio.uio_resid == 0) {
bcopy(&AfpInfo[4], &mi->mi_finderinfo,
sizeof (mi->mi_finderinfo));
}
smb_node_release(snode);
snode = NULL;
}
if (smb2_aapl_server_caps & kAAPL_UNIX_BASED) {
bzero(&attr, sizeof (attr));
attr.sa_mask = SMB_AT_MODE;
rc = smb_node_getattr(NULL, fnode, kcr, NULL, &attr);
if (rc == 0) {
mi->mi_unixmode = (uint16_t)attr.sa_vattr.va_mode;
}
}
smb_node_release(fnode);
return (0);
}