ntvfs: Use security_unix_token from auth.idl
[Samba.git] / source4 / ntvfs / unixuid / vfs_unixuid.c
blob02b7cb8db52252a89d3e57ae9900329229fa75fd
1 /*
2 Unix SMB/CIFS implementation.
4 a pass-thru NTVFS module to setup a security context using unix
5 uid/gid
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/>.
23 #include "includes.h"
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
30 #include <tevent.h>
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"
36 #endif
37 #else
38 #define uwrap_enabled() 0
39 #endif
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);
57 if (sec == NULL) {
58 return NULL;
60 sec->uid = geteuid();
61 sec->gid = getegid();
62 sec->ngroups = getgroups(0, NULL);
63 if (sec->ngroups == -1) {
64 talloc_free(sec);
65 return NULL;
67 sec->groups = talloc_array(sec, gid_t, sec->ngroups);
68 if (sec->groups == NULL) {
69 talloc_free(sec);
70 return NULL;
73 if (getgroups(sec->ngroups, sec->groups) != sec->ngroups) {
74 talloc_free(sec);
75 return NULL;
78 return sec;
82 set the current security context from a security_unix_token
84 static NTSTATUS set_unix_security(struct security_unix_token *sec)
86 seteuid(0);
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;
97 return NT_STATUS_OK;
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,
107 void *private_data,
108 uint32_t level,
109 bool begin,
110 void *stack_ptr,
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 */
118 return 0;
121 if (begin) {
122 sec_ctx = save_unix_security(ev);
123 if (sec_ctx == NULL) {
124 DEBUG(0,("%s: Failed to save security context\n", location));
125 return -1;
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));
130 return -1;
132 } else {
133 /* called when we come out of a nesting level */
134 NTSTATUS status;
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() */
141 return 0;
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)));
150 return -1;
154 return 0;
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;
167 int i;
168 NTSTATUS status;
169 struct id_map *ids;
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;
200 } else {
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;
207 } else {
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;
215 } else {
216 return NT_STATUS_INVALID_SID;
220 return NT_STATUS_OK;
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;
232 NTSTATUS status;
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);
244 if (*sec == NULL) {
245 return NT_STATUS_NO_MEMORY;
248 if (token == priv->last_token) {
249 newsec = priv->last_sec_ctx;
250 } else {
251 status = nt_token_to_unix_security(ntvfs, req, token, &newsec);
252 if (!NT_STATUS_IS_OK(status)) {
253 talloc_free(*sec);
254 return 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)) {
266 talloc_free(*sec);
267 return status;
270 return NT_STATUS_OK;
274 this pass through macro operates on request contexts
276 #define PASS_THRU_REQ(ntvfs, req, op, args) do { \
277 NTSTATUS status2; \
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); \
285 talloc_free(sec); \
286 if (!NT_STATUS_IS_OK(status2)) smb_panic("Unable to reset security context"); \
287 } while (0)
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;
298 NTSTATUS status;
300 priv = talloc(ntvfs, struct unixuid_private);
301 if (!priv) {
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) {
308 talloc_free(priv);
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);
325 return status;
329 disconnect from a share
331 static NTSTATUS unixuid_disconnect(struct ntvfs_module_context *ntvfs)
333 struct unixuid_private *priv = ntvfs->private_data;
334 NTSTATUS status;
336 talloc_free(priv);
337 ntvfs->private_data = NULL;
339 status = ntvfs_next_disconnect(ntvfs);
341 return status;
346 delete a file
348 static NTSTATUS unixuid_unlink(struct ntvfs_module_context *ntvfs,
349 struct ntvfs_request *req,
350 union smb_unlink *unl)
352 NTSTATUS status;
354 PASS_THRU_REQ(ntvfs, req, unlink, (ntvfs, req, unl));
356 return status;
360 ioctl interface
362 static NTSTATUS unixuid_ioctl(struct ntvfs_module_context *ntvfs,
363 struct ntvfs_request *req, union smb_ioctl *io)
365 NTSTATUS status;
367 PASS_THRU_REQ(ntvfs, req, ioctl, (ntvfs, req, io));
369 return status;
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)
379 NTSTATUS status;
381 PASS_THRU_REQ(ntvfs, req, chkpath, (ntvfs, req, cp));
383 return status;
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)
392 NTSTATUS status;
394 PASS_THRU_REQ(ntvfs, req, qpathinfo, (ntvfs, req, info));
396 return status;
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)
405 NTSTATUS status;
407 PASS_THRU_REQ(ntvfs, req, qfileinfo, (ntvfs, req, info));
409 return status;
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)
419 NTSTATUS status;
421 PASS_THRU_REQ(ntvfs, req, setpathinfo, (ntvfs, req, st));
423 return status;
427 open a file
429 static NTSTATUS unixuid_open(struct ntvfs_module_context *ntvfs,
430 struct ntvfs_request *req, union smb_open *io)
432 NTSTATUS status;
434 PASS_THRU_REQ(ntvfs, req, open, (ntvfs, req, io));
436 return status;
440 create a directory
442 static NTSTATUS unixuid_mkdir(struct ntvfs_module_context *ntvfs,
443 struct ntvfs_request *req, union smb_mkdir *md)
445 NTSTATUS status;
447 PASS_THRU_REQ(ntvfs, req, mkdir, (ntvfs, req, md));
449 return status;
453 remove a directory
455 static NTSTATUS unixuid_rmdir(struct ntvfs_module_context *ntvfs,
456 struct ntvfs_request *req, struct smb_rmdir *rd)
458 NTSTATUS status;
460 PASS_THRU_REQ(ntvfs, req, rmdir, (ntvfs, req, rd));
462 return status;
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)
471 NTSTATUS status;
473 PASS_THRU_REQ(ntvfs, req, rename, (ntvfs, req, ren));
475 return status;
479 copy a set of files
481 static NTSTATUS unixuid_copy(struct ntvfs_module_context *ntvfs,
482 struct ntvfs_request *req, struct smb_copy *cp)
484 NTSTATUS status;
486 PASS_THRU_REQ(ntvfs, req, copy, (ntvfs, req, cp));
488 return status;
492 read from a file
494 static NTSTATUS unixuid_read(struct ntvfs_module_context *ntvfs,
495 struct ntvfs_request *req, union smb_read *rd)
497 NTSTATUS status;
499 PASS_THRU_REQ(ntvfs, req, read, (ntvfs, req, rd));
501 return status;
505 write to a file
507 static NTSTATUS unixuid_write(struct ntvfs_module_context *ntvfs,
508 struct ntvfs_request *req, union smb_write *wr)
510 NTSTATUS status;
512 PASS_THRU_REQ(ntvfs, req, write, (ntvfs, req, wr));
514 return status;
518 seek in a file
520 static NTSTATUS unixuid_seek(struct ntvfs_module_context *ntvfs,
521 struct ntvfs_request *req,
522 union smb_seek *io)
524 NTSTATUS status;
526 PASS_THRU_REQ(ntvfs, req, seek, (ntvfs, req, io));
528 return status;
532 flush a file
534 static NTSTATUS unixuid_flush(struct ntvfs_module_context *ntvfs,
535 struct ntvfs_request *req,
536 union smb_flush *io)
538 NTSTATUS status;
540 PASS_THRU_REQ(ntvfs, req, flush, (ntvfs, req, io));
542 return status;
546 close a file
548 static NTSTATUS unixuid_close(struct ntvfs_module_context *ntvfs,
549 struct ntvfs_request *req, union smb_close *io)
551 NTSTATUS status;
553 PASS_THRU_REQ(ntvfs, req, close, (ntvfs, req, io));
555 return status;
559 exit - closing files
561 static NTSTATUS unixuid_exit(struct ntvfs_module_context *ntvfs,
562 struct ntvfs_request *req)
564 NTSTATUS status;
566 PASS_THRU_REQ(ntvfs, req, exit, (ntvfs, req));
568 return status;
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;
578 NTSTATUS status;
580 PASS_THRU_REQ(ntvfs, req, logoff, (ntvfs, req));
582 priv->last_token = NULL;
584 return status;
588 async setup
590 static NTSTATUS unixuid_async_setup(struct ntvfs_module_context *ntvfs,
591 struct ntvfs_request *req,
592 void *private_data)
594 NTSTATUS status;
596 PASS_THRU_REQ(ntvfs, req, async_setup, (ntvfs, req, private_data));
598 return status;
602 cancel an async request
604 static NTSTATUS unixuid_cancel(struct ntvfs_module_context *ntvfs,
605 struct ntvfs_request *req)
607 NTSTATUS status;
609 PASS_THRU_REQ(ntvfs, req, cancel, (ntvfs, req));
611 return status;
615 change notify
617 static NTSTATUS unixuid_notify(struct ntvfs_module_context *ntvfs,
618 struct ntvfs_request *req, union smb_notify *info)
620 NTSTATUS status;
622 PASS_THRU_REQ(ntvfs, req, notify, (ntvfs, req, info));
624 return status;
628 lock a byte range
630 static NTSTATUS unixuid_lock(struct ntvfs_module_context *ntvfs,
631 struct ntvfs_request *req, union smb_lock *lck)
633 NTSTATUS status;
635 PASS_THRU_REQ(ntvfs, req, lock, (ntvfs, req, lck));
637 return status;
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)
647 NTSTATUS status;
649 PASS_THRU_REQ(ntvfs, req, setfileinfo, (ntvfs, req, info));
651 return status;
656 return filesystem space info
658 static NTSTATUS unixuid_fsinfo(struct ntvfs_module_context *ntvfs,
659 struct ntvfs_request *req, union smb_fsinfo *fs)
661 NTSTATUS status;
663 PASS_THRU_REQ(ntvfs, req, fsinfo, (ntvfs, req, fs));
665 return status;
669 return print queue info
671 static NTSTATUS unixuid_lpq(struct ntvfs_module_context *ntvfs,
672 struct ntvfs_request *req, union smb_lpq *lpq)
674 NTSTATUS status;
676 PASS_THRU_REQ(ntvfs, req, lpq, (ntvfs, req, lpq));
678 return status;
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 *))
689 NTSTATUS status;
691 PASS_THRU_REQ(ntvfs, req, search_first, (ntvfs, req, io, search_private, callback));
693 return status;
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 *))
702 NTSTATUS status;
704 PASS_THRU_REQ(ntvfs, req, search_next, (ntvfs, req, io, search_private, callback));
706 return status;
709 /* close a search */
710 static NTSTATUS unixuid_search_close(struct ntvfs_module_context *ntvfs,
711 struct ntvfs_request *req, union smb_search_close *io)
713 NTSTATUS status;
715 PASS_THRU_REQ(ntvfs, req, search_close, (ntvfs, req, io));
717 return status;
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)
724 NTSTATUS status;
726 PASS_THRU_REQ(ntvfs, req, trans, (ntvfs, req, trans2));
728 return status;
732 initialise the unixuid backend, registering ourselves with the ntvfs subsystem
734 NTSTATUS ntvfs_unixuid_init(void)
736 NTSTATUS ret;
737 struct ntvfs_ops ops;
738 NTVFS_CURRENT_CRITICAL_SIZES(vers);
740 ZERO_STRUCT(ops);
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;
790 failed:
791 return ret;