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 struct unixuid_private *priv = ntvfs->private_data;
159 return security_token_to_unix_token(req,
160 priv->wbc_ctx->event_ctx,
165 setup our unix security context according to the session authentication info
167 static NTSTATUS unixuid_setup_security(struct ntvfs_module_context *ntvfs,
168 struct ntvfs_request *req, struct security_unix_token **sec)
170 struct unixuid_private *priv = ntvfs->private_data;
171 struct security_token *token;
172 struct security_unix_token *newsec;
175 /* If we are asked to set up, but have not had a successful
176 * session setup or tree connect, then these may not be filled
177 * in. ACCESS_DENIED is the right error code here */
178 if (req->session_info == NULL || priv == NULL) {
179 return NT_STATUS_ACCESS_DENIED;
182 token = req->session_info->security_token;
184 *sec = save_unix_security(ntvfs);
186 return NT_STATUS_NO_MEMORY;
189 if (token == priv->last_token) {
190 newsec = priv->last_sec_ctx;
192 status = nt_token_to_unix_security(ntvfs, req, token, &newsec);
193 if (!NT_STATUS_IS_OK(status)) {
197 if (priv->last_sec_ctx) {
198 talloc_free(priv->last_sec_ctx);
200 priv->last_sec_ctx = newsec;
201 priv->last_token = token;
202 talloc_steal(priv, newsec);
205 status = set_unix_security(newsec);
206 if (!NT_STATUS_IS_OK(status)) {
215 this pass through macro operates on request contexts
217 #define PASS_THRU_REQ(ntvfs, req, op, args) do { \
219 struct security_unix_token *sec; \
220 status = unixuid_setup_security(ntvfs, req, &sec); \
221 NT_STATUS_NOT_OK_RETURN(status); \
222 unixuid_nesting_level++; \
223 status = ntvfs_next_##op args; \
224 unixuid_nesting_level--; \
225 status2 = set_unix_security(sec); \
227 if (!NT_STATUS_IS_OK(status2)) smb_panic("Unable to reset security context"); \
233 connect to a share - used when a tree_connect operation comes in.
235 static NTSTATUS unixuid_connect(struct ntvfs_module_context *ntvfs,
236 struct ntvfs_request *req, union smb_tcon *tcon)
238 struct unixuid_private *priv;
241 priv = talloc(ntvfs, struct unixuid_private);
243 return NT_STATUS_NO_MEMORY;
246 priv->wbc_ctx = wbc_init(priv, ntvfs->ctx->msg_ctx,
247 ntvfs->ctx->event_ctx);
248 if (priv->wbc_ctx == NULL) {
250 return NT_STATUS_INTERNAL_ERROR;
253 priv->last_sec_ctx = NULL;
254 priv->last_token = NULL;
255 ntvfs->private_data = priv;
257 tevent_loop_set_nesting_hook(ntvfs->ctx->event_ctx,
258 unixuid_event_nesting_hook,
259 &unixuid_nesting_level);
261 /* we don't use PASS_THRU_REQ here, as the connect operation runs with
262 root privileges. This allows the backends to setup any database
263 links they might need during the connect. */
264 status = ntvfs_next_connect(ntvfs, req, tcon);
270 disconnect from a share
272 static NTSTATUS unixuid_disconnect(struct ntvfs_module_context *ntvfs)
274 struct unixuid_private *priv = ntvfs->private_data;
278 ntvfs->private_data = NULL;
280 status = ntvfs_next_disconnect(ntvfs);
289 static NTSTATUS unixuid_unlink(struct ntvfs_module_context *ntvfs,
290 struct ntvfs_request *req,
291 union smb_unlink *unl)
295 PASS_THRU_REQ(ntvfs, req, unlink, (ntvfs, req, unl));
303 static NTSTATUS unixuid_ioctl(struct ntvfs_module_context *ntvfs,
304 struct ntvfs_request *req, union smb_ioctl *io)
308 PASS_THRU_REQ(ntvfs, req, ioctl, (ntvfs, req, io));
314 check if a directory exists
316 static NTSTATUS unixuid_chkpath(struct ntvfs_module_context *ntvfs,
317 struct ntvfs_request *req,
318 union smb_chkpath *cp)
322 PASS_THRU_REQ(ntvfs, req, chkpath, (ntvfs, req, cp));
328 return info on a pathname
330 static NTSTATUS unixuid_qpathinfo(struct ntvfs_module_context *ntvfs,
331 struct ntvfs_request *req, union smb_fileinfo *info)
335 PASS_THRU_REQ(ntvfs, req, qpathinfo, (ntvfs, req, info));
341 query info on a open file
343 static NTSTATUS unixuid_qfileinfo(struct ntvfs_module_context *ntvfs,
344 struct ntvfs_request *req, union smb_fileinfo *info)
348 PASS_THRU_REQ(ntvfs, req, qfileinfo, (ntvfs, req, info));
355 set info on a pathname
357 static NTSTATUS unixuid_setpathinfo(struct ntvfs_module_context *ntvfs,
358 struct ntvfs_request *req, union smb_setfileinfo *st)
362 PASS_THRU_REQ(ntvfs, req, setpathinfo, (ntvfs, req, st));
370 static NTSTATUS unixuid_open(struct ntvfs_module_context *ntvfs,
371 struct ntvfs_request *req, union smb_open *io)
375 PASS_THRU_REQ(ntvfs, req, open, (ntvfs, req, io));
383 static NTSTATUS unixuid_mkdir(struct ntvfs_module_context *ntvfs,
384 struct ntvfs_request *req, union smb_mkdir *md)
388 PASS_THRU_REQ(ntvfs, req, mkdir, (ntvfs, req, md));
396 static NTSTATUS unixuid_rmdir(struct ntvfs_module_context *ntvfs,
397 struct ntvfs_request *req, struct smb_rmdir *rd)
401 PASS_THRU_REQ(ntvfs, req, rmdir, (ntvfs, req, rd));
407 rename a set of files
409 static NTSTATUS unixuid_rename(struct ntvfs_module_context *ntvfs,
410 struct ntvfs_request *req, union smb_rename *ren)
414 PASS_THRU_REQ(ntvfs, req, rename, (ntvfs, req, ren));
422 static NTSTATUS unixuid_copy(struct ntvfs_module_context *ntvfs,
423 struct ntvfs_request *req, struct smb_copy *cp)
427 PASS_THRU_REQ(ntvfs, req, copy, (ntvfs, req, cp));
435 static NTSTATUS unixuid_read(struct ntvfs_module_context *ntvfs,
436 struct ntvfs_request *req, union smb_read *rd)
440 PASS_THRU_REQ(ntvfs, req, read, (ntvfs, req, rd));
448 static NTSTATUS unixuid_write(struct ntvfs_module_context *ntvfs,
449 struct ntvfs_request *req, union smb_write *wr)
453 PASS_THRU_REQ(ntvfs, req, write, (ntvfs, req, wr));
461 static NTSTATUS unixuid_seek(struct ntvfs_module_context *ntvfs,
462 struct ntvfs_request *req,
467 PASS_THRU_REQ(ntvfs, req, seek, (ntvfs, req, io));
475 static NTSTATUS unixuid_flush(struct ntvfs_module_context *ntvfs,
476 struct ntvfs_request *req,
481 PASS_THRU_REQ(ntvfs, req, flush, (ntvfs, req, io));
489 static NTSTATUS unixuid_close(struct ntvfs_module_context *ntvfs,
490 struct ntvfs_request *req, union smb_close *io)
494 PASS_THRU_REQ(ntvfs, req, close, (ntvfs, req, io));
502 static NTSTATUS unixuid_exit(struct ntvfs_module_context *ntvfs,
503 struct ntvfs_request *req)
507 PASS_THRU_REQ(ntvfs, req, exit, (ntvfs, req));
513 logoff - closing files
515 static NTSTATUS unixuid_logoff(struct ntvfs_module_context *ntvfs,
516 struct ntvfs_request *req)
518 struct unixuid_private *priv = ntvfs->private_data;
521 PASS_THRU_REQ(ntvfs, req, logoff, (ntvfs, req));
523 priv->last_token = NULL;
531 static NTSTATUS unixuid_async_setup(struct ntvfs_module_context *ntvfs,
532 struct ntvfs_request *req,
537 PASS_THRU_REQ(ntvfs, req, async_setup, (ntvfs, req, private_data));
543 cancel an async request
545 static NTSTATUS unixuid_cancel(struct ntvfs_module_context *ntvfs,
546 struct ntvfs_request *req)
550 PASS_THRU_REQ(ntvfs, req, cancel, (ntvfs, req));
558 static NTSTATUS unixuid_notify(struct ntvfs_module_context *ntvfs,
559 struct ntvfs_request *req, union smb_notify *info)
563 PASS_THRU_REQ(ntvfs, req, notify, (ntvfs, req, info));
571 static NTSTATUS unixuid_lock(struct ntvfs_module_context *ntvfs,
572 struct ntvfs_request *req, union smb_lock *lck)
576 PASS_THRU_REQ(ntvfs, req, lock, (ntvfs, req, lck));
582 set info on a open file
584 static NTSTATUS unixuid_setfileinfo(struct ntvfs_module_context *ntvfs,
585 struct ntvfs_request *req,
586 union smb_setfileinfo *info)
590 PASS_THRU_REQ(ntvfs, req, setfileinfo, (ntvfs, req, info));
597 return filesystem space info
599 static NTSTATUS unixuid_fsinfo(struct ntvfs_module_context *ntvfs,
600 struct ntvfs_request *req, union smb_fsinfo *fs)
604 PASS_THRU_REQ(ntvfs, req, fsinfo, (ntvfs, req, fs));
610 return print queue info
612 static NTSTATUS unixuid_lpq(struct ntvfs_module_context *ntvfs,
613 struct ntvfs_request *req, union smb_lpq *lpq)
617 PASS_THRU_REQ(ntvfs, req, lpq, (ntvfs, req, lpq));
623 list files in a directory matching a wildcard pattern
625 static NTSTATUS unixuid_search_first(struct ntvfs_module_context *ntvfs,
626 struct ntvfs_request *req, union smb_search_first *io,
627 void *search_private,
628 bool (*callback)(void *, const union smb_search_data *))
632 PASS_THRU_REQ(ntvfs, req, search_first, (ntvfs, req, io, search_private, callback));
637 /* continue a search */
638 static NTSTATUS unixuid_search_next(struct ntvfs_module_context *ntvfs,
639 struct ntvfs_request *req, union smb_search_next *io,
640 void *search_private,
641 bool (*callback)(void *, const union smb_search_data *))
645 PASS_THRU_REQ(ntvfs, req, search_next, (ntvfs, req, io, search_private, callback));
651 static NTSTATUS unixuid_search_close(struct ntvfs_module_context *ntvfs,
652 struct ntvfs_request *req, union smb_search_close *io)
656 PASS_THRU_REQ(ntvfs, req, search_close, (ntvfs, req, io));
661 /* SMBtrans - not used on file shares */
662 static NTSTATUS unixuid_trans(struct ntvfs_module_context *ntvfs,
663 struct ntvfs_request *req, struct smb_trans2 *trans2)
667 PASS_THRU_REQ(ntvfs, req, trans, (ntvfs, req, trans2));
673 initialise the unixuid backend, registering ourselves with the ntvfs subsystem
675 NTSTATUS ntvfs_unixuid_init(void)
678 struct ntvfs_ops ops;
679 NTVFS_CURRENT_CRITICAL_SIZES(vers);
683 /* fill in all the operations */
684 ops.connect_fn = unixuid_connect;
685 ops.disconnect_fn = unixuid_disconnect;
686 ops.unlink_fn = unixuid_unlink;
687 ops.chkpath_fn = unixuid_chkpath;
688 ops.qpathinfo_fn = unixuid_qpathinfo;
689 ops.setpathinfo_fn = unixuid_setpathinfo;
690 ops.open_fn = unixuid_open;
691 ops.mkdir_fn = unixuid_mkdir;
692 ops.rmdir_fn = unixuid_rmdir;
693 ops.rename_fn = unixuid_rename;
694 ops.copy_fn = unixuid_copy;
695 ops.ioctl_fn = unixuid_ioctl;
696 ops.read_fn = unixuid_read;
697 ops.write_fn = unixuid_write;
698 ops.seek_fn = unixuid_seek;
699 ops.flush_fn = unixuid_flush;
700 ops.close_fn = unixuid_close;
701 ops.exit_fn = unixuid_exit;
702 ops.lock_fn = unixuid_lock;
703 ops.setfileinfo_fn = unixuid_setfileinfo;
704 ops.qfileinfo_fn = unixuid_qfileinfo;
705 ops.fsinfo_fn = unixuid_fsinfo;
706 ops.lpq_fn = unixuid_lpq;
707 ops.search_first_fn = unixuid_search_first;
708 ops.search_next_fn = unixuid_search_next;
709 ops.search_close_fn = unixuid_search_close;
710 ops.trans_fn = unixuid_trans;
711 ops.logoff_fn = unixuid_logoff;
712 ops.async_setup_fn = unixuid_async_setup;
713 ops.cancel_fn = unixuid_cancel;
714 ops.notify_fn = unixuid_notify;
716 ops.name = "unixuid";
718 /* we register under all 3 backend types, as we are not type specific */
719 ops.type = NTVFS_DISK;
720 ret = ntvfs_register(&ops, &vers);
721 if (!NT_STATUS_IS_OK(ret)) goto failed;
723 ops.type = NTVFS_PRINT;
724 ret = ntvfs_register(&ops, &vers);
725 if (!NT_STATUS_IS_OK(ret)) goto failed;
727 ops.type = NTVFS_IPC;
728 ret = ntvfs_register(&ops, &vers);
729 if (!NT_STATUS_IS_OK(ret)) goto failed;