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 #if defined(UID_WRAPPER)
33 #if !defined(UID_WRAPPER_REPLACE) && !defined(UID_WRAPPER_NOT_REPLACE)
34 #define UID_WRAPPER_REPLACE
35 #include "../uid_wrapper/uid_wrapper.h"
38 #define uwrap_enabled() 0
42 NTSTATUS
ntvfs_unixuid_init(void);
44 struct unixuid_private
{
45 struct wbc_context
*wbc_ctx
;
46 struct security_unix_token
*last_sec_ctx
;
47 struct security_token
*last_token
;
52 pull the current security context into a security_unix_token
54 static struct security_unix_token
*save_unix_security(TALLOC_CTX
*mem_ctx
)
56 struct security_unix_token
*sec
= talloc(mem_ctx
, struct security_unix_token
);
62 sec
->ngroups
= getgroups(0, NULL
);
63 if (sec
->ngroups
== -1) {
67 sec
->groups
= talloc_array(sec
, gid_t
, sec
->ngroups
);
68 if (sec
->groups
== NULL
) {
73 if (getgroups(sec
->ngroups
, sec
->groups
) != sec
->ngroups
) {
82 set the current security context from a security_unix_token
84 static NTSTATUS
set_unix_security(struct security_unix_token
*sec
)
88 if (setgroups(sec
->ngroups
, sec
->groups
) != 0) {
89 return NT_STATUS_ACCESS_DENIED
;
91 if (setegid(sec
->gid
) != 0) {
92 return NT_STATUS_ACCESS_DENIED
;
94 if (seteuid(sec
->uid
) != 0) {
95 return NT_STATUS_ACCESS_DENIED
;
100 static int unixuid_nesting_level
;
103 called at the start and end of a tevent nesting loop. Needs to save/restore
104 unix security context
106 static int unixuid_event_nesting_hook(struct tevent_context
*ev
,
111 const char *location
)
113 struct security_unix_token
*sec_ctx
;
115 if (unixuid_nesting_level
== 0) {
116 /* we don't need to do anything unless we are nested
117 inside of a call in this module */
122 sec_ctx
= save_unix_security(ev
);
123 if (sec_ctx
== NULL
) {
124 DEBUG(0,("%s: Failed to save security context\n", location
));
127 *(struct security_unix_token
**)stack_ptr
= sec_ctx
;
128 if (seteuid(0) != 0 || setegid(0) != 0) {
129 DEBUG(0,("%s: Failed to change to root\n", location
));
133 /* called when we come out of a nesting level */
136 sec_ctx
= *(struct security_unix_token
**)stack_ptr
;
137 if (sec_ctx
== NULL
) {
138 /* this happens the first time this function
139 is called, as we install the hook while
140 inside an event in unixuid_connect() */
144 sec_ctx
= talloc_get_type_abort(sec_ctx
, struct security_unix_token
);
145 status
= set_unix_security(sec_ctx
);
146 talloc_free(sec_ctx
);
147 if (!NT_STATUS_IS_OK(status
)) {
148 DEBUG(0,("%s: Failed to revert security context (%s)\n",
149 location
, nt_errstr(status
)));
159 form a security_unix_token from the current security_token
161 static NTSTATUS
nt_token_to_unix_security(struct ntvfs_module_context
*ntvfs
,
162 struct ntvfs_request
*req
,
163 struct security_token
*token
,
164 struct security_unix_token
**sec
)
166 struct unixuid_private
*priv
= ntvfs
->private_data
;
170 struct composite_context
*ctx
;
171 *sec
= talloc(req
, struct security_unix_token
);
173 /* we can't do unix security without a user and group */
174 if (token
->num_sids
< 2) {
175 return NT_STATUS_ACCESS_DENIED
;
178 ids
= talloc_array(req
, struct id_map
, token
->num_sids
);
179 NT_STATUS_HAVE_NO_MEMORY(ids
);
181 (*sec
)->ngroups
= token
->num_sids
- 2;
182 (*sec
)->groups
= talloc_array(*sec
, gid_t
, (*sec
)->ngroups
);
183 NT_STATUS_HAVE_NO_MEMORY((*sec
)->groups
);
185 for (i
=0;i
<token
->num_sids
;i
++) {
186 ZERO_STRUCT(ids
[i
].xid
);
187 ids
[i
].sid
= &token
->sids
[i
];
188 ids
[i
].status
= ID_UNKNOWN
;
191 ctx
= wbc_sids_to_xids_send(priv
->wbc_ctx
, ids
, token
->num_sids
, ids
);
192 NT_STATUS_HAVE_NO_MEMORY(ctx
);
194 status
= wbc_sids_to_xids_recv(ctx
, &ids
);
195 NT_STATUS_NOT_OK_RETURN(status
);
197 if (ids
[0].xid
.type
== ID_TYPE_BOTH
||
198 ids
[0].xid
.type
== ID_TYPE_UID
) {
199 (*sec
)->uid
= ids
[0].xid
.id
;
201 return NT_STATUS_INVALID_SID
;
204 if (ids
[1].xid
.type
== ID_TYPE_BOTH
||
205 ids
[1].xid
.type
== ID_TYPE_GID
) {
206 (*sec
)->gid
= ids
[1].xid
.id
;
208 return NT_STATUS_INVALID_SID
;
211 for (i
=0;i
<(*sec
)->ngroups
;i
++) {
212 if (ids
[i
+2].xid
.type
== ID_TYPE_BOTH
||
213 ids
[i
+2].xid
.type
== ID_TYPE_GID
) {
214 (*sec
)->groups
[i
] = ids
[i
+2].xid
.id
;
216 return NT_STATUS_INVALID_SID
;
224 setup our unix security context according to the session authentication info
226 static NTSTATUS
unixuid_setup_security(struct ntvfs_module_context
*ntvfs
,
227 struct ntvfs_request
*req
, struct security_unix_token
**sec
)
229 struct unixuid_private
*priv
= ntvfs
->private_data
;
230 struct security_token
*token
;
231 struct security_unix_token
*newsec
;
234 /* If we are asked to set up, but have not had a successful
235 * session setup or tree connect, then these may not be filled
236 * in. ACCESS_DENIED is the right error code here */
237 if (req
->session_info
== NULL
|| priv
== NULL
) {
238 return NT_STATUS_ACCESS_DENIED
;
241 token
= req
->session_info
->security_token
;
243 *sec
= save_unix_security(ntvfs
);
245 return NT_STATUS_NO_MEMORY
;
248 if (token
== priv
->last_token
) {
249 newsec
= priv
->last_sec_ctx
;
251 status
= nt_token_to_unix_security(ntvfs
, req
, token
, &newsec
);
252 if (!NT_STATUS_IS_OK(status
)) {
256 if (priv
->last_sec_ctx
) {
257 talloc_free(priv
->last_sec_ctx
);
259 priv
->last_sec_ctx
= newsec
;
260 priv
->last_token
= token
;
261 talloc_steal(priv
, newsec
);
264 status
= set_unix_security(newsec
);
265 if (!NT_STATUS_IS_OK(status
)) {
274 this pass through macro operates on request contexts
276 #define PASS_THRU_REQ(ntvfs, req, op, args) do { \
278 struct security_unix_token *sec; \
279 status = unixuid_setup_security(ntvfs, req, &sec); \
280 NT_STATUS_NOT_OK_RETURN(status); \
281 unixuid_nesting_level++; \
282 status = ntvfs_next_##op args; \
283 unixuid_nesting_level--; \
284 status2 = set_unix_security(sec); \
286 if (!NT_STATUS_IS_OK(status2)) smb_panic("Unable to reset security context"); \
292 connect to a share - used when a tree_connect operation comes in.
294 static NTSTATUS
unixuid_connect(struct ntvfs_module_context
*ntvfs
,
295 struct ntvfs_request
*req
, union smb_tcon
*tcon
)
297 struct unixuid_private
*priv
;
300 priv
= talloc(ntvfs
, struct unixuid_private
);
302 return NT_STATUS_NO_MEMORY
;
305 priv
->wbc_ctx
= wbc_init(priv
, ntvfs
->ctx
->msg_ctx
,
306 ntvfs
->ctx
->event_ctx
);
307 if (priv
->wbc_ctx
== NULL
) {
309 return NT_STATUS_INTERNAL_ERROR
;
312 priv
->last_sec_ctx
= NULL
;
313 priv
->last_token
= NULL
;
314 ntvfs
->private_data
= priv
;
316 tevent_loop_set_nesting_hook(ntvfs
->ctx
->event_ctx
,
317 unixuid_event_nesting_hook
,
318 &unixuid_nesting_level
);
320 /* we don't use PASS_THRU_REQ here, as the connect operation runs with
321 root privileges. This allows the backends to setup any database
322 links they might need during the connect. */
323 status
= ntvfs_next_connect(ntvfs
, req
, tcon
);
329 disconnect from a share
331 static NTSTATUS
unixuid_disconnect(struct ntvfs_module_context
*ntvfs
)
333 struct unixuid_private
*priv
= ntvfs
->private_data
;
337 ntvfs
->private_data
= NULL
;
339 status
= ntvfs_next_disconnect(ntvfs
);
348 static NTSTATUS
unixuid_unlink(struct ntvfs_module_context
*ntvfs
,
349 struct ntvfs_request
*req
,
350 union smb_unlink
*unl
)
354 PASS_THRU_REQ(ntvfs
, req
, unlink
, (ntvfs
, req
, unl
));
362 static NTSTATUS
unixuid_ioctl(struct ntvfs_module_context
*ntvfs
,
363 struct ntvfs_request
*req
, union smb_ioctl
*io
)
367 PASS_THRU_REQ(ntvfs
, req
, ioctl
, (ntvfs
, req
, io
));
373 check if a directory exists
375 static NTSTATUS
unixuid_chkpath(struct ntvfs_module_context
*ntvfs
,
376 struct ntvfs_request
*req
,
377 union smb_chkpath
*cp
)
381 PASS_THRU_REQ(ntvfs
, req
, chkpath
, (ntvfs
, req
, cp
));
387 return info on a pathname
389 static NTSTATUS
unixuid_qpathinfo(struct ntvfs_module_context
*ntvfs
,
390 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
394 PASS_THRU_REQ(ntvfs
, req
, qpathinfo
, (ntvfs
, req
, info
));
400 query info on a open file
402 static NTSTATUS
unixuid_qfileinfo(struct ntvfs_module_context
*ntvfs
,
403 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
407 PASS_THRU_REQ(ntvfs
, req
, qfileinfo
, (ntvfs
, req
, info
));
414 set info on a pathname
416 static NTSTATUS
unixuid_setpathinfo(struct ntvfs_module_context
*ntvfs
,
417 struct ntvfs_request
*req
, union smb_setfileinfo
*st
)
421 PASS_THRU_REQ(ntvfs
, req
, setpathinfo
, (ntvfs
, req
, st
));
429 static NTSTATUS
unixuid_open(struct ntvfs_module_context
*ntvfs
,
430 struct ntvfs_request
*req
, union smb_open
*io
)
434 PASS_THRU_REQ(ntvfs
, req
, open
, (ntvfs
, req
, io
));
442 static NTSTATUS
unixuid_mkdir(struct ntvfs_module_context
*ntvfs
,
443 struct ntvfs_request
*req
, union smb_mkdir
*md
)
447 PASS_THRU_REQ(ntvfs
, req
, mkdir
, (ntvfs
, req
, md
));
455 static NTSTATUS
unixuid_rmdir(struct ntvfs_module_context
*ntvfs
,
456 struct ntvfs_request
*req
, struct smb_rmdir
*rd
)
460 PASS_THRU_REQ(ntvfs
, req
, rmdir
, (ntvfs
, req
, rd
));
466 rename a set of files
468 static NTSTATUS
unixuid_rename(struct ntvfs_module_context
*ntvfs
,
469 struct ntvfs_request
*req
, union smb_rename
*ren
)
473 PASS_THRU_REQ(ntvfs
, req
, rename
, (ntvfs
, req
, ren
));
481 static NTSTATUS
unixuid_copy(struct ntvfs_module_context
*ntvfs
,
482 struct ntvfs_request
*req
, struct smb_copy
*cp
)
486 PASS_THRU_REQ(ntvfs
, req
, copy
, (ntvfs
, req
, cp
));
494 static NTSTATUS
unixuid_read(struct ntvfs_module_context
*ntvfs
,
495 struct ntvfs_request
*req
, union smb_read
*rd
)
499 PASS_THRU_REQ(ntvfs
, req
, read
, (ntvfs
, req
, rd
));
507 static NTSTATUS
unixuid_write(struct ntvfs_module_context
*ntvfs
,
508 struct ntvfs_request
*req
, union smb_write
*wr
)
512 PASS_THRU_REQ(ntvfs
, req
, write
, (ntvfs
, req
, wr
));
520 static NTSTATUS
unixuid_seek(struct ntvfs_module_context
*ntvfs
,
521 struct ntvfs_request
*req
,
526 PASS_THRU_REQ(ntvfs
, req
, seek
, (ntvfs
, req
, io
));
534 static NTSTATUS
unixuid_flush(struct ntvfs_module_context
*ntvfs
,
535 struct ntvfs_request
*req
,
540 PASS_THRU_REQ(ntvfs
, req
, flush
, (ntvfs
, req
, io
));
548 static NTSTATUS
unixuid_close(struct ntvfs_module_context
*ntvfs
,
549 struct ntvfs_request
*req
, union smb_close
*io
)
553 PASS_THRU_REQ(ntvfs
, req
, close
, (ntvfs
, req
, io
));
561 static NTSTATUS
unixuid_exit(struct ntvfs_module_context
*ntvfs
,
562 struct ntvfs_request
*req
)
566 PASS_THRU_REQ(ntvfs
, req
, exit
, (ntvfs
, req
));
572 logoff - closing files
574 static NTSTATUS
unixuid_logoff(struct ntvfs_module_context
*ntvfs
,
575 struct ntvfs_request
*req
)
577 struct unixuid_private
*priv
= ntvfs
->private_data
;
580 PASS_THRU_REQ(ntvfs
, req
, logoff
, (ntvfs
, req
));
582 priv
->last_token
= NULL
;
590 static NTSTATUS
unixuid_async_setup(struct ntvfs_module_context
*ntvfs
,
591 struct ntvfs_request
*req
,
596 PASS_THRU_REQ(ntvfs
, req
, async_setup
, (ntvfs
, req
, private_data
));
602 cancel an async request
604 static NTSTATUS
unixuid_cancel(struct ntvfs_module_context
*ntvfs
,
605 struct ntvfs_request
*req
)
609 PASS_THRU_REQ(ntvfs
, req
, cancel
, (ntvfs
, req
));
617 static NTSTATUS
unixuid_notify(struct ntvfs_module_context
*ntvfs
,
618 struct ntvfs_request
*req
, union smb_notify
*info
)
622 PASS_THRU_REQ(ntvfs
, req
, notify
, (ntvfs
, req
, info
));
630 static NTSTATUS
unixuid_lock(struct ntvfs_module_context
*ntvfs
,
631 struct ntvfs_request
*req
, union smb_lock
*lck
)
635 PASS_THRU_REQ(ntvfs
, req
, lock
, (ntvfs
, req
, lck
));
641 set info on a open file
643 static NTSTATUS
unixuid_setfileinfo(struct ntvfs_module_context
*ntvfs
,
644 struct ntvfs_request
*req
,
645 union smb_setfileinfo
*info
)
649 PASS_THRU_REQ(ntvfs
, req
, setfileinfo
, (ntvfs
, req
, info
));
656 return filesystem space info
658 static NTSTATUS
unixuid_fsinfo(struct ntvfs_module_context
*ntvfs
,
659 struct ntvfs_request
*req
, union smb_fsinfo
*fs
)
663 PASS_THRU_REQ(ntvfs
, req
, fsinfo
, (ntvfs
, req
, fs
));
669 return print queue info
671 static NTSTATUS
unixuid_lpq(struct ntvfs_module_context
*ntvfs
,
672 struct ntvfs_request
*req
, union smb_lpq
*lpq
)
676 PASS_THRU_REQ(ntvfs
, req
, lpq
, (ntvfs
, req
, lpq
));
682 list files in a directory matching a wildcard pattern
684 static NTSTATUS
unixuid_search_first(struct ntvfs_module_context
*ntvfs
,
685 struct ntvfs_request
*req
, union smb_search_first
*io
,
686 void *search_private
,
687 bool (*callback
)(void *, const union smb_search_data
*))
691 PASS_THRU_REQ(ntvfs
, req
, search_first
, (ntvfs
, req
, io
, search_private
, callback
));
696 /* continue a search */
697 static NTSTATUS
unixuid_search_next(struct ntvfs_module_context
*ntvfs
,
698 struct ntvfs_request
*req
, union smb_search_next
*io
,
699 void *search_private
,
700 bool (*callback
)(void *, const union smb_search_data
*))
704 PASS_THRU_REQ(ntvfs
, req
, search_next
, (ntvfs
, req
, io
, search_private
, callback
));
710 static NTSTATUS
unixuid_search_close(struct ntvfs_module_context
*ntvfs
,
711 struct ntvfs_request
*req
, union smb_search_close
*io
)
715 PASS_THRU_REQ(ntvfs
, req
, search_close
, (ntvfs
, req
, io
));
720 /* SMBtrans - not used on file shares */
721 static NTSTATUS
unixuid_trans(struct ntvfs_module_context
*ntvfs
,
722 struct ntvfs_request
*req
, struct smb_trans2
*trans2
)
726 PASS_THRU_REQ(ntvfs
, req
, trans
, (ntvfs
, req
, trans2
));
732 initialise the unixuid backend, registering ourselves with the ntvfs subsystem
734 NTSTATUS
ntvfs_unixuid_init(void)
737 struct ntvfs_ops ops
;
738 NTVFS_CURRENT_CRITICAL_SIZES(vers
);
742 /* fill in all the operations */
743 ops
.connect
= unixuid_connect
;
744 ops
.disconnect
= unixuid_disconnect
;
745 ops
.unlink
= unixuid_unlink
;
746 ops
.chkpath
= unixuid_chkpath
;
747 ops
.qpathinfo
= unixuid_qpathinfo
;
748 ops
.setpathinfo
= unixuid_setpathinfo
;
749 ops
.open
= unixuid_open
;
750 ops
.mkdir
= unixuid_mkdir
;
751 ops
.rmdir
= unixuid_rmdir
;
752 ops
.rename
= unixuid_rename
;
753 ops
.copy
= unixuid_copy
;
754 ops
.ioctl
= unixuid_ioctl
;
755 ops
.read
= unixuid_read
;
756 ops
.write
= unixuid_write
;
757 ops
.seek
= unixuid_seek
;
758 ops
.flush
= unixuid_flush
;
759 ops
.close
= unixuid_close
;
760 ops
.exit
= unixuid_exit
;
761 ops
.lock
= unixuid_lock
;
762 ops
.setfileinfo
= unixuid_setfileinfo
;
763 ops
.qfileinfo
= unixuid_qfileinfo
;
764 ops
.fsinfo
= unixuid_fsinfo
;
765 ops
.lpq
= unixuid_lpq
;
766 ops
.search_first
= unixuid_search_first
;
767 ops
.search_next
= unixuid_search_next
;
768 ops
.search_close
= unixuid_search_close
;
769 ops
.trans
= unixuid_trans
;
770 ops
.logoff
= unixuid_logoff
;
771 ops
.async_setup
= unixuid_async_setup
;
772 ops
.cancel
= unixuid_cancel
;
773 ops
.notify
= unixuid_notify
;
775 ops
.name
= "unixuid";
777 /* we register under all 3 backend types, as we are not type specific */
778 ops
.type
= NTVFS_DISK
;
779 ret
= ntvfs_register(&ops
, &vers
);
780 if (!NT_STATUS_IS_OK(ret
)) goto failed
;
782 ops
.type
= NTVFS_PRINT
;
783 ret
= ntvfs_register(&ops
, &vers
);
784 if (!NT_STATUS_IS_OK(ret
)) goto failed
;
786 ops
.type
= NTVFS_IPC
;
787 ret
= ntvfs_register(&ops
, &vers
);
788 if (!NT_STATUS_IS_OK(ret
)) goto failed
;