s3: Slightly simplify is_stat_open
[Samba/gebeck_regimport.git] / source4 / ntvfs / unixuid / vfs_unixuid.c
blobb6da79064bb696fdc6038bd98a61260fc7cba735
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>
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);
48 if (sec == NULL) {
49 return NULL;
51 sec->uid = geteuid();
52 sec->gid = getegid();
53 sec->ngroups = getgroups(0, NULL);
54 if (sec->ngroups == -1) {
55 talloc_free(sec);
56 return NULL;
58 sec->groups = talloc_array(sec, gid_t, sec->ngroups);
59 if (sec->groups == NULL) {
60 talloc_free(sec);
61 return NULL;
64 if (getgroups(sec->ngroups, sec->groups) != sec->ngroups) {
65 talloc_free(sec);
66 return NULL;
69 return sec;
73 set the current security context from a security_unix_token
75 static NTSTATUS set_unix_security(struct security_unix_token *sec)
77 samba_seteuid(0);
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;
88 return NT_STATUS_OK;
91 static int unixuid_nesting_level;
94 called at the start and end of a tevent nesting loop. Needs to save/restore
95 unix security context
97 static int unixuid_event_nesting_hook(struct tevent_context *ev,
98 void *private_data,
99 uint32_t level,
100 bool begin,
101 void *stack_ptr,
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 */
109 return 0;
112 if (begin) {
113 sec_ctx = save_unix_security(ev);
114 if (sec_ctx == NULL) {
115 DEBUG(0,("%s: Failed to save security context\n", location));
116 return -1;
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));
121 return -1;
123 } else {
124 /* called when we come out of a nesting level */
125 NTSTATUS status;
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() */
132 return 0;
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)));
141 return -1;
145 return 0;
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,
160 priv->wbc_ctx,
161 token, sec);
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;
173 NTSTATUS status;
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);
185 if (*sec == NULL) {
186 return NT_STATUS_NO_MEMORY;
189 if (token == priv->last_token) {
190 newsec = priv->last_sec_ctx;
191 } else {
192 status = nt_token_to_unix_security(ntvfs, req, token, &newsec);
193 if (!NT_STATUS_IS_OK(status)) {
194 talloc_free(*sec);
195 return 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)) {
207 talloc_free(*sec);
208 return status;
211 return NT_STATUS_OK;
215 this pass through macro operates on request contexts
217 #define PASS_THRU_REQ(ntvfs, req, op, args) do { \
218 NTSTATUS status2; \
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); \
226 talloc_free(sec); \
227 if (!NT_STATUS_IS_OK(status2)) smb_panic("Unable to reset security context"); \
228 } while (0)
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;
239 NTSTATUS status;
241 priv = talloc(ntvfs, struct unixuid_private);
242 if (!priv) {
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) {
249 talloc_free(priv);
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);
266 return status;
270 disconnect from a share
272 static NTSTATUS unixuid_disconnect(struct ntvfs_module_context *ntvfs)
274 struct unixuid_private *priv = ntvfs->private_data;
275 NTSTATUS status;
277 talloc_free(priv);
278 ntvfs->private_data = NULL;
280 status = ntvfs_next_disconnect(ntvfs);
282 return status;
287 delete a file
289 static NTSTATUS unixuid_unlink(struct ntvfs_module_context *ntvfs,
290 struct ntvfs_request *req,
291 union smb_unlink *unl)
293 NTSTATUS status;
295 PASS_THRU_REQ(ntvfs, req, unlink, (ntvfs, req, unl));
297 return status;
301 ioctl interface
303 static NTSTATUS unixuid_ioctl(struct ntvfs_module_context *ntvfs,
304 struct ntvfs_request *req, union smb_ioctl *io)
306 NTSTATUS status;
308 PASS_THRU_REQ(ntvfs, req, ioctl, (ntvfs, req, io));
310 return status;
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)
320 NTSTATUS status;
322 PASS_THRU_REQ(ntvfs, req, chkpath, (ntvfs, req, cp));
324 return status;
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)
333 NTSTATUS status;
335 PASS_THRU_REQ(ntvfs, req, qpathinfo, (ntvfs, req, info));
337 return status;
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)
346 NTSTATUS status;
348 PASS_THRU_REQ(ntvfs, req, qfileinfo, (ntvfs, req, info));
350 return status;
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)
360 NTSTATUS status;
362 PASS_THRU_REQ(ntvfs, req, setpathinfo, (ntvfs, req, st));
364 return status;
368 open a file
370 static NTSTATUS unixuid_open(struct ntvfs_module_context *ntvfs,
371 struct ntvfs_request *req, union smb_open *io)
373 NTSTATUS status;
375 PASS_THRU_REQ(ntvfs, req, open, (ntvfs, req, io));
377 return status;
381 create a directory
383 static NTSTATUS unixuid_mkdir(struct ntvfs_module_context *ntvfs,
384 struct ntvfs_request *req, union smb_mkdir *md)
386 NTSTATUS status;
388 PASS_THRU_REQ(ntvfs, req, mkdir, (ntvfs, req, md));
390 return status;
394 remove a directory
396 static NTSTATUS unixuid_rmdir(struct ntvfs_module_context *ntvfs,
397 struct ntvfs_request *req, struct smb_rmdir *rd)
399 NTSTATUS status;
401 PASS_THRU_REQ(ntvfs, req, rmdir, (ntvfs, req, rd));
403 return status;
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)
412 NTSTATUS status;
414 PASS_THRU_REQ(ntvfs, req, rename, (ntvfs, req, ren));
416 return status;
420 copy a set of files
422 static NTSTATUS unixuid_copy(struct ntvfs_module_context *ntvfs,
423 struct ntvfs_request *req, struct smb_copy *cp)
425 NTSTATUS status;
427 PASS_THRU_REQ(ntvfs, req, copy, (ntvfs, req, cp));
429 return status;
433 read from a file
435 static NTSTATUS unixuid_read(struct ntvfs_module_context *ntvfs,
436 struct ntvfs_request *req, union smb_read *rd)
438 NTSTATUS status;
440 PASS_THRU_REQ(ntvfs, req, read, (ntvfs, req, rd));
442 return status;
446 write to a file
448 static NTSTATUS unixuid_write(struct ntvfs_module_context *ntvfs,
449 struct ntvfs_request *req, union smb_write *wr)
451 NTSTATUS status;
453 PASS_THRU_REQ(ntvfs, req, write, (ntvfs, req, wr));
455 return status;
459 seek in a file
461 static NTSTATUS unixuid_seek(struct ntvfs_module_context *ntvfs,
462 struct ntvfs_request *req,
463 union smb_seek *io)
465 NTSTATUS status;
467 PASS_THRU_REQ(ntvfs, req, seek, (ntvfs, req, io));
469 return status;
473 flush a file
475 static NTSTATUS unixuid_flush(struct ntvfs_module_context *ntvfs,
476 struct ntvfs_request *req,
477 union smb_flush *io)
479 NTSTATUS status;
481 PASS_THRU_REQ(ntvfs, req, flush, (ntvfs, req, io));
483 return status;
487 close a file
489 static NTSTATUS unixuid_close(struct ntvfs_module_context *ntvfs,
490 struct ntvfs_request *req, union smb_close *io)
492 NTSTATUS status;
494 PASS_THRU_REQ(ntvfs, req, close, (ntvfs, req, io));
496 return status;
500 exit - closing files
502 static NTSTATUS unixuid_exit(struct ntvfs_module_context *ntvfs,
503 struct ntvfs_request *req)
505 NTSTATUS status;
507 PASS_THRU_REQ(ntvfs, req, exit, (ntvfs, req));
509 return status;
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;
519 NTSTATUS status;
521 PASS_THRU_REQ(ntvfs, req, logoff, (ntvfs, req));
523 priv->last_token = NULL;
525 return status;
529 async setup
531 static NTSTATUS unixuid_async_setup(struct ntvfs_module_context *ntvfs,
532 struct ntvfs_request *req,
533 void *private_data)
535 NTSTATUS status;
537 PASS_THRU_REQ(ntvfs, req, async_setup, (ntvfs, req, private_data));
539 return status;
543 cancel an async request
545 static NTSTATUS unixuid_cancel(struct ntvfs_module_context *ntvfs,
546 struct ntvfs_request *req)
548 NTSTATUS status;
550 PASS_THRU_REQ(ntvfs, req, cancel, (ntvfs, req));
552 return status;
556 change notify
558 static NTSTATUS unixuid_notify(struct ntvfs_module_context *ntvfs,
559 struct ntvfs_request *req, union smb_notify *info)
561 NTSTATUS status;
563 PASS_THRU_REQ(ntvfs, req, notify, (ntvfs, req, info));
565 return status;
569 lock a byte range
571 static NTSTATUS unixuid_lock(struct ntvfs_module_context *ntvfs,
572 struct ntvfs_request *req, union smb_lock *lck)
574 NTSTATUS status;
576 PASS_THRU_REQ(ntvfs, req, lock, (ntvfs, req, lck));
578 return status;
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)
588 NTSTATUS status;
590 PASS_THRU_REQ(ntvfs, req, setfileinfo, (ntvfs, req, info));
592 return status;
597 return filesystem space info
599 static NTSTATUS unixuid_fsinfo(struct ntvfs_module_context *ntvfs,
600 struct ntvfs_request *req, union smb_fsinfo *fs)
602 NTSTATUS status;
604 PASS_THRU_REQ(ntvfs, req, fsinfo, (ntvfs, req, fs));
606 return status;
610 return print queue info
612 static NTSTATUS unixuid_lpq(struct ntvfs_module_context *ntvfs,
613 struct ntvfs_request *req, union smb_lpq *lpq)
615 NTSTATUS status;
617 PASS_THRU_REQ(ntvfs, req, lpq, (ntvfs, req, lpq));
619 return status;
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 *))
630 NTSTATUS status;
632 PASS_THRU_REQ(ntvfs, req, search_first, (ntvfs, req, io, search_private, callback));
634 return status;
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 *))
643 NTSTATUS status;
645 PASS_THRU_REQ(ntvfs, req, search_next, (ntvfs, req, io, search_private, callback));
647 return status;
650 /* close a search */
651 static NTSTATUS unixuid_search_close(struct ntvfs_module_context *ntvfs,
652 struct ntvfs_request *req, union smb_search_close *io)
654 NTSTATUS status;
656 PASS_THRU_REQ(ntvfs, req, search_close, (ntvfs, req, io));
658 return status;
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)
665 NTSTATUS status;
667 PASS_THRU_REQ(ntvfs, req, trans, (ntvfs, req, trans2));
669 return status;
673 initialise the unixuid backend, registering ourselves with the ntvfs subsystem
675 NTSTATUS ntvfs_unixuid_init(void)
677 NTSTATUS ret;
678 struct ntvfs_ops ops;
679 NTVFS_CURRENT_CRITICAL_SIZES(vers);
681 ZERO_STRUCT(ops);
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;
731 failed:
732 return ret;