2 Unix SMB/CIFS implementation.
4 A pass-through 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(TALLOC_CTX
*);
35 struct unixuid_private
{
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 (samba_setgroups(sec
->ngroups
, sec
->groups
) != 0) {
79 DBG_ERR("*** samba_setgroups failed\n");
80 return NT_STATUS_ACCESS_DENIED
;
82 if (samba_setegid(sec
->gid
) != 0) {
83 DBG_ERR("*** samba_setegid(%u) failed\n", sec
->gid
);
84 return NT_STATUS_ACCESS_DENIED
;
86 if (samba_seteuid(sec
->uid
) != 0) {
87 DBG_ERR("*** samba_seteuid(%u) failed\n", sec
->uid
);
88 return NT_STATUS_ACCESS_DENIED
;
93 static int unixuid_nesting_level
;
96 called at the start and end of a tevent nesting loop. Needs to save/restore
99 static int unixuid_event_nesting_hook(struct tevent_context
*ev
,
104 const char *location
)
106 struct security_unix_token
*sec_ctx
;
108 if (unixuid_nesting_level
== 0) {
109 /* we don't need to do anything unless we are nested
110 inside of a call in this module */
115 sec_ctx
= save_unix_security(ev
);
116 if (sec_ctx
== NULL
) {
117 DEBUG(0,("%s: Failed to save security context\n", location
));
120 *(struct security_unix_token
**)stack_ptr
= sec_ctx
;
121 if (samba_seteuid(0) != 0 || samba_setegid(0) != 0) {
122 DEBUG(0,("%s: Failed to change to root\n", location
));
126 /* called when we come out of a nesting level */
129 sec_ctx
= *(struct security_unix_token
**)stack_ptr
;
130 if (sec_ctx
== NULL
) {
131 /* this happens the first time this function
132 is called, as we install the hook while
133 inside an event in unixuid_connect() */
137 sec_ctx
= talloc_get_type_abort(sec_ctx
, struct security_unix_token
);
138 status
= set_unix_security(sec_ctx
);
139 talloc_free(sec_ctx
);
140 if (!NT_STATUS_IS_OK(status
)) {
141 DEBUG(0,("%s: Failed to revert security context (%s)\n",
142 location
, nt_errstr(status
)));
152 form a security_unix_token from the current security_token
154 static NTSTATUS
nt_token_to_unix_security(struct ntvfs_module_context
*ntvfs
,
155 struct ntvfs_request
*req
,
156 struct security_token
*token
,
157 struct security_unix_token
**sec
)
159 return security_token_to_unix_token(req
, token
, sec
);
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
->last_sec_ctx
= NULL
;
245 priv
->last_token
= NULL
;
246 ntvfs
->private_data
= priv
;
248 tevent_loop_set_nesting_hook(ntvfs
->ctx
->event_ctx
,
249 unixuid_event_nesting_hook
,
250 &unixuid_nesting_level
);
252 /* we don't use PASS_THRU_REQ here, as the connect operation runs with
253 root privileges. This allows the backends to setup any database
254 links they might need during the connect. */
255 status
= ntvfs_next_connect(ntvfs
, req
, tcon
);
261 disconnect from a share
263 static NTSTATUS
unixuid_disconnect(struct ntvfs_module_context
*ntvfs
)
265 struct unixuid_private
*priv
= ntvfs
->private_data
;
269 ntvfs
->private_data
= NULL
;
271 status
= ntvfs_next_disconnect(ntvfs
);
280 static NTSTATUS
unixuid_unlink(struct ntvfs_module_context
*ntvfs
,
281 struct ntvfs_request
*req
,
282 union smb_unlink
*unl
)
286 PASS_THRU_REQ(ntvfs
, req
, unlink
, (ntvfs
, req
, unl
));
294 static NTSTATUS
unixuid_ioctl(struct ntvfs_module_context
*ntvfs
,
295 struct ntvfs_request
*req
, union smb_ioctl
*io
)
299 PASS_THRU_REQ(ntvfs
, req
, ioctl
, (ntvfs
, req
, io
));
305 check if a directory exists
307 static NTSTATUS
unixuid_chkpath(struct ntvfs_module_context
*ntvfs
,
308 struct ntvfs_request
*req
,
309 union smb_chkpath
*cp
)
313 PASS_THRU_REQ(ntvfs
, req
, chkpath
, (ntvfs
, req
, cp
));
319 return info on a pathname
321 static NTSTATUS
unixuid_qpathinfo(struct ntvfs_module_context
*ntvfs
,
322 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
326 PASS_THRU_REQ(ntvfs
, req
, qpathinfo
, (ntvfs
, req
, info
));
332 query info on a open file
334 static NTSTATUS
unixuid_qfileinfo(struct ntvfs_module_context
*ntvfs
,
335 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
339 PASS_THRU_REQ(ntvfs
, req
, qfileinfo
, (ntvfs
, req
, info
));
346 set info on a pathname
348 static NTSTATUS
unixuid_setpathinfo(struct ntvfs_module_context
*ntvfs
,
349 struct ntvfs_request
*req
, union smb_setfileinfo
*st
)
353 PASS_THRU_REQ(ntvfs
, req
, setpathinfo
, (ntvfs
, req
, st
));
361 static NTSTATUS
unixuid_open(struct ntvfs_module_context
*ntvfs
,
362 struct ntvfs_request
*req
, union smb_open
*io
)
366 PASS_THRU_REQ(ntvfs
, req
, open
, (ntvfs
, req
, io
));
374 static NTSTATUS
unixuid_mkdir(struct ntvfs_module_context
*ntvfs
,
375 struct ntvfs_request
*req
, union smb_mkdir
*md
)
379 PASS_THRU_REQ(ntvfs
, req
, mkdir
, (ntvfs
, req
, md
));
387 static NTSTATUS
unixuid_rmdir(struct ntvfs_module_context
*ntvfs
,
388 struct ntvfs_request
*req
, struct smb_rmdir
*rd
)
392 PASS_THRU_REQ(ntvfs
, req
, rmdir
, (ntvfs
, req
, rd
));
398 rename a set of files
400 static NTSTATUS
unixuid_rename(struct ntvfs_module_context
*ntvfs
,
401 struct ntvfs_request
*req
, union smb_rename
*ren
)
405 PASS_THRU_REQ(ntvfs
, req
, rename
, (ntvfs
, req
, ren
));
413 static NTSTATUS
unixuid_copy(struct ntvfs_module_context
*ntvfs
,
414 struct ntvfs_request
*req
, struct smb_copy
*cp
)
418 PASS_THRU_REQ(ntvfs
, req
, copy
, (ntvfs
, req
, cp
));
426 static NTSTATUS
unixuid_read(struct ntvfs_module_context
*ntvfs
,
427 struct ntvfs_request
*req
, union smb_read
*rd
)
431 PASS_THRU_REQ(ntvfs
, req
, read
, (ntvfs
, req
, rd
));
439 static NTSTATUS
unixuid_write(struct ntvfs_module_context
*ntvfs
,
440 struct ntvfs_request
*req
, union smb_write
*wr
)
444 PASS_THRU_REQ(ntvfs
, req
, write
, (ntvfs
, req
, wr
));
452 static NTSTATUS
unixuid_seek(struct ntvfs_module_context
*ntvfs
,
453 struct ntvfs_request
*req
,
458 PASS_THRU_REQ(ntvfs
, req
, seek
, (ntvfs
, req
, io
));
466 static NTSTATUS
unixuid_flush(struct ntvfs_module_context
*ntvfs
,
467 struct ntvfs_request
*req
,
472 PASS_THRU_REQ(ntvfs
, req
, flush
, (ntvfs
, req
, io
));
480 static NTSTATUS
unixuid_close(struct ntvfs_module_context
*ntvfs
,
481 struct ntvfs_request
*req
, union smb_close
*io
)
485 PASS_THRU_REQ(ntvfs
, req
, close
, (ntvfs
, req
, io
));
493 static NTSTATUS
unixuid_exit(struct ntvfs_module_context
*ntvfs
,
494 struct ntvfs_request
*req
)
498 PASS_THRU_REQ(ntvfs
, req
, exit
, (ntvfs
, req
));
504 logoff - closing files
506 static NTSTATUS
unixuid_logoff(struct ntvfs_module_context
*ntvfs
,
507 struct ntvfs_request
*req
)
509 struct unixuid_private
*priv
= ntvfs
->private_data
;
512 PASS_THRU_REQ(ntvfs
, req
, logoff
, (ntvfs
, req
));
514 priv
->last_token
= NULL
;
522 static NTSTATUS
unixuid_async_setup(struct ntvfs_module_context
*ntvfs
,
523 struct ntvfs_request
*req
,
528 PASS_THRU_REQ(ntvfs
, req
, async_setup
, (ntvfs
, req
, private_data
));
534 cancel an async request
536 static NTSTATUS
unixuid_cancel(struct ntvfs_module_context
*ntvfs
,
537 struct ntvfs_request
*req
)
541 PASS_THRU_REQ(ntvfs
, req
, cancel
, (ntvfs
, req
));
549 static NTSTATUS
unixuid_notify(struct ntvfs_module_context
*ntvfs
,
550 struct ntvfs_request
*req
, union smb_notify
*info
)
554 PASS_THRU_REQ(ntvfs
, req
, notify
, (ntvfs
, req
, info
));
562 static NTSTATUS
unixuid_lock(struct ntvfs_module_context
*ntvfs
,
563 struct ntvfs_request
*req
, union smb_lock
*lck
)
567 PASS_THRU_REQ(ntvfs
, req
, lock
, (ntvfs
, req
, lck
));
573 set info on a open file
575 static NTSTATUS
unixuid_setfileinfo(struct ntvfs_module_context
*ntvfs
,
576 struct ntvfs_request
*req
,
577 union smb_setfileinfo
*info
)
581 PASS_THRU_REQ(ntvfs
, req
, setfileinfo
, (ntvfs
, req
, info
));
588 return filesystem space info
590 static NTSTATUS
unixuid_fsinfo(struct ntvfs_module_context
*ntvfs
,
591 struct ntvfs_request
*req
, union smb_fsinfo
*fs
)
595 PASS_THRU_REQ(ntvfs
, req
, fsinfo
, (ntvfs
, req
, fs
));
601 return print queue info
603 static NTSTATUS
unixuid_lpq(struct ntvfs_module_context
*ntvfs
,
604 struct ntvfs_request
*req
, union smb_lpq
*lpq
)
608 PASS_THRU_REQ(ntvfs
, req
, lpq
, (ntvfs
, req
, lpq
));
614 list files in a directory matching a wildcard pattern
616 static NTSTATUS
unixuid_search_first(struct ntvfs_module_context
*ntvfs
,
617 struct ntvfs_request
*req
, union smb_search_first
*io
,
618 void *search_private
,
619 bool (*callback
)(void *, const union smb_search_data
*))
623 PASS_THRU_REQ(ntvfs
, req
, search_first
, (ntvfs
, req
, io
, search_private
, callback
));
628 /* continue a search */
629 static NTSTATUS
unixuid_search_next(struct ntvfs_module_context
*ntvfs
,
630 struct ntvfs_request
*req
, union smb_search_next
*io
,
631 void *search_private
,
632 bool (*callback
)(void *, const union smb_search_data
*))
636 PASS_THRU_REQ(ntvfs
, req
, search_next
, (ntvfs
, req
, io
, search_private
, callback
));
642 static NTSTATUS
unixuid_search_close(struct ntvfs_module_context
*ntvfs
,
643 struct ntvfs_request
*req
, union smb_search_close
*io
)
647 PASS_THRU_REQ(ntvfs
, req
, search_close
, (ntvfs
, req
, io
));
652 /* SMBtrans - not used on file shares */
653 static NTSTATUS
unixuid_trans(struct ntvfs_module_context
*ntvfs
,
654 struct ntvfs_request
*req
, struct smb_trans2
*trans2
)
658 PASS_THRU_REQ(ntvfs
, req
, trans
, (ntvfs
, req
, trans2
));
664 initialise the unixuid backend, registering ourselves with the ntvfs subsystem
666 NTSTATUS
ntvfs_unixuid_init(TALLOC_CTX
*ctx
)
669 struct ntvfs_ops ops
;
670 NTVFS_CURRENT_CRITICAL_SIZES(vers
);
674 /* fill in all the operations */
675 ops
.connect_fn
= unixuid_connect
;
676 ops
.disconnect_fn
= unixuid_disconnect
;
677 ops
.unlink_fn
= unixuid_unlink
;
678 ops
.chkpath_fn
= unixuid_chkpath
;
679 ops
.qpathinfo_fn
= unixuid_qpathinfo
;
680 ops
.setpathinfo_fn
= unixuid_setpathinfo
;
681 ops
.open_fn
= unixuid_open
;
682 ops
.mkdir_fn
= unixuid_mkdir
;
683 ops
.rmdir_fn
= unixuid_rmdir
;
684 ops
.rename_fn
= unixuid_rename
;
685 ops
.copy_fn
= unixuid_copy
;
686 ops
.ioctl_fn
= unixuid_ioctl
;
687 ops
.read_fn
= unixuid_read
;
688 ops
.write_fn
= unixuid_write
;
689 ops
.seek_fn
= unixuid_seek
;
690 ops
.flush_fn
= unixuid_flush
;
691 ops
.close_fn
= unixuid_close
;
692 ops
.exit_fn
= unixuid_exit
;
693 ops
.lock_fn
= unixuid_lock
;
694 ops
.setfileinfo_fn
= unixuid_setfileinfo
;
695 ops
.qfileinfo_fn
= unixuid_qfileinfo
;
696 ops
.fsinfo_fn
= unixuid_fsinfo
;
697 ops
.lpq_fn
= unixuid_lpq
;
698 ops
.search_first_fn
= unixuid_search_first
;
699 ops
.search_next_fn
= unixuid_search_next
;
700 ops
.search_close_fn
= unixuid_search_close
;
701 ops
.trans_fn
= unixuid_trans
;
702 ops
.logoff_fn
= unixuid_logoff
;
703 ops
.async_setup_fn
= unixuid_async_setup
;
704 ops
.cancel_fn
= unixuid_cancel
;
705 ops
.notify_fn
= unixuid_notify
;
707 ops
.name
= "unixuid";
709 /* we register under all 3 backend types, as we are not type specific */
710 ops
.type
= NTVFS_DISK
;
711 ret
= ntvfs_register(&ops
, &vers
);
712 if (!NT_STATUS_IS_OK(ret
)) goto failed
;
714 ops
.type
= NTVFS_PRINT
;
715 ret
= ntvfs_register(&ops
, &vers
);
716 if (!NT_STATUS_IS_OK(ret
)) goto failed
;
718 ops
.type
= NTVFS_IPC
;
719 ret
= ntvfs_register(&ops
, &vers
);
720 if (!NT_STATUS_IS_OK(ret
)) goto failed
;