📄 vfs_unixuid.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"#include "param/param.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;}/* 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 *private = 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 == private->last_token) { newsec = private->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 (private->last_sec_ctx) { talloc_free(private->last_sec_ctx); } private->last_sec_ctx = newsec; private->last_token = token; talloc_steal(private, 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); \ status = ntvfs_next_##op args; \ 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, const char *sharename){ struct unixuid_private *private; NTSTATUS status; private = talloc(ntvfs, struct unixuid_private); if (!private) { return NT_STATUS_NO_MEMORY; } private->wbc_ctx = wbc_init(private, ntvfs->ctx->msg_ctx, ntvfs->ctx->event_ctx); if (private->wbc_ctx == NULL) { talloc_free(private); return NT_STATUS_INTERNAL_ERROR; } ntvfs->private_data = private; private->last_sec_ctx = NULL; private->last_token = NULL; /* 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, sharename); return status;}/* disconnect from a share*/static NTSTATUS unixuid_disconnect(struct ntvfs_module_context *ntvfs){ struct unixuid_private *private = ntvfs->private_data; NTSTATUS status; talloc_free(private); 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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -