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
32 NTSTATUS
ntvfs_unixuid_init(void);
34 struct unixuid_private
{
35 struct wbc_context
*wbc_ctx
;
36 struct security_unix_token
*last_sec_ctx
;
37 struct security_token
*last_token
;
42 pull the current security context into a security_unix_token
44 static struct security_unix_token
*save_unix_security(TALLOC_CTX
*mem_ctx
)
46 struct security_unix_token
*sec
= talloc(mem_ctx
, struct security_unix_token
);
52 sec
->ngroups
= getgroups(0, NULL
);
53 if (sec
->ngroups
== -1) {
57 sec
->groups
= talloc_array(sec
, gid_t
, sec
->ngroups
);
58 if (sec
->groups
== NULL
) {
63 if (getgroups(sec
->ngroups
, sec
->groups
) != sec
->ngroups
) {
72 set the current security context from a security_unix_token
74 static NTSTATUS
set_unix_security(struct security_unix_token
*sec
)
78 if (setgroups(sec
->ngroups
, sec
->groups
) != 0) {
79 return NT_STATUS_ACCESS_DENIED
;
81 if (setegid(sec
->gid
) != 0) {
82 return NT_STATUS_ACCESS_DENIED
;
84 if (seteuid(sec
->uid
) != 0) {
85 return NT_STATUS_ACCESS_DENIED
;
90 static int unixuid_nesting_level
;
93 called at the start and end of a tevent nesting loop. Needs to save/restore
96 static int unixuid_event_nesting_hook(struct tevent_context
*ev
,
101 const char *location
)
103 struct security_unix_token
*sec_ctx
;
105 if (unixuid_nesting_level
== 0) {
106 /* we don't need to do anything unless we are nested
107 inside of a call in this module */
112 sec_ctx
= save_unix_security(ev
);
113 if (sec_ctx
== NULL
) {
114 DEBUG(0,("%s: Failed to save security context\n", location
));
117 *(struct security_unix_token
**)stack_ptr
= sec_ctx
;
118 if (seteuid(0) != 0 || setegid(0) != 0) {
119 DEBUG(0,("%s: Failed to change to root\n", location
));
123 /* called when we come out of a nesting level */
126 sec_ctx
= *(struct security_unix_token
**)stack_ptr
;
127 if (sec_ctx
== NULL
) {
128 /* this happens the first time this function
129 is called, as we install the hook while
130 inside an event in unixuid_connect() */
134 sec_ctx
= talloc_get_type_abort(sec_ctx
, struct security_unix_token
);
135 status
= set_unix_security(sec_ctx
);
136 talloc_free(sec_ctx
);
137 if (!NT_STATUS_IS_OK(status
)) {
138 DEBUG(0,("%s: Failed to revert security context (%s)\n",
139 location
, nt_errstr(status
)));
149 form a security_unix_token from the current security_token
151 static NTSTATUS
nt_token_to_unix_security(struct ntvfs_module_context
*ntvfs
,
152 struct ntvfs_request
*req
,
153 struct security_token
*token
,
154 struct security_unix_token
**sec
)
156 struct unixuid_private
*priv
= ntvfs
->private_data
;
158 return security_token_to_unix_token(req
,
164 setup our unix security context according to the session authentication info
166 static NTSTATUS
unixuid_setup_security(struct ntvfs_module_context
*ntvfs
,
167 struct ntvfs_request
*req
, struct security_unix_token
**sec
)
169 struct unixuid_private
*priv
= ntvfs
->private_data
;
170 struct security_token
*token
;
171 struct security_unix_token
*newsec
;
174 /* If we are asked to set up, but have not had a successful
175 * session setup or tree connect, then these may not be filled
176 * in. ACCESS_DENIED is the right error code here */
177 if (req
->session_info
== NULL
|| priv
== NULL
) {
178 return NT_STATUS_ACCESS_DENIED
;
181 token
= req
->session_info
->security_token
;
183 *sec
= save_unix_security(ntvfs
);
185 return NT_STATUS_NO_MEMORY
;
188 if (token
== priv
->last_token
) {
189 newsec
= priv
->last_sec_ctx
;
191 status
= nt_token_to_unix_security(ntvfs
, req
, token
, &newsec
);
192 if (!NT_STATUS_IS_OK(status
)) {
196 if (priv
->last_sec_ctx
) {
197 talloc_free(priv
->last_sec_ctx
);
199 priv
->last_sec_ctx
= newsec
;
200 priv
->last_token
= token
;
201 talloc_steal(priv
, newsec
);
204 status
= set_unix_security(newsec
);
205 if (!NT_STATUS_IS_OK(status
)) {
214 this pass through macro operates on request contexts
216 #define PASS_THRU_REQ(ntvfs, req, op, args) do { \
218 struct security_unix_token *sec; \
219 status = unixuid_setup_security(ntvfs, req, &sec); \
220 NT_STATUS_NOT_OK_RETURN(status); \
221 unixuid_nesting_level++; \
222 status = ntvfs_next_##op args; \
223 unixuid_nesting_level--; \
224 status2 = set_unix_security(sec); \
226 if (!NT_STATUS_IS_OK(status2)) smb_panic("Unable to reset security context"); \
232 connect to a share - used when a tree_connect operation comes in.
234 static NTSTATUS
unixuid_connect(struct ntvfs_module_context
*ntvfs
,
235 struct ntvfs_request
*req
, union smb_tcon
*tcon
)
237 struct unixuid_private
*priv
;
240 priv
= talloc(ntvfs
, struct unixuid_private
);
242 return NT_STATUS_NO_MEMORY
;
245 priv
->wbc_ctx
= wbc_init(priv
, ntvfs
->ctx
->msg_ctx
,
246 ntvfs
->ctx
->event_ctx
);
247 if (priv
->wbc_ctx
== NULL
) {
249 return NT_STATUS_INTERNAL_ERROR
;
252 priv
->last_sec_ctx
= NULL
;
253 priv
->last_token
= NULL
;
254 ntvfs
->private_data
= priv
;
256 tevent_loop_set_nesting_hook(ntvfs
->ctx
->event_ctx
,
257 unixuid_event_nesting_hook
,
258 &unixuid_nesting_level
);
260 /* we don't use PASS_THRU_REQ here, as the connect operation runs with
261 root privileges. This allows the backends to setup any database
262 links they might need during the connect. */
263 status
= ntvfs_next_connect(ntvfs
, req
, tcon
);
269 disconnect from a share
271 static NTSTATUS
unixuid_disconnect(struct ntvfs_module_context
*ntvfs
)
273 struct unixuid_private
*priv
= ntvfs
->private_data
;
277 ntvfs
->private_data
= NULL
;
279 status
= ntvfs_next_disconnect(ntvfs
);
288 static NTSTATUS
unixuid_unlink(struct ntvfs_module_context
*ntvfs
,
289 struct ntvfs_request
*req
,
290 union smb_unlink
*unl
)
294 PASS_THRU_REQ(ntvfs
, req
, unlink
, (ntvfs
, req
, unl
));
302 static NTSTATUS
unixuid_ioctl(struct ntvfs_module_context
*ntvfs
,
303 struct ntvfs_request
*req
, union smb_ioctl
*io
)
307 PASS_THRU_REQ(ntvfs
, req
, ioctl
, (ntvfs
, req
, io
));
313 check if a directory exists
315 static NTSTATUS
unixuid_chkpath(struct ntvfs_module_context
*ntvfs
,
316 struct ntvfs_request
*req
,
317 union smb_chkpath
*cp
)
321 PASS_THRU_REQ(ntvfs
, req
, chkpath
, (ntvfs
, req
, cp
));
327 return info on a pathname
329 static NTSTATUS
unixuid_qpathinfo(struct ntvfs_module_context
*ntvfs
,
330 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
334 PASS_THRU_REQ(ntvfs
, req
, qpathinfo
, (ntvfs
, req
, info
));
340 query info on a open file
342 static NTSTATUS
unixuid_qfileinfo(struct ntvfs_module_context
*ntvfs
,
343 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
347 PASS_THRU_REQ(ntvfs
, req
, qfileinfo
, (ntvfs
, req
, info
));
354 set info on a pathname
356 static NTSTATUS
unixuid_setpathinfo(struct ntvfs_module_context
*ntvfs
,
357 struct ntvfs_request
*req
, union smb_setfileinfo
*st
)
361 PASS_THRU_REQ(ntvfs
, req
, setpathinfo
, (ntvfs
, req
, st
));
369 static NTSTATUS
unixuid_open(struct ntvfs_module_context
*ntvfs
,
370 struct ntvfs_request
*req
, union smb_open
*io
)
374 PASS_THRU_REQ(ntvfs
, req
, open
, (ntvfs
, req
, io
));
382 static NTSTATUS
unixuid_mkdir(struct ntvfs_module_context
*ntvfs
,
383 struct ntvfs_request
*req
, union smb_mkdir
*md
)
387 PASS_THRU_REQ(ntvfs
, req
, mkdir
, (ntvfs
, req
, md
));
395 static NTSTATUS
unixuid_rmdir(struct ntvfs_module_context
*ntvfs
,
396 struct ntvfs_request
*req
, struct smb_rmdir
*rd
)
400 PASS_THRU_REQ(ntvfs
, req
, rmdir
, (ntvfs
, req
, rd
));
406 rename a set of files
408 static NTSTATUS
unixuid_rename(struct ntvfs_module_context
*ntvfs
,
409 struct ntvfs_request
*req
, union smb_rename
*ren
)
413 PASS_THRU_REQ(ntvfs
, req
, rename
, (ntvfs
, req
, ren
));
421 static NTSTATUS
unixuid_copy(struct ntvfs_module_context
*ntvfs
,
422 struct ntvfs_request
*req
, struct smb_copy
*cp
)
426 PASS_THRU_REQ(ntvfs
, req
, copy
, (ntvfs
, req
, cp
));
434 static NTSTATUS
unixuid_read(struct ntvfs_module_context
*ntvfs
,
435 struct ntvfs_request
*req
, union smb_read
*rd
)
439 PASS_THRU_REQ(ntvfs
, req
, read
, (ntvfs
, req
, rd
));
447 static NTSTATUS
unixuid_write(struct ntvfs_module_context
*ntvfs
,
448 struct ntvfs_request
*req
, union smb_write
*wr
)
452 PASS_THRU_REQ(ntvfs
, req
, write
, (ntvfs
, req
, wr
));
460 static NTSTATUS
unixuid_seek(struct ntvfs_module_context
*ntvfs
,
461 struct ntvfs_request
*req
,
466 PASS_THRU_REQ(ntvfs
, req
, seek
, (ntvfs
, req
, io
));
474 static NTSTATUS
unixuid_flush(struct ntvfs_module_context
*ntvfs
,
475 struct ntvfs_request
*req
,
480 PASS_THRU_REQ(ntvfs
, req
, flush
, (ntvfs
, req
, io
));
488 static NTSTATUS
unixuid_close(struct ntvfs_module_context
*ntvfs
,
489 struct ntvfs_request
*req
, union smb_close
*io
)
493 PASS_THRU_REQ(ntvfs
, req
, close
, (ntvfs
, req
, io
));
501 static NTSTATUS
unixuid_exit(struct ntvfs_module_context
*ntvfs
,
502 struct ntvfs_request
*req
)
506 PASS_THRU_REQ(ntvfs
, req
, exit
, (ntvfs
, req
));
512 logoff - closing files
514 static NTSTATUS
unixuid_logoff(struct ntvfs_module_context
*ntvfs
,
515 struct ntvfs_request
*req
)
517 struct unixuid_private
*priv
= ntvfs
->private_data
;
520 PASS_THRU_REQ(ntvfs
, req
, logoff
, (ntvfs
, req
));
522 priv
->last_token
= NULL
;
530 static NTSTATUS
unixuid_async_setup(struct ntvfs_module_context
*ntvfs
,
531 struct ntvfs_request
*req
,
536 PASS_THRU_REQ(ntvfs
, req
, async_setup
, (ntvfs
, req
, private_data
));
542 cancel an async request
544 static NTSTATUS
unixuid_cancel(struct ntvfs_module_context
*ntvfs
,
545 struct ntvfs_request
*req
)
549 PASS_THRU_REQ(ntvfs
, req
, cancel
, (ntvfs
, req
));
557 static NTSTATUS
unixuid_notify(struct ntvfs_module_context
*ntvfs
,
558 struct ntvfs_request
*req
, union smb_notify
*info
)
562 PASS_THRU_REQ(ntvfs
, req
, notify
, (ntvfs
, req
, info
));
570 static NTSTATUS
unixuid_lock(struct ntvfs_module_context
*ntvfs
,
571 struct ntvfs_request
*req
, union smb_lock
*lck
)
575 PASS_THRU_REQ(ntvfs
, req
, lock
, (ntvfs
, req
, lck
));
581 set info on a open file
583 static NTSTATUS
unixuid_setfileinfo(struct ntvfs_module_context
*ntvfs
,
584 struct ntvfs_request
*req
,
585 union smb_setfileinfo
*info
)
589 PASS_THRU_REQ(ntvfs
, req
, setfileinfo
, (ntvfs
, req
, info
));
596 return filesystem space info
598 static NTSTATUS
unixuid_fsinfo(struct ntvfs_module_context
*ntvfs
,
599 struct ntvfs_request
*req
, union smb_fsinfo
*fs
)
603 PASS_THRU_REQ(ntvfs
, req
, fsinfo
, (ntvfs
, req
, fs
));
609 return print queue info
611 static NTSTATUS
unixuid_lpq(struct ntvfs_module_context
*ntvfs
,
612 struct ntvfs_request
*req
, union smb_lpq
*lpq
)
616 PASS_THRU_REQ(ntvfs
, req
, lpq
, (ntvfs
, req
, lpq
));
622 list files in a directory matching a wildcard pattern
624 static NTSTATUS
unixuid_search_first(struct ntvfs_module_context
*ntvfs
,
625 struct ntvfs_request
*req
, union smb_search_first
*io
,
626 void *search_private
,
627 bool (*callback
)(void *, const union smb_search_data
*))
631 PASS_THRU_REQ(ntvfs
, req
, search_first
, (ntvfs
, req
, io
, search_private
, callback
));
636 /* continue a search */
637 static NTSTATUS
unixuid_search_next(struct ntvfs_module_context
*ntvfs
,
638 struct ntvfs_request
*req
, union smb_search_next
*io
,
639 void *search_private
,
640 bool (*callback
)(void *, const union smb_search_data
*))
644 PASS_THRU_REQ(ntvfs
, req
, search_next
, (ntvfs
, req
, io
, search_private
, callback
));
650 static NTSTATUS
unixuid_search_close(struct ntvfs_module_context
*ntvfs
,
651 struct ntvfs_request
*req
, union smb_search_close
*io
)
655 PASS_THRU_REQ(ntvfs
, req
, search_close
, (ntvfs
, req
, io
));
660 /* SMBtrans - not used on file shares */
661 static NTSTATUS
unixuid_trans(struct ntvfs_module_context
*ntvfs
,
662 struct ntvfs_request
*req
, struct smb_trans2
*trans2
)
666 PASS_THRU_REQ(ntvfs
, req
, trans
, (ntvfs
, req
, trans2
));
672 initialise the unixuid backend, registering ourselves with the ntvfs subsystem
674 NTSTATUS
ntvfs_unixuid_init(void)
677 struct ntvfs_ops ops
;
678 NTVFS_CURRENT_CRITICAL_SIZES(vers
);
682 /* fill in all the operations */
683 ops
.connect_fn
= unixuid_connect
;
684 ops
.disconnect_fn
= unixuid_disconnect
;
685 ops
.unlink_fn
= unixuid_unlink
;
686 ops
.chkpath_fn
= unixuid_chkpath
;
687 ops
.qpathinfo_fn
= unixuid_qpathinfo
;
688 ops
.setpathinfo_fn
= unixuid_setpathinfo
;
689 ops
.open_fn
= unixuid_open
;
690 ops
.mkdir_fn
= unixuid_mkdir
;
691 ops
.rmdir_fn
= unixuid_rmdir
;
692 ops
.rename_fn
= unixuid_rename
;
693 ops
.copy_fn
= unixuid_copy
;
694 ops
.ioctl_fn
= unixuid_ioctl
;
695 ops
.read_fn
= unixuid_read
;
696 ops
.write_fn
= unixuid_write
;
697 ops
.seek_fn
= unixuid_seek
;
698 ops
.flush_fn
= unixuid_flush
;
699 ops
.close_fn
= unixuid_close
;
700 ops
.exit_fn
= unixuid_exit
;
701 ops
.lock_fn
= unixuid_lock
;
702 ops
.setfileinfo_fn
= unixuid_setfileinfo
;
703 ops
.qfileinfo_fn
= unixuid_qfileinfo
;
704 ops
.fsinfo_fn
= unixuid_fsinfo
;
705 ops
.lpq_fn
= unixuid_lpq
;
706 ops
.search_first_fn
= unixuid_search_first
;
707 ops
.search_next_fn
= unixuid_search_next
;
708 ops
.search_close_fn
= unixuid_search_close
;
709 ops
.trans_fn
= unixuid_trans
;
710 ops
.logoff_fn
= unixuid_logoff
;
711 ops
.async_setup_fn
= unixuid_async_setup
;
712 ops
.cancel_fn
= unixuid_cancel
;
713 ops
.notify_fn
= unixuid_notify
;
715 ops
.name
= "unixuid";
717 /* we register under all 3 backend types, as we are not type specific */
718 ops
.type
= NTVFS_DISK
;
719 ret
= ntvfs_register(&ops
, &vers
);
720 if (!NT_STATUS_IS_OK(ret
)) goto failed
;
722 ops
.type
= NTVFS_PRINT
;
723 ret
= ntvfs_register(&ops
, &vers
);
724 if (!NT_STATUS_IS_OK(ret
)) goto failed
;
726 ops
.type
= NTVFS_IPC
;
727 ret
= ntvfs_register(&ops
, &vers
);
728 if (!NT_STATUS_IS_OK(ret
)) goto failed
;