mirror of
https://github.com/samba-team/samba.git
synced 2025-01-13 13:18:06 +03:00
4b21ad9db7
This change brings ntvfs_connect into compliance with other ntvfs functions which take an ntvfs module, an ntvfs request and an smb io union. It now becomes the responsibility of ntvfs modules to examine tcon->generic.level themselves and derive the share name and any other options directly; e.g. const char *sharename; switch (tcon->generic.level) { case RAW_TCON_TCON: sharename = tcon->tcon.in.service; break; case RAW_TCON_TCONX: sharename = tcon->tconx.in.path; break; case RAW_TCON_SMB2: default: return NT_STATUS_INVALID_LEVEL; } if (strncmp(sharename, "\\\\", 2) == 0) { char *p = strchr(sharename+2, '\\'); if (p) { sharename = p + 1; } } service.c smbsrv_tcon_backend() is called before ntvfs_connect and fills in some of the tcon->..out values. For the case of RAW_TCON_TCONX, it filles out tcon->tconx.out.tid and tcon->tconx.out.options For the case of RAW_TCON_TCON it fills out tcon->tcon.out.tid and tcon->tcon.out.max_xmit Thus the ntvfs_connect function for vfs modules may override these values if desired, but are not required to. ntvfs_connect functions are required to fill in the tcon->tconx.out.*_type fields, for RAW_TCON_TCONX, perhaps something like: if (tcon->generic.level == RAW_TCON_TCONX) { tcon->tconx.out.fs_type = ntvfs->ctx->fs_type; tcon->tconx.out.dev_type = ntvfs->ctx->dev_type; } Signed-off-by: Sam Liddicott <sam@liddicott.com> (I fixed the ntvfs_connect() in the smb_server/smb2/ and the RAW_TCON_SMB2 switch case in the modules) Signed-off-by: Stefan Metzmacher <metze@samba.org>
794 lines
17 KiB
C
794 lines
17 KiB
C
/*
|
|
Unix SMB/CIFS implementation.
|
|
|
|
a pass-thru NTVFS module to setup a security context using unix
|
|
uid/gid
|
|
|
|
Copyright (C) Andrew Tridgell 2004
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "includes.h"
|
|
#include "system/filesys.h"
|
|
#include "system/passwd.h"
|
|
#include "auth/auth.h"
|
|
#include "ntvfs/ntvfs.h"
|
|
#include "libcli/wbclient/wbclient.h"
|
|
#define TEVENT_DEPRECATED
|
|
#include <tevent.h>
|
|
|
|
struct unixuid_private {
|
|
struct wbc_context *wbc_ctx;
|
|
struct unix_sec_ctx *last_sec_ctx;
|
|
struct security_token *last_token;
|
|
};
|
|
|
|
|
|
|
|
struct unix_sec_ctx {
|
|
uid_t uid;
|
|
gid_t gid;
|
|
uint_t ngroups;
|
|
gid_t *groups;
|
|
};
|
|
|
|
/*
|
|
pull the current security context into a unix_sec_ctx
|
|
*/
|
|
static struct unix_sec_ctx *save_unix_security(TALLOC_CTX *mem_ctx)
|
|
{
|
|
struct unix_sec_ctx *sec = talloc(mem_ctx, struct unix_sec_ctx);
|
|
if (sec == NULL) {
|
|
return NULL;
|
|
}
|
|
sec->uid = geteuid();
|
|
sec->gid = getegid();
|
|
sec->ngroups = getgroups(0, NULL);
|
|
if (sec->ngroups == -1) {
|
|
talloc_free(sec);
|
|
return NULL;
|
|
}
|
|
sec->groups = talloc_array(sec, gid_t, sec->ngroups);
|
|
if (sec->groups == NULL) {
|
|
talloc_free(sec);
|
|
return NULL;
|
|
}
|
|
|
|
if (getgroups(sec->ngroups, sec->groups) != sec->ngroups) {
|
|
talloc_free(sec);
|
|
return NULL;
|
|
}
|
|
|
|
return sec;
|
|
}
|
|
|
|
/*
|
|
set the current security context from a unix_sec_ctx
|
|
*/
|
|
static NTSTATUS set_unix_security(struct unix_sec_ctx *sec)
|
|
{
|
|
seteuid(0);
|
|
|
|
if (setgroups(sec->ngroups, sec->groups) != 0) {
|
|
return NT_STATUS_ACCESS_DENIED;
|
|
}
|
|
if (setegid(sec->gid) != 0) {
|
|
return NT_STATUS_ACCESS_DENIED;
|
|
}
|
|
if (seteuid(sec->uid) != 0) {
|
|
return NT_STATUS_ACCESS_DENIED;
|
|
}
|
|
return NT_STATUS_OK;
|
|
}
|
|
|
|
static int unixuid_nesting_level;
|
|
|
|
/*
|
|
called at the start and end of a tevent nesting loop. Needs to save/restore
|
|
unix security context
|
|
*/
|
|
static int unixuid_event_nesting_hook(struct tevent_context *ev,
|
|
void *private_data,
|
|
uint32_t level,
|
|
bool begin,
|
|
void *stack_ptr,
|
|
const char *location)
|
|
{
|
|
struct unix_sec_ctx *sec_ctx;
|
|
|
|
if (unixuid_nesting_level == 0) {
|
|
/* we don't need to do anything unless we are nested
|
|
inside of a call in this module */
|
|
return 0;
|
|
}
|
|
|
|
if (begin) {
|
|
sec_ctx = save_unix_security(ev);
|
|
if (sec_ctx == NULL) {
|
|
DEBUG(0,("%s: Failed to save security context\n", location));
|
|
return -1;
|
|
}
|
|
*(struct unix_sec_ctx **)stack_ptr = sec_ctx;
|
|
if (seteuid(0) != 0 || setegid(0) != 0) {
|
|
DEBUG(0,("%s: Failed to change to root\n", location));
|
|
return -1;
|
|
}
|
|
} else {
|
|
/* called when we come out of a nesting level */
|
|
NTSTATUS status;
|
|
|
|
sec_ctx = *(struct unix_sec_ctx **)stack_ptr;
|
|
if (sec_ctx == NULL) {
|
|
/* this happens the first time this function
|
|
is called, as we install the hook while
|
|
inside an event in unixuid_connect() */
|
|
return 0;
|
|
}
|
|
|
|
sec_ctx = talloc_get_type_abort(sec_ctx, struct unix_sec_ctx);
|
|
status = set_unix_security(sec_ctx);
|
|
talloc_free(sec_ctx);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
DEBUG(0,("%s: Failed to revert security context (%s)\n",
|
|
location, nt_errstr(status)));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
form a unix_sec_ctx from the current security_token
|
|
*/
|
|
static NTSTATUS nt_token_to_unix_security(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req,
|
|
struct security_token *token,
|
|
struct unix_sec_ctx **sec)
|
|
{
|
|
struct unixuid_private *priv = ntvfs->private_data;
|
|
int i;
|
|
NTSTATUS status;
|
|
struct id_mapping *ids;
|
|
struct composite_context *ctx;
|
|
*sec = talloc(req, struct unix_sec_ctx);
|
|
|
|
/* we can't do unix security without a user and group */
|
|
if (token->num_sids < 2) {
|
|
return NT_STATUS_ACCESS_DENIED;
|
|
}
|
|
|
|
ids = talloc_array(req, struct id_mapping, token->num_sids);
|
|
NT_STATUS_HAVE_NO_MEMORY(ids);
|
|
|
|
ids[0].unixid = NULL;
|
|
ids[0].sid = token->user_sid;
|
|
ids[0].status = NT_STATUS_NONE_MAPPED;
|
|
|
|
ids[1].unixid = NULL;
|
|
ids[1].sid = token->group_sid;
|
|
ids[1].status = NT_STATUS_NONE_MAPPED;
|
|
|
|
(*sec)->ngroups = token->num_sids - 2;
|
|
(*sec)->groups = talloc_array(*sec, gid_t, (*sec)->ngroups);
|
|
NT_STATUS_HAVE_NO_MEMORY((*sec)->groups);
|
|
|
|
for (i=0;i<(*sec)->ngroups;i++) {
|
|
ids[i+2].unixid = NULL;
|
|
ids[i+2].sid = token->sids[i+2];
|
|
ids[i+2].status = NT_STATUS_NONE_MAPPED;
|
|
}
|
|
|
|
ctx = wbc_sids_to_xids_send(priv->wbc_ctx, ids, token->num_sids, ids);
|
|
NT_STATUS_HAVE_NO_MEMORY(ctx);
|
|
|
|
status = wbc_sids_to_xids_recv(ctx, &ids);
|
|
NT_STATUS_NOT_OK_RETURN(status);
|
|
|
|
if (ids[0].unixid->type == ID_TYPE_BOTH ||
|
|
ids[0].unixid->type == ID_TYPE_UID) {
|
|
(*sec)->uid = ids[0].unixid->id;
|
|
} else {
|
|
return NT_STATUS_INVALID_SID;
|
|
}
|
|
|
|
if (ids[1].unixid->type == ID_TYPE_BOTH ||
|
|
ids[1].unixid->type == ID_TYPE_GID) {
|
|
(*sec)->gid = ids[1].unixid->id;
|
|
} else {
|
|
return NT_STATUS_INVALID_SID;
|
|
}
|
|
|
|
for (i=0;i<(*sec)->ngroups;i++) {
|
|
if (ids[i+2].unixid->type == ID_TYPE_BOTH ||
|
|
ids[i+2].unixid->type == ID_TYPE_GID) {
|
|
(*sec)->groups[i] = ids[i+2].unixid->id;
|
|
} else {
|
|
return NT_STATUS_INVALID_SID;
|
|
}
|
|
}
|
|
|
|
return NT_STATUS_OK;
|
|
}
|
|
|
|
/*
|
|
setup our unix security context according to the session authentication info
|
|
*/
|
|
static NTSTATUS unixuid_setup_security(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req, struct unix_sec_ctx **sec)
|
|
{
|
|
struct unixuid_private *priv = ntvfs->private_data;
|
|
struct security_token *token;
|
|
struct unix_sec_ctx *newsec;
|
|
NTSTATUS status;
|
|
|
|
if (req->session_info == NULL) {
|
|
return NT_STATUS_ACCESS_DENIED;
|
|
}
|
|
|
|
token = req->session_info->security_token;
|
|
|
|
*sec = save_unix_security(ntvfs);
|
|
if (*sec == NULL) {
|
|
return NT_STATUS_NO_MEMORY;
|
|
}
|
|
|
|
if (token == priv->last_token) {
|
|
newsec = priv->last_sec_ctx;
|
|
} else {
|
|
status = nt_token_to_unix_security(ntvfs, req, token, &newsec);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
talloc_free(*sec);
|
|
return status;
|
|
}
|
|
if (priv->last_sec_ctx) {
|
|
talloc_free(priv->last_sec_ctx);
|
|
}
|
|
priv->last_sec_ctx = newsec;
|
|
priv->last_token = token;
|
|
talloc_steal(priv, newsec);
|
|
}
|
|
|
|
status = set_unix_security(newsec);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
talloc_free(*sec);
|
|
return status;
|
|
}
|
|
|
|
return NT_STATUS_OK;
|
|
}
|
|
|
|
/*
|
|
this pass through macro operates on request contexts
|
|
*/
|
|
#define PASS_THRU_REQ(ntvfs, req, op, args) do { \
|
|
NTSTATUS status2; \
|
|
struct unix_sec_ctx *sec; \
|
|
status = unixuid_setup_security(ntvfs, req, &sec); \
|
|
NT_STATUS_NOT_OK_RETURN(status); \
|
|
unixuid_nesting_level++; \
|
|
status = ntvfs_next_##op args; \
|
|
unixuid_nesting_level--; \
|
|
status2 = set_unix_security(sec); \
|
|
talloc_free(sec); \
|
|
if (!NT_STATUS_IS_OK(status2)) smb_panic("Unable to reset security context"); \
|
|
} while (0)
|
|
|
|
|
|
|
|
/*
|
|
connect to a share - used when a tree_connect operation comes in.
|
|
*/
|
|
static NTSTATUS unixuid_connect(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req, union smb_tcon *tcon)
|
|
{
|
|
struct unixuid_private *priv;
|
|
NTSTATUS status;
|
|
|
|
priv = talloc(ntvfs, struct unixuid_private);
|
|
if (!priv) {
|
|
return NT_STATUS_NO_MEMORY;
|
|
}
|
|
|
|
priv->wbc_ctx = wbc_init(priv, ntvfs->ctx->msg_ctx,
|
|
ntvfs->ctx->event_ctx);
|
|
if (priv->wbc_ctx == NULL) {
|
|
talloc_free(priv);
|
|
return NT_STATUS_INTERNAL_ERROR;
|
|
}
|
|
|
|
ntvfs->private_data = priv;
|
|
priv->last_sec_ctx = NULL;
|
|
priv->last_token = NULL;
|
|
|
|
tevent_loop_set_nesting_hook(ntvfs->ctx->event_ctx,
|
|
unixuid_event_nesting_hook,
|
|
&unixuid_nesting_level);
|
|
|
|
/* we don't use PASS_THRU_REQ here, as the connect operation runs with
|
|
root privileges. This allows the backends to setup any database
|
|
links they might need during the connect. */
|
|
status = ntvfs_next_connect(ntvfs, req, tcon);
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
disconnect from a share
|
|
*/
|
|
static NTSTATUS unixuid_disconnect(struct ntvfs_module_context *ntvfs)
|
|
{
|
|
struct unixuid_private *priv = ntvfs->private_data;
|
|
NTSTATUS status;
|
|
|
|
talloc_free(priv);
|
|
ntvfs->private_data = NULL;
|
|
|
|
status = ntvfs_next_disconnect(ntvfs);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
/*
|
|
delete a file
|
|
*/
|
|
static NTSTATUS unixuid_unlink(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req,
|
|
union smb_unlink *unl)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, unlink, (ntvfs, req, unl));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
ioctl interface
|
|
*/
|
|
static NTSTATUS unixuid_ioctl(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req, union smb_ioctl *io)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, ioctl, (ntvfs, req, io));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
check if a directory exists
|
|
*/
|
|
static NTSTATUS unixuid_chkpath(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req,
|
|
union smb_chkpath *cp)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, chkpath, (ntvfs, req, cp));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
return info on a pathname
|
|
*/
|
|
static NTSTATUS unixuid_qpathinfo(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req, union smb_fileinfo *info)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, qpathinfo, (ntvfs, req, info));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
query info on a open file
|
|
*/
|
|
static NTSTATUS unixuid_qfileinfo(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req, union smb_fileinfo *info)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, qfileinfo, (ntvfs, req, info));
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
/*
|
|
set info on a pathname
|
|
*/
|
|
static NTSTATUS unixuid_setpathinfo(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req, union smb_setfileinfo *st)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, setpathinfo, (ntvfs, req, st));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
open a file
|
|
*/
|
|
static NTSTATUS unixuid_open(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req, union smb_open *io)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, open, (ntvfs, req, io));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
create a directory
|
|
*/
|
|
static NTSTATUS unixuid_mkdir(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req, union smb_mkdir *md)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, mkdir, (ntvfs, req, md));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
remove a directory
|
|
*/
|
|
static NTSTATUS unixuid_rmdir(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req, struct smb_rmdir *rd)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, rmdir, (ntvfs, req, rd));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
rename a set of files
|
|
*/
|
|
static NTSTATUS unixuid_rename(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req, union smb_rename *ren)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, rename, (ntvfs, req, ren));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
copy a set of files
|
|
*/
|
|
static NTSTATUS unixuid_copy(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req, struct smb_copy *cp)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, copy, (ntvfs, req, cp));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
read from a file
|
|
*/
|
|
static NTSTATUS unixuid_read(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req, union smb_read *rd)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, read, (ntvfs, req, rd));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
write to a file
|
|
*/
|
|
static NTSTATUS unixuid_write(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req, union smb_write *wr)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, write, (ntvfs, req, wr));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
seek in a file
|
|
*/
|
|
static NTSTATUS unixuid_seek(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req,
|
|
union smb_seek *io)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, seek, (ntvfs, req, io));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
flush a file
|
|
*/
|
|
static NTSTATUS unixuid_flush(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req,
|
|
union smb_flush *io)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, flush, (ntvfs, req, io));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
close a file
|
|
*/
|
|
static NTSTATUS unixuid_close(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req, union smb_close *io)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, close, (ntvfs, req, io));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
exit - closing files
|
|
*/
|
|
static NTSTATUS unixuid_exit(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, exit, (ntvfs, req));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
logoff - closing files
|
|
*/
|
|
static NTSTATUS unixuid_logoff(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req)
|
|
{
|
|
struct unixuid_private *priv = ntvfs->private_data;
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, logoff, (ntvfs, req));
|
|
|
|
priv->last_token = NULL;
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
async setup
|
|
*/
|
|
static NTSTATUS unixuid_async_setup(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req,
|
|
void *private_data)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, async_setup, (ntvfs, req, private_data));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
cancel an async request
|
|
*/
|
|
static NTSTATUS unixuid_cancel(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, cancel, (ntvfs, req));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
change notify
|
|
*/
|
|
static NTSTATUS unixuid_notify(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req, union smb_notify *info)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, notify, (ntvfs, req, info));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
lock a byte range
|
|
*/
|
|
static NTSTATUS unixuid_lock(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req, union smb_lock *lck)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, lock, (ntvfs, req, lck));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
set info on a open file
|
|
*/
|
|
static NTSTATUS unixuid_setfileinfo(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req,
|
|
union smb_setfileinfo *info)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, setfileinfo, (ntvfs, req, info));
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
/*
|
|
return filesystem space info
|
|
*/
|
|
static NTSTATUS unixuid_fsinfo(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req, union smb_fsinfo *fs)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, fsinfo, (ntvfs, req, fs));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
return print queue info
|
|
*/
|
|
static NTSTATUS unixuid_lpq(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req, union smb_lpq *lpq)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, lpq, (ntvfs, req, lpq));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
list files in a directory matching a wildcard pattern
|
|
*/
|
|
static NTSTATUS unixuid_search_first(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req, union smb_search_first *io,
|
|
void *search_private,
|
|
bool (*callback)(void *, const union smb_search_data *))
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, search_first, (ntvfs, req, io, search_private, callback));
|
|
|
|
return status;
|
|
}
|
|
|
|
/* continue a search */
|
|
static NTSTATUS unixuid_search_next(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req, union smb_search_next *io,
|
|
void *search_private,
|
|
bool (*callback)(void *, const union smb_search_data *))
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, search_next, (ntvfs, req, io, search_private, callback));
|
|
|
|
return status;
|
|
}
|
|
|
|
/* close a search */
|
|
static NTSTATUS unixuid_search_close(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req, union smb_search_close *io)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, search_close, (ntvfs, req, io));
|
|
|
|
return status;
|
|
}
|
|
|
|
/* SMBtrans - not used on file shares */
|
|
static NTSTATUS unixuid_trans(struct ntvfs_module_context *ntvfs,
|
|
struct ntvfs_request *req, struct smb_trans2 *trans2)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PASS_THRU_REQ(ntvfs, req, trans, (ntvfs, req, trans2));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
initialise the unixuid backend, registering ourselves with the ntvfs subsystem
|
|
*/
|
|
NTSTATUS ntvfs_unixuid_init(void)
|
|
{
|
|
NTSTATUS ret;
|
|
struct ntvfs_ops ops;
|
|
NTVFS_CURRENT_CRITICAL_SIZES(vers);
|
|
|
|
ZERO_STRUCT(ops);
|
|
|
|
/* fill in all the operations */
|
|
ops.connect = unixuid_connect;
|
|
ops.disconnect = unixuid_disconnect;
|
|
ops.unlink = unixuid_unlink;
|
|
ops.chkpath = unixuid_chkpath;
|
|
ops.qpathinfo = unixuid_qpathinfo;
|
|
ops.setpathinfo = unixuid_setpathinfo;
|
|
ops.open = unixuid_open;
|
|
ops.mkdir = unixuid_mkdir;
|
|
ops.rmdir = unixuid_rmdir;
|
|
ops.rename = unixuid_rename;
|
|
ops.copy = unixuid_copy;
|
|
ops.ioctl = unixuid_ioctl;
|
|
ops.read = unixuid_read;
|
|
ops.write = unixuid_write;
|
|
ops.seek = unixuid_seek;
|
|
ops.flush = unixuid_flush;
|
|
ops.close = unixuid_close;
|
|
ops.exit = unixuid_exit;
|
|
ops.lock = unixuid_lock;
|
|
ops.setfileinfo = unixuid_setfileinfo;
|
|
ops.qfileinfo = unixuid_qfileinfo;
|
|
ops.fsinfo = unixuid_fsinfo;
|
|
ops.lpq = unixuid_lpq;
|
|
ops.search_first = unixuid_search_first;
|
|
ops.search_next = unixuid_search_next;
|
|
ops.search_close = unixuid_search_close;
|
|
ops.trans = unixuid_trans;
|
|
ops.logoff = unixuid_logoff;
|
|
ops.async_setup = unixuid_async_setup;
|
|
ops.cancel = unixuid_cancel;
|
|
ops.notify = unixuid_notify;
|
|
|
|
ops.name = "unixuid";
|
|
|
|
/* we register under all 3 backend types, as we are not type specific */
|
|
ops.type = NTVFS_DISK;
|
|
ret = ntvfs_register(&ops, &vers);
|
|
if (!NT_STATUS_IS_OK(ret)) goto failed;
|
|
|
|
ops.type = NTVFS_PRINT;
|
|
ret = ntvfs_register(&ops, &vers);
|
|
if (!NT_STATUS_IS_OK(ret)) goto failed;
|
|
|
|
ops.type = NTVFS_IPC;
|
|
ret = ntvfs_register(&ops, &vers);
|
|
if (!NT_STATUS_IS_OK(ret)) goto failed;
|
|
|
|
failed:
|
|
return ret;
|
|
}
|