#include <sys/types.h>
#include <sys/errno.h>
#include <sys/cred.h>
#include <sys/cmn_err.h>
#include <sys/kmem.h>
#include <sys/sunddi.h>
#include <sys/acl.h>
#include <sys/vnode.h>
#include <sys/vfs.h>
#include <sys/byteorder.h>
#include <errno.h>
#include <stdio.h>
#include <strings.h>
#include <unistd.h>
#include <umem.h>
#include <idmap.h>
#include <sys/fs/smbfs_ioctl.h>
#include <netsmb/smb.h>
#include <netsmb/smb_lib.h>
#include <netsmb/smbfs_acl.h>
#include "smbfs_ntacl.h"
#include "private.h"
#define MAX_RAW_SD_SIZE 32768
acl_t *acl_alloc(enum acl_type);
void acl_free(acl_t *);
int
smbfs_acl_iocget(int fd, uint32_t selector, mbdata_t *mbp)
{
ioc_sdbuf_t iocb;
struct mbuf *m;
int error;
error = mb_init_sz(mbp, MAX_RAW_SD_SIZE);
if (error)
return (error);
m = mbp->mb_top;
bzero(&iocb, sizeof (iocb));
iocb.addr = mtod(m, uintptr_t);
iocb.alloc = m->m_maxlen;
iocb.used = 0;
iocb.selector = selector;
if (nsmb_ioctl(fd, SMBFSIO_GETSD, &iocb) < 0) {
error = errno;
goto errout;
}
m->m_len = iocb.used;
return (0);
errout:
mb_done(mbp);
return (error);
}
int
smbfs_acl_iocset(int fd, uint32_t selector, mbdata_t *mbp)
{
ioc_sdbuf_t iocb;
struct mbuf *m;
int error;
error = m_lineup(mbp->mb_top, &m);
if (error)
return (error);
if (mbp->mb_top != m)
mb_initm(mbp, m);
bzero(&iocb, sizeof (iocb));
iocb.addr = mtod(m, uintptr_t);
iocb.alloc = m->m_maxlen;
iocb.used = m->m_len;
iocb.selector = selector;
if (nsmb_ioctl(fd, SMBFSIO_SETSD, &iocb) < 0)
error = errno;
return (error);
}
int
smbfs_acl_getsd(int fd, uint32_t selector, i_ntsd_t **sdp)
{
mbdata_t *mbp, mb_store;
int error;
mbp = &mb_store;
bzero(mbp, sizeof (*mbp));
error = smbfs_acl_iocget(fd, selector, mbp);
if (error == 0) {
error = md_get_ntsd(mbp, sdp);
}
mb_done(mbp);
return (error);
}
int
smbfs_acl_setsd(int fd, uint32_t selector, i_ntsd_t *sd)
{
mbdata_t *mbp, mb_store;
int error;
mbp = &mb_store;
error = mb_init_sz(mbp, MAX_RAW_SD_SIZE);
if (error)
return (error);
error = mb_put_ntsd(mbp, sd);
if (error == 0) {
error = smbfs_acl_iocset(fd, selector, mbp);
}
mb_done(mbp);
return (error);
}
int
smbfs_acl_get(int fd, acl_t **aclp, uid_t *uidp, gid_t *gidp)
{
i_ntsd_t *sd = NULL;
acl_t *acl = NULL;
uint32_t selector;
int error;
selector = 0;
if (aclp)
selector |= DACL_SECURITY_INFORMATION;
if (uidp)
selector |= OWNER_SECURITY_INFORMATION;
if (gidp)
selector |= GROUP_SECURITY_INFORMATION;
if (selector == 0)
return (0);
error = smbfs_acl_getsd(fd, selector, &sd);
if (error)
return (error);
if (aclp) {
acl = acl_alloc(ACE_T);
if (acl == NULL) {
error = ENOMEM;
goto out;
}
}
error = smbfs_acl_sd2zfs(sd, acl, uidp, gidp);
if (error)
goto out;
if (aclp) {
*aclp = acl;
acl = NULL;
}
out:
if (acl)
acl_free(acl);
smbfs_acl_free_sd(sd);
return (error);
}
int
smbfs_acl_set(int fd, acl_t *acl, uid_t uid, gid_t gid)
{
struct stat st;
i_ntsd_t *sd = NULL;
uint32_t selector;
int error;
if (acl && acl->acl_type != ACE_T)
return (EINVAL);
selector = 0;
if (acl)
selector |= DACL_SECURITY_INFORMATION;
if (uid != (uid_t)-1)
selector |= OWNER_SECURITY_INFORMATION;
if (gid != (gid_t)-1)
selector |= GROUP_SECURITY_INFORMATION;
if (selector == 0)
return (0);
if (uid == (uid_t)-1 || gid == (gid_t)-1) {
if (fstat(fd, &st) != 0)
return (errno);
if (uid == (uid_t)-1)
uid = st.st_uid;
if (gid == (gid_t)-1)
gid = st.st_gid;
}
error = smbfs_acl_zfs2sd(acl, uid, gid, selector, &sd);
if (error == 0)
error = smbfs_acl_setsd(fd, selector, sd);
smbfs_acl_free_sd(sd);
return (error);
}