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
,
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
;