2 Unix SMB/CIFS implementation.
4 a pass-thru NTVFS module to setup a security context using unix
7 Copyright (C) Andrew Tridgell 2004
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "system/filesys.h"
25 #include "system/passwd.h"
26 #include "auth/auth.h"
27 #include "ntvfs/ntvfs.h"
28 #include "libcli/wbclient/wbclient.h"
29 #define TEVENT_DEPRECATED
31 #include "../lib/util/setid.h"
33 NTSTATUS ntvfs_unixuid_init(void);
35 struct unixuid_private {
36 struct wbc_context *wbc_ctx;
37 struct security_unix_token *last_sec_ctx;
38 struct security_token *last_token;
43 pull the current security context into a security_unix_token
45 static struct security_unix_token *save_unix_security(TALLOC_CTX *mem_ctx)
47 struct security_unix_token *sec = talloc(mem_ctx, struct security_unix_token);
53 sec->ngroups = getgroups(0, NULL);
54 if (sec->ngroups == -1) {
58 sec->groups = talloc_array(sec, gid_t, sec->ngroups);
59 if (sec->groups == NULL) {
64 if (getgroups(sec->ngroups, sec->groups) != sec->ngroups) {
73 set the current security context from a security_unix_token
75 static NTSTATUS set_unix_security(struct security_unix_token *sec)
79 if (samba_setgroups(sec->ngroups, sec->groups) != 0) {
80 return NT_STATUS_ACCESS_DENIED;
82 if (samba_setegid(sec->gid) != 0) {
83 return NT_STATUS_ACCESS_DENIED;
85 if (samba_seteuid(sec->uid) != 0) {
86 return NT_STATUS_ACCESS_DENIED;
91 static int unixuid_nesting_level;
94 called at the start and end of a tevent nesting loop. Needs to save/restore
97 static int unixuid_event_nesting_hook(struct tevent_context *ev,
102 const char *location)
104 struct security_unix_token *sec_ctx;
106 if (unixuid_nesting_level == 0) {
107 /* we don't need to do anything unless we are nested
108 inside of a call in this module */
113 sec_ctx = save_unix_security(ev);
114 if (sec_ctx == NULL) {
115 DEBUG(0,("%s: Failed to save security context\n", location));
118 *(struct security_unix_token **)stack_ptr = sec_ctx;
119 if (samba_seteuid(0) != 0 || samba_setegid(0) != 0) {
120 DEBUG(0,("%s: Failed to change to root\n", location));
124 /* called when we come out of a nesting level */
127 sec_ctx = *(struct security_unix_token **)stack_ptr;
128 if (sec_ctx == NULL) {
129 /* this happens the first time this function
130 is called, as we install the hook while
131 inside an event in unixuid_connect() */
135 sec_ctx = talloc_get_type_abort(sec_ctx, struct security_unix_token);
136 status = set_unix_security(sec_ctx);
137 talloc_free(sec_ctx);
138 if (!NT_STATUS_IS_OK(status)) {
139 DEBUG(0,("%s: Failed to revert security context (%s)\n",
140 location, nt_errstr(status)));
150 form a security_unix_token from the current security_token
152 static NTSTATUS nt_token_to_unix_security(struct ntvfs_module_context *ntvfs,
153 struct ntvfs_request *req,
154 struct security_token *token,
155 struct security_unix_token **sec)
157 return security_token_to_unix_token(req,
158 ntvfs->ctx->event_ctx,
163 setup our unix security context according to the session authentication info
165 static NTSTATUS unixuid_setup_security(struct ntvfs_module_context *ntvfs,
166 struct ntvfs_request *req, struct security_unix_token **sec)
168 struct unixuid_private *priv = ntvfs->private_data;
169 struct security_token *token;
170 struct security_unix_token *newsec;
173 /* If we are asked to set up, but have not had a successful
174 * session setup or tree connect, then these may not be filled
175 * in. ACCESS_DENIED is the right error code here */
176 if (req->session_info == NULL || priv == NULL) {
177 return NT_STATUS_ACCESS_DENIED;
180 token = req->session_info->security_token;
182 *sec = save_unix_security(ntvfs);
184 return NT_STATUS_NO_MEMORY;
187 if (token == priv->last_token) {
188 newsec = priv->last_sec_ctx;
190 status = nt_token_to_unix_security(ntvfs, req, token, &newsec);
191 if (!NT_STATUS_IS_OK(status)) {
195 if (priv->last_sec_ctx) {
196 talloc_free(priv->last_sec_ctx);
198 priv->last_sec_ctx = newsec;
199 priv->last_token = token;
200 talloc_steal(priv, newsec);
203 status = set_unix_security(newsec);
204 if (!NT_STATUS_IS_OK(status)) {
213 this pass through macro operates on request contexts
215 #define PASS_THRU_REQ(ntvfs, req, op, args) do { \
217 struct security_unix_token *sec; \
218 status = unixuid_setup_security(ntvfs, req, &sec); \
219 NT_STATUS_NOT_OK_RETURN(status); \
220 unixuid_nesting_level++; \
221 status = ntvfs_next_##op args; \
222 unixuid_nesting_level--; \
223 status2 = set_unix_security(sec); \
225 if (!NT_STATUS_IS_OK(status2)) smb_panic("Unable to reset security context"); \
231 connect to a share - used when a tree_connect operation comes in.
233 static NTSTATUS unixuid_connect(struct ntvfs_module_context *ntvfs,
234 struct ntvfs_request *req, union smb_tcon *tcon)
236 struct unixuid_private *priv;
239 priv = talloc(ntvfs, struct unixuid_private);
241 return NT_STATUS_NO_MEMORY;
244 priv->wbc_ctx = wbc_init(priv, ntvfs->ctx->msg_ctx,
245 ntvfs->ctx->event_ctx);
246 if (priv->wbc_ctx == NULL) {
248 return NT_STATUS_INTERNAL_ERROR;
251 priv->last_sec_ctx = NULL;
252 priv->last_token = NULL;
253 ntvfs->private_data = priv;
255 tevent_loop_set_nesting_hook(ntvfs->ctx->event_ctx,
256 unixuid_event_nesting_hook,
257 &unixuid_nesting_level);
259 /* we don't use PASS_THRU_REQ here, as the connect operation runs with
260 root privileges. This allows the backends to setup any database
261 links they might need during the connect. */
262 status = ntvfs_next_connect(ntvfs, req, tcon);
268 disconnect from a share
270 static NTSTATUS unixuid_disconnect(struct ntvfs_module_context *ntvfs)
272 struct unixuid_private *priv = ntvfs->private_data;
276 ntvfs->private_data = NULL;
278 status = ntvfs_next_disconnect(ntvfs);
287 static NTSTATUS unixuid_unlink(struct ntvfs_module_context *ntvfs,
288 struct ntvfs_request *req,
289 union smb_unlink *unl)
293 PASS_THRU_REQ(ntvfs, req, unlink, (ntvfs, req, unl));
301 static NTSTATUS unixuid_ioctl(struct ntvfs_module_context *ntvfs,
302 struct ntvfs_request *req, union smb_ioctl *io)
306 PASS_THRU_REQ(ntvfs, req, ioctl, (ntvfs, req, io));
312 check if a directory exists
314 static NTSTATUS unixuid_chkpath(struct ntvfs_module_context *ntvfs,
315 struct ntvfs_request *req,
316 union smb_chkpath *cp)
320 PASS_THRU_REQ(ntvfs, req, chkpath, (ntvfs, req, cp));
326 return info on a pathname
328 static NTSTATUS unixuid_qpathinfo(struct ntvfs_module_context *ntvfs,
329 struct ntvfs_request *req, union smb_fileinfo *info)
333 PASS_THRU_REQ(ntvfs, req, qpathinfo, (ntvfs, req, info));
339 query info on a open file
341 static NTSTATUS unixuid_qfileinfo(struct ntvfs_module_context *ntvfs,
342 struct ntvfs_request *req, union smb_fileinfo *info)
346 PASS_THRU_REQ(ntvfs, req, qfileinfo, (ntvfs, req, info));
353 set info on a pathname
355 static NTSTATUS unixuid_setpathinfo(struct ntvfs_module_context *ntvfs,
356 struct ntvfs_request *req, union smb_setfileinfo *st)
360 PASS_THRU_REQ(ntvfs, req, setpathinfo, (ntvfs, req, st));
368 static NTSTATUS unixuid_open(struct ntvfs_module_context *ntvfs,
369 struct ntvfs_request *req, union smb_open *io)
373 PASS_THRU_REQ(ntvfs, req, open, (ntvfs, req, io));
381 static NTSTATUS unixuid_mkdir(struct ntvfs_module_context *ntvfs,
382 struct ntvfs_request *req, union smb_mkdir *md)
386 PASS_THRU_REQ(ntvfs, req, mkdir, (ntvfs, req, md));
394 static NTSTATUS unixuid_rmdir(struct ntvfs_module_context *ntvfs,
395 struct ntvfs_request *req, struct smb_rmdir *rd)
399 PASS_THRU_REQ(ntvfs, req, rmdir, (ntvfs, req, rd));
405 rename a set of files
407 static NTSTATUS unixuid_rename(struct ntvfs_module_context *ntvfs,
408 struct ntvfs_request *req, union smb_rename *ren)
412 PASS_THRU_REQ(ntvfs, req, rename, (ntvfs, req, ren));
420 static NTSTATUS unixuid_copy(struct ntvfs_module_context *ntvfs,
421 struct ntvfs_request *req, struct smb_copy *cp)
425 PASS_THRU_REQ(ntvfs, req, copy, (ntvfs, req, cp));
433 static NTSTATUS unixuid_read(struct ntvfs_module_context *ntvfs,
434 struct ntvfs_request *req, union smb_read *rd)
438 PASS_THRU_REQ(ntvfs, req, read, (ntvfs, req, rd));
446 static NTSTATUS unixuid_write(struct ntvfs_module_context *ntvfs,
447 struct ntvfs_request *req, union smb_write *wr)
451 PASS_THRU_REQ(ntvfs, req, write, (ntvfs, req, wr));
459 static NTSTATUS unixuid_seek(struct ntvfs_module_context *ntvfs,
460 struct ntvfs_request *req,
465 PASS_THRU_REQ(ntvfs, req, seek, (ntvfs, req, io));
473 static NTSTATUS unixuid_flush(struct ntvfs_module_context *ntvfs,
474 struct ntvfs_request *req,
479 PASS_THRU_REQ(ntvfs, req, flush, (ntvfs, req, io));
487 static NTSTATUS unixuid_close(struct ntvfs_module_context *ntvfs,
488 struct ntvfs_request *req, union smb_close *io)
492 PASS_THRU_REQ(ntvfs, req, close, (ntvfs, req, io));
500 static NTSTATUS unixuid_exit(struct ntvfs_module_context *ntvfs,
501 struct ntvfs_request *req)
505 PASS_THRU_REQ(ntvfs, req, exit, (ntvfs, req));
511 logoff - closing files
513 static NTSTATUS unixuid_logoff(struct ntvfs_module_context *ntvfs,
514 struct ntvfs_request *req)
516 struct unixuid_private *priv = ntvfs->private_data;
519 PASS_THRU_REQ(ntvfs, req, logoff, (ntvfs, req));
521 priv->last_token = NULL;
529 static NTSTATUS unixuid_async_setup(struct ntvfs_module_context *ntvfs,
530 struct ntvfs_request *req,
535 PASS_THRU_REQ(ntvfs, req, async_setup, (ntvfs, req, private_data));
541 cancel an async request
543 static NTSTATUS unixuid_cancel(struct ntvfs_module_context *ntvfs,
544 struct ntvfs_request *req)
548 PASS_THRU_REQ(ntvfs, req, cancel, (ntvfs, req));
556 static NTSTATUS unixuid_notify(struct ntvfs_module_context *ntvfs,
557 struct ntvfs_request *req, union smb_notify *info)
561 PASS_THRU_REQ(ntvfs, req, notify, (ntvfs, req, info));
569 static NTSTATUS unixuid_lock(struct ntvfs_module_context *ntvfs,
570 struct ntvfs_request *req, union smb_lock *lck)
574 PASS_THRU_REQ(ntvfs, req, lock, (ntvfs, req, lck));
580 set info on a open file
582 static NTSTATUS unixuid_setfileinfo(struct ntvfs_module_context *ntvfs,
583 struct ntvfs_request *req,
584 union smb_setfileinfo *info)
588 PASS_THRU_REQ(ntvfs, req, setfileinfo, (ntvfs, req, info));
595 return filesystem space info
597 static NTSTATUS unixuid_fsinfo(struct ntvfs_module_context *ntvfs,
598 struct ntvfs_request *req, union smb_fsinfo *fs)
602 PASS_THRU_REQ(ntvfs, req, fsinfo, (ntvfs, req, fs));
608 return print queue info
610 static NTSTATUS unixuid_lpq(struct ntvfs_module_context *ntvfs,
611 struct ntvfs_request *req, union smb_lpq *lpq)
615 PASS_THRU_REQ(ntvfs, req, lpq, (ntvfs, req, lpq));
621 list files in a directory matching a wildcard pattern
623 static NTSTATUS unixuid_search_first(struct ntvfs_module_context *ntvfs,
624 struct ntvfs_request *req, union smb_search_first *io,
625 void *search_private,
626 bool (*callback)(void *, const union smb_search_data *))
630 PASS_THRU_REQ(ntvfs, req, search_first, (ntvfs, req, io, search_private, callback));
635 /* continue a search */
636 static NTSTATUS unixuid_search_next(struct ntvfs_module_context *ntvfs,
637 struct ntvfs_request *req, union smb_search_next *io,
638 void *search_private,
639 bool (*callback)(void *, const union smb_search_data *))
643 PASS_THRU_REQ(ntvfs, req, search_next, (ntvfs, req, io, search_private, callback));
649 static NTSTATUS unixuid_search_close(struct ntvfs_module_context *ntvfs,
650 struct ntvfs_request *req, union smb_search_close *io)
654 PASS_THRU_REQ(ntvfs, req, search_close, (ntvfs, req, io));
659 /* SMBtrans - not used on file shares */
660 static NTSTATUS unixuid_trans(struct ntvfs_module_context *ntvfs,
661 struct ntvfs_request *req, struct smb_trans2 *trans2)
665 PASS_THRU_REQ(ntvfs, req, trans, (ntvfs, req, trans2));
671 initialise the unixuid backend, registering ourselves with the ntvfs subsystem
673 NTSTATUS ntvfs_unixuid_init(void)
676 struct ntvfs_ops ops;
677 NTVFS_CURRENT_CRITICAL_SIZES(vers);
681 /* fill in all the operations */
682 ops.connect_fn = unixuid_connect;
683 ops.disconnect_fn = unixuid_disconnect;
684 ops.unlink_fn = unixuid_unlink;
685 ops.chkpath_fn = unixuid_chkpath;
686 ops.qpathinfo_fn = unixuid_qpathinfo;
687 ops.setpathinfo_fn = unixuid_setpathinfo;
688 ops.open_fn = unixuid_open;
689 ops.mkdir_fn = unixuid_mkdir;
690 ops.rmdir_fn = unixuid_rmdir;
691 ops.rename_fn = unixuid_rename;
692 ops.copy_fn = unixuid_copy;
693 ops.ioctl_fn = unixuid_ioctl;
694 ops.read_fn = unixuid_read;
695 ops.write_fn = unixuid_write;
696 ops.seek_fn = unixuid_seek;
697 ops.flush_fn = unixuid_flush;
698 ops.close_fn = unixuid_close;
699 ops.exit_fn = unixuid_exit;
700 ops.lock_fn = unixuid_lock;
701 ops.setfileinfo_fn = unixuid_setfileinfo;
702 ops.qfileinfo_fn = unixuid_qfileinfo;
703 ops.fsinfo_fn = unixuid_fsinfo;
704 ops.lpq_fn = unixuid_lpq;
705 ops.search_first_fn = unixuid_search_first;
706 ops.search_next_fn = unixuid_search_next;
707 ops.search_close_fn = unixuid_search_close;
708 ops.trans_fn = unixuid_trans;
709 ops.logoff_fn = unixuid_logoff;
710 ops.async_setup_fn = unixuid_async_setup;
711 ops.cancel_fn = unixuid_cancel;
712 ops.notify_fn = unixuid_notify;
714 ops.name = "unixuid";
716 /* we register under all 3 backend types, as we are not type specific */
717 ops.type = NTVFS_DISK;
718 ret = ntvfs_register(&ops, &vers);
719 if (!NT_STATUS_IS_OK(ret)) goto failed;
721 ops.type = NTVFS_PRINT;
722 ret = ntvfs_register(&ops, &vers);
723 if (!NT_STATUS_IS_OK(ret)) goto failed;
725 ops.type = NTVFS_IPC;
726 ret = ntvfs_register(&ops, &vers);
727 if (!NT_STATUS_IS_OK(ret)) goto failed;