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 "auth/auth.h"
26 #include "smb_server/smb_server.h"
28 struct unixuid_private
{
30 struct unix_sec_ctx
*last_sec_ctx
;
31 struct nt_user_token
*last_token
;
36 map a sid to a unix uid
38 static NTSTATUS
sid_to_unixuid(struct ntvfs_module_context
*ntvfs
,
39 struct smbsrv_request
*req
, struct dom_sid
*sid
, uid_t
*uid
)
41 struct unixuid_private
*private = ntvfs
->private_data
;
42 const char *attrs
[] = { "sAMAccountName", "unixID", "unixName", "sAMAccountType", NULL
};
46 struct ldb_message
**res
;
51 sidstr
= dom_sid_string(ctx
, sid
);
53 ret
= samdb_search(private->samctx
, ctx
, NULL
, &res
, attrs
, "objectSid=%s", sidstr
);
55 DEBUG(0,("sid_to_unixuid: unable to find sam record for sid %s\n", sidstr
));
57 return NT_STATUS_ACCESS_DENIED
;
60 /* make sure its a user, not a group */
61 atype
= samdb_result_uint(res
[0], "sAMAccountType", 0);
62 if (atype
&& (!(atype
& ATYPE_ACCOUNT
))) {
63 DEBUG(0,("sid_to_unixuid: sid %s is not an account!\n", sidstr
));
65 return NT_STATUS_ACCESS_DENIED
;
68 /* first try to get the uid directly */
69 s
= samdb_result_string(res
[0], "unixID", NULL
);
71 *uid
= strtoul(s
, NULL
, 0);
76 /* next try via the UnixName attribute */
77 s
= samdb_result_string(res
[0], "unixName", NULL
);
79 struct passwd
*pwd
= getpwnam(s
);
81 DEBUG(0,("unixName %s for sid %s does not exist as a local user\n", s
, sidstr
));
83 return NT_STATUS_ACCESS_DENIED
;
90 /* finally try via the sAMAccountName attribute */
91 s
= samdb_result_string(res
[0], "sAMAccountName", NULL
);
93 struct passwd
*pwd
= getpwnam(s
);
95 DEBUG(0,("sAMAccountName '%s' for sid %s does not exist as a local user\n", s
, sidstr
));
97 return NT_STATUS_ACCESS_DENIED
;
104 DEBUG(0,("sid_to_unixuid: no unixID, unixName or sAMAccountName for sid %s\n", sidstr
));
107 return NT_STATUS_ACCESS_DENIED
;
112 map a sid to a unix gid
114 static NTSTATUS
sid_to_unixgid(struct ntvfs_module_context
*ntvfs
,
115 struct smbsrv_request
*req
, struct dom_sid
*sid
, gid_t
*gid
)
117 struct unixuid_private
*private = ntvfs
->private_data
;
118 const char *attrs
[] = { "sAMAccountName", "unixID", "unixName", "sAMAccountType", NULL
};
122 struct ldb_message
**res
;
126 ctx
= talloc(req
, 0);
127 sidstr
= dom_sid_string(ctx
, sid
);
129 ret
= samdb_search(private->samctx
, ctx
, NULL
, &res
, attrs
, "objectSid=%s", sidstr
);
131 DEBUG(0,("sid_to_unixgid: unable to find sam record for sid %s\n", sidstr
));
133 return NT_STATUS_ACCESS_DENIED
;
136 /* make sure its not a user */
137 atype
= samdb_result_uint(res
[0], "sAMAccountType", 0);
138 if (atype
&& atype
== ATYPE_NORMAL_ACCOUNT
) {
139 DEBUG(0,("sid_to_unixgid: sid %s is a ATYPE_NORMAL_ACCOUNT\n", sidstr
));
141 return NT_STATUS_ACCESS_DENIED
;
144 /* first try to get the gid directly */
145 s
= samdb_result_string(res
[0], "unixID", NULL
);
147 *gid
= strtoul(s
, NULL
, 0);
152 /* next try via the UnixName attribute */
153 s
= samdb_result_string(res
[0], "unixName", NULL
);
155 struct group
*grp
= getgrnam(s
);
157 DEBUG(0,("unixName '%s' for sid %s does not exist as a local group\n", s
, sidstr
));
159 return NT_STATUS_ACCESS_DENIED
;
166 /* finally try via the sAMAccountName attribute */
167 s
= samdb_result_string(res
[0], "sAMAccountName", NULL
);
169 struct group
*grp
= getgrnam(s
);
171 DEBUG(0,("sAMAccountName '%s' for sid %s does not exist as a local group\n", s
, sidstr
));
173 return NT_STATUS_ACCESS_DENIED
;
180 DEBUG(0,("sid_to_unixgid: no unixID, unixName or sAMAccountName for sid %s\n", sidstr
));
183 return NT_STATUS_ACCESS_DENIED
;
186 struct unix_sec_ctx
{
194 pull the current security context into a unix_sec_ctx
196 static struct unix_sec_ctx
*save_unix_security(TALLOC_CTX
*mem_ctx
)
198 struct unix_sec_ctx
*sec
= talloc_p(mem_ctx
, struct unix_sec_ctx
);
202 sec
->uid
= geteuid();
203 sec
->gid
= getegid();
204 sec
->ngroups
= getgroups(0, NULL
);
205 if (sec
->ngroups
== -1) {
209 sec
->groups
= talloc_array_p(sec
, gid_t
, sec
->ngroups
);
210 if (sec
->groups
== NULL
) {
215 if (getgroups(sec
->ngroups
, sec
->groups
) != sec
->ngroups
) {
224 set the current security context from a unix_sec_ctx
226 static NTSTATUS
set_unix_security(struct unix_sec_ctx
*sec
)
230 if (setgroups(sec
->ngroups
, sec
->groups
) != 0) {
231 return NT_STATUS_ACCESS_DENIED
;
233 if (setegid(sec
->gid
) != 0) {
234 return NT_STATUS_ACCESS_DENIED
;
236 if (seteuid(sec
->uid
) != 0) {
237 return NT_STATUS_ACCESS_DENIED
;
243 form a unix_sec_ctx from the current nt_user_token
245 static NTSTATUS
nt_token_to_unix_security(struct ntvfs_module_context
*ntvfs
,
246 struct smbsrv_request
*req
,
247 struct nt_user_token
*token
,
248 struct unix_sec_ctx
**sec
)
252 *sec
= talloc_p(req
, struct unix_sec_ctx
);
254 /* we can't do unix security without a user and group */
255 if (token
->num_sids
< 2) {
256 return NT_STATUS_ACCESS_DENIED
;
259 status
= sid_to_unixuid(ntvfs
, req
, token
->user_sids
[0], &(*sec
)->uid
);
260 if (!NT_STATUS_IS_OK(status
)) {
264 status
= sid_to_unixgid(ntvfs
, req
, token
->user_sids
[1], &(*sec
)->gid
);
265 if (!NT_STATUS_IS_OK(status
)) {
269 (*sec
)->ngroups
= token
->num_sids
- 2;
270 (*sec
)->groups
= talloc_array_p(*sec
, gid_t
, (*sec
)->ngroups
);
271 if ((*sec
)->groups
== NULL
) {
272 return NT_STATUS_NO_MEMORY
;
275 for (i
=0;i
<(*sec
)->ngroups
;i
++) {
276 status
= sid_to_unixgid(ntvfs
, req
, token
->user_sids
[i
+2], &(*sec
)->groups
[i
]);
277 if (!NT_STATUS_IS_OK(status
)) {
286 setup our unix security context according to the session authentication info
288 static NTSTATUS
unixuid_setup_security(struct ntvfs_module_context
*ntvfs
,
289 struct smbsrv_request
*req
, struct unix_sec_ctx
**sec
)
291 struct unixuid_private
*private = ntvfs
->private_data
;
292 struct nt_user_token
*token
= req
->session
->session_info
->nt_user_token
;
293 void *ctx
= talloc(req
, 0);
294 struct unix_sec_ctx
*newsec
;
297 *sec
= save_unix_security(req
);
299 return NT_STATUS_NO_MEMORY
;
302 if (req
->session
->session_info
->nt_user_token
== private->last_token
) {
303 newsec
= private->last_sec_ctx
;
305 status
= nt_token_to_unix_security(ntvfs
, req
, token
, &newsec
);
306 if (!NT_STATUS_IS_OK(status
)) {
310 if (private->last_sec_ctx
) {
311 talloc_free(private->last_sec_ctx
);
313 private->last_sec_ctx
= newsec
;
314 private->last_token
= req
->session
->session_info
->nt_user_token
;
315 talloc_steal(private, newsec
);
318 status
= set_unix_security(newsec
);
319 if (!NT_STATUS_IS_OK(status
)) {
330 this pass through macro operates on request contexts
332 #define PASS_THRU_REQ(ntvfs, req, op, args) do { \
334 struct unix_sec_ctx *sec; \
335 status = unixuid_setup_security(ntvfs, req, &sec); \
336 if (NT_STATUS_IS_OK(status)) status = ntvfs_next_##op args; \
337 status2 = set_unix_security(sec); \
338 if (!NT_STATUS_IS_OK(status2)) smb_panic("Unable to reset security context"); \
344 connect to a share - used when a tree_connect operation comes in.
346 static NTSTATUS
unixuid_connect(struct ntvfs_module_context
*ntvfs
,
347 struct smbsrv_request
*req
, const char *sharename
)
349 struct unixuid_private
*private;
352 private = talloc_p(req
->tcon
, struct unixuid_private
);
354 return NT_STATUS_NO_MEMORY
;
357 private->samctx
= samdb_connect(private);
358 if (private->samctx
== NULL
) {
359 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
362 ntvfs
->private_data
= private;
363 private->last_sec_ctx
= NULL
;
364 private->last_token
= NULL
;
366 /* we don't use PASS_THRU_REQ here, as the connect operation runs with
367 root privileges. This allows the backends to setup any database
368 links they might need during the connect. */
369 status
= ntvfs_next_connect(ntvfs
, req
, sharename
);
375 disconnect from a share
377 static NTSTATUS
unixuid_disconnect(struct ntvfs_module_context
*ntvfs
,
378 struct smbsrv_tcon
*tcon
)
380 struct unixuid_private
*private = ntvfs
->private_data
;
383 talloc_free(private);
385 status
= ntvfs_next_disconnect(ntvfs
, tcon
);
394 static NTSTATUS
unixuid_unlink(struct ntvfs_module_context
*ntvfs
,
395 struct smbsrv_request
*req
, struct smb_unlink
*unl
)
399 PASS_THRU_REQ(ntvfs
, req
, unlink
, (ntvfs
, req
, unl
));
407 static NTSTATUS
unixuid_ioctl(struct ntvfs_module_context
*ntvfs
,
408 struct smbsrv_request
*req
, union smb_ioctl
*io
)
412 PASS_THRU_REQ(ntvfs
, req
, ioctl
, (ntvfs
, req
, io
));
418 check if a directory exists
420 static NTSTATUS
unixuid_chkpath(struct ntvfs_module_context
*ntvfs
,
421 struct smbsrv_request
*req
, struct smb_chkpath
*cp
)
425 PASS_THRU_REQ(ntvfs
, req
, chkpath
, (ntvfs
, req
, cp
));
431 return info on a pathname
433 static NTSTATUS
unixuid_qpathinfo(struct ntvfs_module_context
*ntvfs
,
434 struct smbsrv_request
*req
, union smb_fileinfo
*info
)
438 PASS_THRU_REQ(ntvfs
, req
, qpathinfo
, (ntvfs
, req
, info
));
444 query info on a open file
446 static NTSTATUS
unixuid_qfileinfo(struct ntvfs_module_context
*ntvfs
,
447 struct smbsrv_request
*req
, union smb_fileinfo
*info
)
451 PASS_THRU_REQ(ntvfs
, req
, qfileinfo
, (ntvfs
, req
, info
));
458 set info on a pathname
460 static NTSTATUS
unixuid_setpathinfo(struct ntvfs_module_context
*ntvfs
,
461 struct smbsrv_request
*req
, union smb_setfileinfo
*st
)
465 PASS_THRU_REQ(ntvfs
, req
, setpathinfo
, (ntvfs
, req
, st
));
473 static NTSTATUS
unixuid_openfile(struct ntvfs_module_context
*ntvfs
,
474 struct smbsrv_request
*req
, union smb_open
*io
)
478 PASS_THRU_REQ(ntvfs
, req
, openfile
, (ntvfs
, req
, io
));
486 static NTSTATUS
unixuid_mkdir(struct ntvfs_module_context
*ntvfs
,
487 struct smbsrv_request
*req
, union smb_mkdir
*md
)
491 PASS_THRU_REQ(ntvfs
, req
, mkdir
, (ntvfs
, req
, md
));
499 static NTSTATUS
unixuid_rmdir(struct ntvfs_module_context
*ntvfs
,
500 struct smbsrv_request
*req
, struct smb_rmdir
*rd
)
504 PASS_THRU_REQ(ntvfs
, req
, rmdir
, (ntvfs
, req
, rd
));
510 rename a set of files
512 static NTSTATUS
unixuid_rename(struct ntvfs_module_context
*ntvfs
,
513 struct smbsrv_request
*req
, union smb_rename
*ren
)
517 PASS_THRU_REQ(ntvfs
, req
, rename
, (ntvfs
, req
, ren
));
525 static NTSTATUS
unixuid_copy(struct ntvfs_module_context
*ntvfs
,
526 struct smbsrv_request
*req
, struct smb_copy
*cp
)
530 PASS_THRU_REQ(ntvfs
, req
, copy
, (ntvfs
, req
, cp
));
538 static NTSTATUS
unixuid_read(struct ntvfs_module_context
*ntvfs
,
539 struct smbsrv_request
*req
, union smb_read
*rd
)
543 PASS_THRU_REQ(ntvfs
, req
, read
, (ntvfs
, req
, rd
));
551 static NTSTATUS
unixuid_write(struct ntvfs_module_context
*ntvfs
,
552 struct smbsrv_request
*req
, union smb_write
*wr
)
556 PASS_THRU_REQ(ntvfs
, req
, write
, (ntvfs
, req
, wr
));
564 static NTSTATUS
unixuid_seek(struct ntvfs_module_context
*ntvfs
,
565 struct smbsrv_request
*req
, struct smb_seek
*io
)
569 PASS_THRU_REQ(ntvfs
, req
, seek
, (ntvfs
, req
, io
));
577 static NTSTATUS
unixuid_flush(struct ntvfs_module_context
*ntvfs
,
578 struct smbsrv_request
*req
, struct smb_flush
*io
)
582 PASS_THRU_REQ(ntvfs
, req
, flush
, (ntvfs
, req
, io
));
590 static NTSTATUS
unixuid_close(struct ntvfs_module_context
*ntvfs
,
591 struct smbsrv_request
*req
, union smb_close
*io
)
595 PASS_THRU_REQ(ntvfs
, req
, close
, (ntvfs
, req
, io
));
603 static NTSTATUS
unixuid_exit(struct ntvfs_module_context
*ntvfs
,
604 struct smbsrv_request
*req
)
608 PASS_THRU_REQ(ntvfs
, req
, exit
, (ntvfs
, req
));
614 logoff - closing files
616 static NTSTATUS
unixuid_logoff(struct ntvfs_module_context
*ntvfs
,
617 struct smbsrv_request
*req
)
619 struct unixuid_private
*private = ntvfs
->private_data
;
622 PASS_THRU_REQ(ntvfs
, req
, logoff
, (ntvfs
, req
));
624 private->last_token
= NULL
;
632 static NTSTATUS
unixuid_async_setup(struct ntvfs_module_context
*ntvfs
,
633 struct smbsrv_request
*req
,
638 PASS_THRU_REQ(ntvfs
, req
, async_setup
, (ntvfs
, req
, private));
644 cancel an async request
646 static NTSTATUS
unixuid_cancel(struct ntvfs_module_context
*ntvfs
,
647 struct smbsrv_request
*req
)
651 PASS_THRU_REQ(ntvfs
, req
, cancel
, (ntvfs
, req
));
659 static NTSTATUS
unixuid_lock(struct ntvfs_module_context
*ntvfs
,
660 struct smbsrv_request
*req
, union smb_lock
*lck
)
664 PASS_THRU_REQ(ntvfs
, req
, lock
, (ntvfs
, req
, lck
));
670 set info on a open file
672 static NTSTATUS
unixuid_setfileinfo(struct ntvfs_module_context
*ntvfs
,
673 struct smbsrv_request
*req
,
674 union smb_setfileinfo
*info
)
678 PASS_THRU_REQ(ntvfs
, req
, setfileinfo
, (ntvfs
, req
, info
));
685 return filesystem space info
687 static NTSTATUS
unixuid_fsinfo(struct ntvfs_module_context
*ntvfs
,
688 struct smbsrv_request
*req
, union smb_fsinfo
*fs
)
692 PASS_THRU_REQ(ntvfs
, req
, fsinfo
, (ntvfs
, req
, fs
));
698 return print queue info
700 static NTSTATUS
unixuid_lpq(struct ntvfs_module_context
*ntvfs
,
701 struct smbsrv_request
*req
, union smb_lpq
*lpq
)
705 PASS_THRU_REQ(ntvfs
, req
, lpq
, (ntvfs
, req
, lpq
));
711 list files in a directory matching a wildcard pattern
713 static NTSTATUS
unixuid_search_first(struct ntvfs_module_context
*ntvfs
,
714 struct smbsrv_request
*req
, union smb_search_first
*io
,
715 void *search_private
,
716 BOOL (*callback
)(void *, union smb_search_data
*))
720 PASS_THRU_REQ(ntvfs
, req
, search_first
, (ntvfs
, req
, io
, search_private
, callback
));
725 /* continue a search */
726 static NTSTATUS
unixuid_search_next(struct ntvfs_module_context
*ntvfs
,
727 struct smbsrv_request
*req
, union smb_search_next
*io
,
728 void *search_private
,
729 BOOL (*callback
)(void *, union smb_search_data
*))
733 PASS_THRU_REQ(ntvfs
, req
, search_next
, (ntvfs
, req
, io
, search_private
, callback
));
739 static NTSTATUS
unixuid_search_close(struct ntvfs_module_context
*ntvfs
,
740 struct smbsrv_request
*req
, union smb_search_close
*io
)
744 PASS_THRU_REQ(ntvfs
, req
, search_close
, (ntvfs
, req
, io
));
749 /* SMBtrans - not used on file shares */
750 static NTSTATUS
unixuid_trans(struct ntvfs_module_context
*ntvfs
,
751 struct smbsrv_request
*req
, struct smb_trans2
*trans2
)
755 PASS_THRU_REQ(ntvfs
, req
, trans
, (ntvfs
, req
, trans2
));
761 initialise the unixuid backend, registering ourselves with the ntvfs subsystem
763 NTSTATUS
ntvfs_unixuid_init(void)
766 struct ntvfs_ops ops
;
770 /* fill in all the operations */
771 ops
.connect
= unixuid_connect
;
772 ops
.disconnect
= unixuid_disconnect
;
773 ops
.unlink
= unixuid_unlink
;
774 ops
.chkpath
= unixuid_chkpath
;
775 ops
.qpathinfo
= unixuid_qpathinfo
;
776 ops
.setpathinfo
= unixuid_setpathinfo
;
777 ops
.openfile
= unixuid_openfile
;
778 ops
.mkdir
= unixuid_mkdir
;
779 ops
.rmdir
= unixuid_rmdir
;
780 ops
.rename
= unixuid_rename
;
781 ops
.copy
= unixuid_copy
;
782 ops
.ioctl
= unixuid_ioctl
;
783 ops
.read
= unixuid_read
;
784 ops
.write
= unixuid_write
;
785 ops
.seek
= unixuid_seek
;
786 ops
.flush
= unixuid_flush
;
787 ops
.close
= unixuid_close
;
788 ops
.exit
= unixuid_exit
;
789 ops
.lock
= unixuid_lock
;
790 ops
.setfileinfo
= unixuid_setfileinfo
;
791 ops
.qfileinfo
= unixuid_qfileinfo
;
792 ops
.fsinfo
= unixuid_fsinfo
;
793 ops
.lpq
= unixuid_lpq
;
794 ops
.search_first
= unixuid_search_first
;
795 ops
.search_next
= unixuid_search_next
;
796 ops
.search_close
= unixuid_search_close
;
797 ops
.trans
= unixuid_trans
;
798 ops
.logoff
= unixuid_logoff
;
799 ops
.async_setup
= unixuid_async_setup
;
800 ops
.cancel
= unixuid_cancel
;
802 ops
.name
= "unixuid";
804 /* we register under all 3 backend types, as we are not type specific */
805 ops
.type
= NTVFS_DISK
;
806 ret
= ntvfs_register(&ops
);
807 if (!NT_STATUS_IS_OK(ret
)) goto failed
;
809 ops
.type
= NTVFS_PRINT
;
810 ret
= ntvfs_register(&ops
);
811 if (!NT_STATUS_IS_OK(ret
)) goto failed
;
813 ops
.type
= NTVFS_IPC
;
814 ret
= ntvfs_register(&ops
);
815 if (!NT_STATUS_IS_OK(ret
)) goto failed
;