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 2 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, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "system/filesys.h"
26 #include "system/passwd.h"
27 #include "auth/auth.h"
28 #include "ntvfs/ntvfs.h"
30 struct unixuid_private
{
31 struct sidmap_context
*sidmap
;
32 struct unix_sec_ctx
*last_sec_ctx
;
33 struct security_token
*last_token
;
46 pull the current security context into a unix_sec_ctx
48 static struct unix_sec_ctx
*save_unix_security(TALLOC_CTX
*mem_ctx
)
50 struct unix_sec_ctx
*sec
= talloc(mem_ctx
, struct unix_sec_ctx
);
56 sec
->ngroups
= getgroups(0, NULL
);
57 if (sec
->ngroups
== -1) {
61 sec
->groups
= talloc_array(sec
, gid_t
, sec
->ngroups
);
62 if (sec
->groups
== NULL
) {
67 if (getgroups(sec
->ngroups
, sec
->groups
) != sec
->ngroups
) {
76 set the current security context from a unix_sec_ctx
78 static NTSTATUS
set_unix_security(struct unix_sec_ctx
*sec
)
82 if (setgroups(sec
->ngroups
, sec
->groups
) != 0) {
83 return NT_STATUS_ACCESS_DENIED
;
85 if (setegid(sec
->gid
) != 0) {
86 return NT_STATUS_ACCESS_DENIED
;
88 if (seteuid(sec
->uid
) != 0) {
89 return NT_STATUS_ACCESS_DENIED
;
95 form a unix_sec_ctx from the current security_token
97 static NTSTATUS
nt_token_to_unix_security(struct ntvfs_module_context
*ntvfs
,
98 struct ntvfs_request
*req
,
99 struct security_token
*token
,
100 struct unix_sec_ctx
**sec
)
102 struct unixuid_private
*private = ntvfs
->private_data
;
105 *sec
= talloc(req
, struct unix_sec_ctx
);
107 /* we can't do unix security without a user and group */
108 if (token
->num_sids
< 2) {
109 return NT_STATUS_ACCESS_DENIED
;
112 status
= sidmap_sid_to_unixuid(private->sidmap
,
113 token
->user_sid
, &(*sec
)->uid
);
114 if (!NT_STATUS_IS_OK(status
)) {
118 status
= sidmap_sid_to_unixgid(private->sidmap
,
119 token
->group_sid
, &(*sec
)->gid
);
120 if (!NT_STATUS_IS_OK(status
)) {
124 (*sec
)->ngroups
= token
->num_sids
- 2;
125 (*sec
)->groups
= talloc_array(*sec
, gid_t
, (*sec
)->ngroups
);
126 if ((*sec
)->groups
== NULL
) {
127 return NT_STATUS_NO_MEMORY
;
130 for (i
=0;i
<(*sec
)->ngroups
;i
++) {
131 status
= sidmap_sid_to_unixgid(private->sidmap
,
132 token
->sids
[i
+2], &(*sec
)->groups
[i
]);
133 if (!NT_STATUS_IS_OK(status
)) {
142 setup our unix security context according to the session authentication info
144 static NTSTATUS
unixuid_setup_security(struct ntvfs_module_context
*ntvfs
,
145 struct ntvfs_request
*req
, struct unix_sec_ctx
**sec
)
147 struct unixuid_private
*private = ntvfs
->private_data
;
148 struct security_token
*token
;
149 struct unix_sec_ctx
*newsec
;
152 if (req
->session_info
== NULL
) {
153 return NT_STATUS_ACCESS_DENIED
;
156 token
= req
->session_info
->security_token
;
158 *sec
= save_unix_security(req
);
160 return NT_STATUS_NO_MEMORY
;
163 if (token
== private->last_token
) {
164 newsec
= private->last_sec_ctx
;
166 status
= nt_token_to_unix_security(ntvfs
, req
, token
, &newsec
);
167 if (!NT_STATUS_IS_OK(status
)) {
170 if (private->last_sec_ctx
) {
171 talloc_free(private->last_sec_ctx
);
173 private->last_sec_ctx
= newsec
;
174 private->last_token
= token
;
175 talloc_steal(private, newsec
);
178 status
= set_unix_security(newsec
);
179 if (!NT_STATUS_IS_OK(status
)) {
187 this pass through macro operates on request contexts
189 #define PASS_THRU_REQ(ntvfs, req, op, args) do { \
191 struct unix_sec_ctx *sec; \
192 status = unixuid_setup_security(ntvfs, req, &sec); \
193 if (NT_STATUS_IS_OK(status)) status = ntvfs_next_##op args; \
194 status2 = set_unix_security(sec); \
195 if (!NT_STATUS_IS_OK(status2)) smb_panic("Unable to reset security context"); \
201 connect to a share - used when a tree_connect operation comes in.
203 static NTSTATUS
unixuid_connect(struct ntvfs_module_context
*ntvfs
,
204 struct ntvfs_request
*req
, const char *sharename
)
206 struct unixuid_private
*private;
209 private = talloc(ntvfs
, struct unixuid_private
);
211 return NT_STATUS_NO_MEMORY
;
214 private->sidmap
= sidmap_open(private);
215 if (private->sidmap
== NULL
) {
216 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
219 ntvfs
->private_data
= private;
220 private->last_sec_ctx
= NULL
;
221 private->last_token
= NULL
;
223 /* we don't use PASS_THRU_REQ here, as the connect operation runs with
224 root privileges. This allows the backends to setup any database
225 links they might need during the connect. */
226 status
= ntvfs_next_connect(ntvfs
, req
, sharename
);
232 disconnect from a share
234 static NTSTATUS
unixuid_disconnect(struct ntvfs_module_context
*ntvfs
)
236 struct unixuid_private
*private = ntvfs
->private_data
;
239 talloc_free(private);
240 ntvfs
->private_data
= NULL
;
242 status
= ntvfs_next_disconnect(ntvfs
);
251 static NTSTATUS
unixuid_unlink(struct ntvfs_module_context
*ntvfs
,
252 struct ntvfs_request
*req
,
253 union smb_unlink
*unl
)
257 PASS_THRU_REQ(ntvfs
, req
, unlink
, (ntvfs
, req
, unl
));
265 static NTSTATUS
unixuid_ioctl(struct ntvfs_module_context
*ntvfs
,
266 struct ntvfs_request
*req
, union smb_ioctl
*io
)
270 PASS_THRU_REQ(ntvfs
, req
, ioctl
, (ntvfs
, req
, io
));
276 check if a directory exists
278 static NTSTATUS
unixuid_chkpath(struct ntvfs_module_context
*ntvfs
,
279 struct ntvfs_request
*req
,
280 union smb_chkpath
*cp
)
284 PASS_THRU_REQ(ntvfs
, req
, chkpath
, (ntvfs
, req
, cp
));
290 return info on a pathname
292 static NTSTATUS
unixuid_qpathinfo(struct ntvfs_module_context
*ntvfs
,
293 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
297 PASS_THRU_REQ(ntvfs
, req
, qpathinfo
, (ntvfs
, req
, info
));
303 query info on a open file
305 static NTSTATUS
unixuid_qfileinfo(struct ntvfs_module_context
*ntvfs
,
306 struct ntvfs_request
*req
, union smb_fileinfo
*info
)
310 PASS_THRU_REQ(ntvfs
, req
, qfileinfo
, (ntvfs
, req
, info
));
317 set info on a pathname
319 static NTSTATUS
unixuid_setpathinfo(struct ntvfs_module_context
*ntvfs
,
320 struct ntvfs_request
*req
, union smb_setfileinfo
*st
)
324 PASS_THRU_REQ(ntvfs
, req
, setpathinfo
, (ntvfs
, req
, st
));
332 static NTSTATUS
unixuid_open(struct ntvfs_module_context
*ntvfs
,
333 struct ntvfs_request
*req
, union smb_open
*io
)
337 PASS_THRU_REQ(ntvfs
, req
, open
, (ntvfs
, req
, io
));
345 static NTSTATUS
unixuid_mkdir(struct ntvfs_module_context
*ntvfs
,
346 struct ntvfs_request
*req
, union smb_mkdir
*md
)
350 PASS_THRU_REQ(ntvfs
, req
, mkdir
, (ntvfs
, req
, md
));
358 static NTSTATUS
unixuid_rmdir(struct ntvfs_module_context
*ntvfs
,
359 struct ntvfs_request
*req
, struct smb_rmdir
*rd
)
363 PASS_THRU_REQ(ntvfs
, req
, rmdir
, (ntvfs
, req
, rd
));
369 rename a set of files
371 static NTSTATUS
unixuid_rename(struct ntvfs_module_context
*ntvfs
,
372 struct ntvfs_request
*req
, union smb_rename
*ren
)
376 PASS_THRU_REQ(ntvfs
, req
, rename
, (ntvfs
, req
, ren
));
384 static NTSTATUS
unixuid_copy(struct ntvfs_module_context
*ntvfs
,
385 struct ntvfs_request
*req
, struct smb_copy
*cp
)
389 PASS_THRU_REQ(ntvfs
, req
, copy
, (ntvfs
, req
, cp
));
397 static NTSTATUS
unixuid_read(struct ntvfs_module_context
*ntvfs
,
398 struct ntvfs_request
*req
, union smb_read
*rd
)
402 PASS_THRU_REQ(ntvfs
, req
, read
, (ntvfs
, req
, rd
));
410 static NTSTATUS
unixuid_write(struct ntvfs_module_context
*ntvfs
,
411 struct ntvfs_request
*req
, union smb_write
*wr
)
415 PASS_THRU_REQ(ntvfs
, req
, write
, (ntvfs
, req
, wr
));
423 static NTSTATUS
unixuid_seek(struct ntvfs_module_context
*ntvfs
,
424 struct ntvfs_request
*req
,
429 PASS_THRU_REQ(ntvfs
, req
, seek
, (ntvfs
, req
, io
));
437 static NTSTATUS
unixuid_flush(struct ntvfs_module_context
*ntvfs
,
438 struct ntvfs_request
*req
,
443 PASS_THRU_REQ(ntvfs
, req
, flush
, (ntvfs
, req
, io
));
451 static NTSTATUS
unixuid_close(struct ntvfs_module_context
*ntvfs
,
452 struct ntvfs_request
*req
, union smb_close
*io
)
456 PASS_THRU_REQ(ntvfs
, req
, close
, (ntvfs
, req
, io
));
464 static NTSTATUS
unixuid_exit(struct ntvfs_module_context
*ntvfs
,
465 struct ntvfs_request
*req
)
469 PASS_THRU_REQ(ntvfs
, req
, exit
, (ntvfs
, req
));
475 logoff - closing files
477 static NTSTATUS
unixuid_logoff(struct ntvfs_module_context
*ntvfs
,
478 struct ntvfs_request
*req
)
480 struct unixuid_private
*private = ntvfs
->private_data
;
483 PASS_THRU_REQ(ntvfs
, req
, logoff
, (ntvfs
, req
));
485 private->last_token
= NULL
;
493 static NTSTATUS
unixuid_async_setup(struct ntvfs_module_context
*ntvfs
,
494 struct ntvfs_request
*req
,
499 PASS_THRU_REQ(ntvfs
, req
, async_setup
, (ntvfs
, req
, private));
505 cancel an async request
507 static NTSTATUS
unixuid_cancel(struct ntvfs_module_context
*ntvfs
,
508 struct ntvfs_request
*req
)
512 PASS_THRU_REQ(ntvfs
, req
, cancel
, (ntvfs
, req
));
520 static NTSTATUS
unixuid_notify(struct ntvfs_module_context
*ntvfs
,
521 struct ntvfs_request
*req
, struct smb_notify
*info
)
525 PASS_THRU_REQ(ntvfs
, req
, notify
, (ntvfs
, req
, info
));
533 static NTSTATUS
unixuid_lock(struct ntvfs_module_context
*ntvfs
,
534 struct ntvfs_request
*req
, union smb_lock
*lck
)
538 PASS_THRU_REQ(ntvfs
, req
, lock
, (ntvfs
, req
, lck
));
544 set info on a open file
546 static NTSTATUS
unixuid_setfileinfo(struct ntvfs_module_context
*ntvfs
,
547 struct ntvfs_request
*req
,
548 union smb_setfileinfo
*info
)
552 PASS_THRU_REQ(ntvfs
, req
, setfileinfo
, (ntvfs
, req
, info
));
559 return filesystem space info
561 static NTSTATUS
unixuid_fsinfo(struct ntvfs_module_context
*ntvfs
,
562 struct ntvfs_request
*req
, union smb_fsinfo
*fs
)
566 PASS_THRU_REQ(ntvfs
, req
, fsinfo
, (ntvfs
, req
, fs
));
572 return print queue info
574 static NTSTATUS
unixuid_lpq(struct ntvfs_module_context
*ntvfs
,
575 struct ntvfs_request
*req
, union smb_lpq
*lpq
)
579 PASS_THRU_REQ(ntvfs
, req
, lpq
, (ntvfs
, req
, lpq
));
585 list files in a directory matching a wildcard pattern
587 static NTSTATUS
unixuid_search_first(struct ntvfs_module_context
*ntvfs
,
588 struct ntvfs_request
*req
, union smb_search_first
*io
,
589 void *search_private
,
590 BOOL (*callback
)(void *, union smb_search_data
*))
594 PASS_THRU_REQ(ntvfs
, req
, search_first
, (ntvfs
, req
, io
, search_private
, callback
));
599 /* continue a search */
600 static NTSTATUS
unixuid_search_next(struct ntvfs_module_context
*ntvfs
,
601 struct ntvfs_request
*req
, union smb_search_next
*io
,
602 void *search_private
,
603 BOOL (*callback
)(void *, union smb_search_data
*))
607 PASS_THRU_REQ(ntvfs
, req
, search_next
, (ntvfs
, req
, io
, search_private
, callback
));
613 static NTSTATUS
unixuid_search_close(struct ntvfs_module_context
*ntvfs
,
614 struct ntvfs_request
*req
, union smb_search_close
*io
)
618 PASS_THRU_REQ(ntvfs
, req
, search_close
, (ntvfs
, req
, io
));
623 /* SMBtrans - not used on file shares */
624 static NTSTATUS
unixuid_trans(struct ntvfs_module_context
*ntvfs
,
625 struct ntvfs_request
*req
, struct smb_trans2
*trans2
)
629 PASS_THRU_REQ(ntvfs
, req
, trans
, (ntvfs
, req
, trans2
));
635 initialise the unixuid backend, registering ourselves with the ntvfs subsystem
637 NTSTATUS
ntvfs_unixuid_init(void)
640 struct ntvfs_ops ops
;
644 /* fill in all the operations */
645 ops
.connect
= unixuid_connect
;
646 ops
.disconnect
= unixuid_disconnect
;
647 ops
.unlink
= unixuid_unlink
;
648 ops
.chkpath
= unixuid_chkpath
;
649 ops
.qpathinfo
= unixuid_qpathinfo
;
650 ops
.setpathinfo
= unixuid_setpathinfo
;
651 ops
.open
= unixuid_open
;
652 ops
.mkdir
= unixuid_mkdir
;
653 ops
.rmdir
= unixuid_rmdir
;
654 ops
.rename
= unixuid_rename
;
655 ops
.copy
= unixuid_copy
;
656 ops
.ioctl
= unixuid_ioctl
;
657 ops
.read
= unixuid_read
;
658 ops
.write
= unixuid_write
;
659 ops
.seek
= unixuid_seek
;
660 ops
.flush
= unixuid_flush
;
661 ops
.close
= unixuid_close
;
662 ops
.exit
= unixuid_exit
;
663 ops
.lock
= unixuid_lock
;
664 ops
.setfileinfo
= unixuid_setfileinfo
;
665 ops
.qfileinfo
= unixuid_qfileinfo
;
666 ops
.fsinfo
= unixuid_fsinfo
;
667 ops
.lpq
= unixuid_lpq
;
668 ops
.search_first
= unixuid_search_first
;
669 ops
.search_next
= unixuid_search_next
;
670 ops
.search_close
= unixuid_search_close
;
671 ops
.trans
= unixuid_trans
;
672 ops
.logoff
= unixuid_logoff
;
673 ops
.async_setup
= unixuid_async_setup
;
674 ops
.cancel
= unixuid_cancel
;
675 ops
.notify
= unixuid_notify
;
677 ops
.name
= "unixuid";
679 /* we register under all 3 backend types, as we are not type specific */
680 ops
.type
= NTVFS_DISK
;
681 ret
= ntvfs_register(&ops
);
682 if (!NT_STATUS_IS_OK(ret
)) goto failed
;
684 ops
.type
= NTVFS_PRINT
;
685 ret
= ntvfs_register(&ops
);
686 if (!NT_STATUS_IS_OK(ret
)) goto failed
;
688 ops
.type
= NTVFS_IPC
;
689 ret
= ntvfs_register(&ops
);
690 if (!NT_STATUS_IS_OK(ret
)) goto failed
;