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.
26 struct unixuid_private {
32 map a sid to a unix uid
34 static NTSTATUS sid_to_unixuid(struct ntvfs_module_context *ntvfs,
35 struct smbsrv_request *req, struct dom_sid *sid, uid_t *uid)
37 struct unixuid_private *private = ntvfs->private_data;
38 const char *attrs[] = { "sAMAccountName", "unixID", "unixName", "sAMAccountType", NULL };
42 struct ldb_message **res;
47 sidstr = dom_sid_string(ctx, sid);
49 ret = samdb_search(private->samctx, ctx, NULL, &res, attrs, "objectSid=%s", sidstr);
51 DEBUG(0,("sid_to_unixuid: unable to find sam record for sid %s\n", sidstr));
53 return NT_STATUS_ACCESS_DENIED;
56 /* make sure its a user, not a group */
57 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
58 if (atype && atype != ATYPE_NORMAL_ACCOUNT) {
59 DEBUG(0,("sid_to_unixuid: sid %s is not ATYPE_NORMAL_ACCOUNT\n", sidstr));
61 return NT_STATUS_ACCESS_DENIED;
64 /* first try to get the uid directly */
65 s = samdb_result_string(res[0], "unixID", NULL);
67 *uid = strtoul(s, NULL, 0);
72 /* next try via the UnixName attribute */
73 s = samdb_result_string(res[0], "unixName", NULL);
75 struct passwd *pwd = getpwnam(s);
77 DEBUG(0,("unixName %s for sid %s does not exist as a local user\n", s, sidstr));
79 return NT_STATUS_ACCESS_DENIED;
86 /* finally try via the sAMAccountName attribute */
87 s = samdb_result_string(res[0], "sAMAccountName", NULL);
89 struct passwd *pwd = getpwnam(s);
91 DEBUG(0,("sAMAccountName '%s' for sid %s does not exist as a local user\n", s, sidstr));
93 return NT_STATUS_ACCESS_DENIED;
100 DEBUG(0,("sid_to_unixuid: no unixID, unixName or sAMAccountName for sid %s\n", sidstr));
103 return NT_STATUS_ACCESS_DENIED;
108 map a sid to a unix gid
110 static NTSTATUS sid_to_unixgid(struct ntvfs_module_context *ntvfs,
111 struct smbsrv_request *req, struct dom_sid *sid, gid_t *gid)
113 struct unixuid_private *private = ntvfs->private_data;
114 const char *attrs[] = { "sAMAccountName", "unixID", "unixName", "sAMAccountType", NULL };
118 struct ldb_message **res;
122 ctx = talloc(req, 0);
123 sidstr = dom_sid_string(ctx, sid);
125 ret = samdb_search(private->samctx, ctx, NULL, &res, attrs, "objectSid=%s", sidstr);
127 DEBUG(0,("sid_to_unixgid: unable to find sam record for sid %s\n", sidstr));
129 return NT_STATUS_ACCESS_DENIED;
132 /* make sure its not a user */
133 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
134 if (atype && atype == ATYPE_NORMAL_ACCOUNT) {
135 DEBUG(0,("sid_to_unixgid: sid %s is a ATYPE_NORMAL_ACCOUNT\n", sidstr));
137 return NT_STATUS_ACCESS_DENIED;
140 /* first try to get the gid directly */
141 s = samdb_result_string(res[0], "unixID", NULL);
143 *gid = strtoul(s, NULL, 0);
148 /* next try via the UnixName attribute */
149 s = samdb_result_string(res[0], "unixName", NULL);
151 struct group *grp = getgrnam(s);
153 DEBUG(0,("unixName '%s' for sid %s does not exist as a local group\n", s, sidstr));
155 return NT_STATUS_ACCESS_DENIED;
162 /* finally try via the sAMAccountName attribute */
163 s = samdb_result_string(res[0], "sAMAccountName", NULL);
165 struct group *grp = getgrnam(s);
167 DEBUG(0,("sAMAccountName '%s' for sid %s does not exist as a local group\n", s, sidstr));
169 return NT_STATUS_ACCESS_DENIED;
176 DEBUG(0,("sid_to_unixgid: no unixID, unixName or sAMAccountName for sid %s\n", sidstr));
179 return NT_STATUS_ACCESS_DENIED;
182 struct unix_sec_ctx {
190 pull the current security context into a unix_sec_ctx
192 static struct unix_sec_ctx *save_unix_security(TALLOC_CTX *mem_ctx)
194 struct unix_sec_ctx *sec = talloc_p(mem_ctx, struct unix_sec_ctx);
198 sec->uid = geteuid();
199 sec->gid = getegid();
200 sec->ngroups = getgroups(0, NULL);
201 if (sec->ngroups == -1) {
205 sec->groups = talloc_array_p(sec, gid_t, sec->ngroups);
206 if (sec->groups == NULL) {
211 if (getgroups(sec->ngroups, sec->groups) != sec->ngroups) {
220 set the current security context from a unix_sec_ctx
222 static NTSTATUS set_unix_security(struct unix_sec_ctx *sec)
226 if (setgroups(sec->ngroups, sec->groups) != 0) {
227 return NT_STATUS_ACCESS_DENIED;
229 if (setegid(sec->gid) != 0) {
230 return NT_STATUS_ACCESS_DENIED;
232 if (seteuid(sec->uid) != 0) {
233 return NT_STATUS_ACCESS_DENIED;
239 form a unix_sec_ctx from the current session info
241 static NTSTATUS authinfo_to_unix_security(struct ntvfs_module_context *ntvfs,
242 struct smbsrv_request *req,
243 struct auth_serversupplied_info *info,
244 struct unix_sec_ctx **sec)
248 *sec = talloc_p(req, struct unix_sec_ctx);
250 status = sid_to_unixuid(ntvfs, req, info->user_sid, &(*sec)->uid);
251 if (!NT_STATUS_IS_OK(status)) {
255 status = sid_to_unixgid(ntvfs, req, info->primary_group_sid, &(*sec)->gid);
256 if (!NT_STATUS_IS_OK(status)) {
260 (*sec)->ngroups = info->n_domain_groups;
261 (*sec)->groups = talloc_array_p(*sec, gid_t, (*sec)->ngroups);
262 if ((*sec)->groups == NULL) {
263 return NT_STATUS_NO_MEMORY;
266 for (i=0;i<(*sec)->ngroups;i++) {
267 status = sid_to_unixgid(ntvfs, req, info->domain_groups[i], &(*sec)->groups[i]);
268 if (!NT_STATUS_IS_OK(status)) {
277 setup our unix security context according to the session authentication info
279 static NTSTATUS unixuid_setup_security(struct ntvfs_module_context *ntvfs,
280 struct smbsrv_request *req, struct unix_sec_ctx **sec)
282 struct auth_serversupplied_info *info = req->session->session_info->server_info;
283 void *ctx = talloc(req, 0);
284 struct unix_sec_ctx *newsec;
287 *sec = save_unix_security(req);
289 return NT_STATUS_NO_MEMORY;
292 status = authinfo_to_unix_security(ntvfs, req, info, &newsec);
293 if (!NT_STATUS_IS_OK(status)) {
298 status = set_unix_security(newsec);
299 if (!NT_STATUS_IS_OK(status)) {
310 this pass through macro operates on request contexts
312 #define PASS_THRU_REQ(ntvfs, req, op, args) do { \
314 struct unix_sec_ctx *sec; \
315 status = unixuid_setup_security(ntvfs, req, &sec); \
316 if (NT_STATUS_IS_OK(status)) status = ntvfs_next_##op args; \
317 status2 = set_unix_security(sec); \
318 if (!NT_STATUS_IS_OK(status2)) smb_panic("Unable to reset security context"); \
324 connect to a share - used when a tree_connect operation comes in.
326 static NTSTATUS unixuid_connect(struct ntvfs_module_context *ntvfs,
327 struct smbsrv_request *req, const char *sharename)
329 struct unixuid_private *private;
332 private = talloc_p(req->tcon, struct unixuid_private);
334 return NT_STATUS_NO_MEMORY;
337 private->samctx = samdb_connect(private);
338 if (private->samctx == NULL) {
339 return NT_STATUS_INTERNAL_DB_CORRUPTION;
342 ntvfs->private_data = private;
344 PASS_THRU_REQ(ntvfs, req, connect, (ntvfs, req, sharename));
350 disconnect from a share
352 static NTSTATUS unixuid_disconnect(struct ntvfs_module_context *ntvfs,
353 struct smbsrv_tcon *tcon)
355 struct unixuid_private *private = ntvfs->private_data;
358 talloc_free(private);
360 status = ntvfs_next_disconnect(ntvfs, tcon);
369 static NTSTATUS unixuid_unlink(struct ntvfs_module_context *ntvfs,
370 struct smbsrv_request *req, struct smb_unlink *unl)
374 PASS_THRU_REQ(ntvfs, req, unlink, (ntvfs, req, unl));
382 static NTSTATUS unixuid_ioctl(struct ntvfs_module_context *ntvfs,
383 struct smbsrv_request *req, union smb_ioctl *io)
387 PASS_THRU_REQ(ntvfs, req, ioctl, (ntvfs, req, io));
393 check if a directory exists
395 static NTSTATUS unixuid_chkpath(struct ntvfs_module_context *ntvfs,
396 struct smbsrv_request *req, struct smb_chkpath *cp)
400 PASS_THRU_REQ(ntvfs, req, chkpath, (ntvfs, req, cp));
406 return info on a pathname
408 static NTSTATUS unixuid_qpathinfo(struct ntvfs_module_context *ntvfs,
409 struct smbsrv_request *req, union smb_fileinfo *info)
413 PASS_THRU_REQ(ntvfs, req, qpathinfo, (ntvfs, req, info));
419 query info on a open file
421 static NTSTATUS unixuid_qfileinfo(struct ntvfs_module_context *ntvfs,
422 struct smbsrv_request *req, union smb_fileinfo *info)
426 PASS_THRU_REQ(ntvfs, req, qfileinfo, (ntvfs, req, info));
433 set info on a pathname
435 static NTSTATUS unixuid_setpathinfo(struct ntvfs_module_context *ntvfs,
436 struct smbsrv_request *req, union smb_setfileinfo *st)
440 PASS_THRU_REQ(ntvfs, req, setpathinfo, (ntvfs, req, st));
448 static NTSTATUS unixuid_open(struct ntvfs_module_context *ntvfs,
449 struct smbsrv_request *req, union smb_open *io)
453 PASS_THRU_REQ(ntvfs, req, open, (ntvfs, req, io));
461 static NTSTATUS unixuid_mkdir(struct ntvfs_module_context *ntvfs,
462 struct smbsrv_request *req, union smb_mkdir *md)
466 PASS_THRU_REQ(ntvfs, req, mkdir, (ntvfs, req, md));
474 static NTSTATUS unixuid_rmdir(struct ntvfs_module_context *ntvfs,
475 struct smbsrv_request *req, struct smb_rmdir *rd)
479 PASS_THRU_REQ(ntvfs, req, rmdir, (ntvfs, req, rd));
485 rename a set of files
487 static NTSTATUS unixuid_rename(struct ntvfs_module_context *ntvfs,
488 struct smbsrv_request *req, union smb_rename *ren)
492 PASS_THRU_REQ(ntvfs, req, rename, (ntvfs, req, ren));
500 static NTSTATUS unixuid_copy(struct ntvfs_module_context *ntvfs,
501 struct smbsrv_request *req, struct smb_copy *cp)
505 PASS_THRU_REQ(ntvfs, req, copy, (ntvfs, req, cp));
513 static NTSTATUS unixuid_read(struct ntvfs_module_context *ntvfs,
514 struct smbsrv_request *req, union smb_read *rd)
518 PASS_THRU_REQ(ntvfs, req, read, (ntvfs, req, rd));
526 static NTSTATUS unixuid_write(struct ntvfs_module_context *ntvfs,
527 struct smbsrv_request *req, union smb_write *wr)
531 PASS_THRU_REQ(ntvfs, req, write, (ntvfs, req, wr));
539 static NTSTATUS unixuid_seek(struct ntvfs_module_context *ntvfs,
540 struct smbsrv_request *req, struct smb_seek *io)
544 PASS_THRU_REQ(ntvfs, req, seek, (ntvfs, req, io));
552 static NTSTATUS unixuid_flush(struct ntvfs_module_context *ntvfs,
553 struct smbsrv_request *req, struct smb_flush *io)
557 PASS_THRU_REQ(ntvfs, req, flush, (ntvfs, req, io));
565 static NTSTATUS unixuid_close(struct ntvfs_module_context *ntvfs,
566 struct smbsrv_request *req, union smb_close *io)
570 PASS_THRU_REQ(ntvfs, req, close, (ntvfs, req, io));
578 static NTSTATUS unixuid_exit(struct ntvfs_module_context *ntvfs,
579 struct smbsrv_request *req)
583 PASS_THRU_REQ(ntvfs, req, exit, (ntvfs, req));
589 logoff - closing files
591 static NTSTATUS unixuid_logoff(struct ntvfs_module_context *ntvfs,
592 struct smbsrv_request *req)
596 PASS_THRU_REQ(ntvfs, req, logoff, (ntvfs, req));
604 static NTSTATUS unixuid_lock(struct ntvfs_module_context *ntvfs,
605 struct smbsrv_request *req, union smb_lock *lck)
609 PASS_THRU_REQ(ntvfs, req, lock, (ntvfs, req, lck));
615 set info on a open file
617 static NTSTATUS unixuid_setfileinfo(struct ntvfs_module_context *ntvfs,
618 struct smbsrv_request *req,
619 union smb_setfileinfo *info)
623 PASS_THRU_REQ(ntvfs, req, setfileinfo, (ntvfs, req, info));
630 return filesystem space info
632 static NTSTATUS unixuid_fsinfo(struct ntvfs_module_context *ntvfs,
633 struct smbsrv_request *req, union smb_fsinfo *fs)
637 PASS_THRU_REQ(ntvfs, req, fsinfo, (ntvfs, req, fs));
643 return print queue info
645 static NTSTATUS unixuid_lpq(struct ntvfs_module_context *ntvfs,
646 struct smbsrv_request *req, union smb_lpq *lpq)
650 PASS_THRU_REQ(ntvfs, req, lpq, (ntvfs, req, lpq));
656 list files in a directory matching a wildcard pattern
658 static NTSTATUS unixuid_search_first(struct ntvfs_module_context *ntvfs,
659 struct smbsrv_request *req, union smb_search_first *io,
660 void *search_private,
661 BOOL (*callback)(void *, union smb_search_data *))
665 PASS_THRU_REQ(ntvfs, req, search_first, (ntvfs, req, io, search_private, callback));
670 /* continue a search */
671 static NTSTATUS unixuid_search_next(struct ntvfs_module_context *ntvfs,
672 struct smbsrv_request *req, union smb_search_next *io,
673 void *search_private,
674 BOOL (*callback)(void *, union smb_search_data *))
678 PASS_THRU_REQ(ntvfs, req, search_next, (ntvfs, req, io, search_private, callback));
684 static NTSTATUS unixuid_search_close(struct ntvfs_module_context *ntvfs,
685 struct smbsrv_request *req, union smb_search_close *io)
689 PASS_THRU_REQ(ntvfs, req, search_close, (ntvfs, req, io));
694 /* SMBtrans - not used on file shares */
695 static NTSTATUS unixuid_trans(struct ntvfs_module_context *ntvfs,
696 struct smbsrv_request *req, struct smb_trans2 *trans2)
700 PASS_THRU_REQ(ntvfs, req, trans, (ntvfs, req, trans2));
706 initialise the unixuid backend, registering ourselves with the ntvfs subsystem
708 NTSTATUS ntvfs_unixuid_init(void)
711 struct ntvfs_ops ops;
715 /* fill in all the operations */
716 ops.connect = unixuid_connect;
717 ops.disconnect = unixuid_disconnect;
718 ops.unlink = unixuid_unlink;
719 ops.chkpath = unixuid_chkpath;
720 ops.qpathinfo = unixuid_qpathinfo;
721 ops.setpathinfo = unixuid_setpathinfo;
722 ops.open = unixuid_open;
723 ops.mkdir = unixuid_mkdir;
724 ops.rmdir = unixuid_rmdir;
725 ops.rename = unixuid_rename;
726 ops.copy = unixuid_copy;
727 ops.ioctl = unixuid_ioctl;
728 ops.read = unixuid_read;
729 ops.write = unixuid_write;
730 ops.seek = unixuid_seek;
731 ops.flush = unixuid_flush;
732 ops.close = unixuid_close;
733 ops.exit = unixuid_exit;
734 ops.lock = unixuid_lock;
735 ops.setfileinfo = unixuid_setfileinfo;
736 ops.qfileinfo = unixuid_qfileinfo;
737 ops.fsinfo = unixuid_fsinfo;
738 ops.lpq = unixuid_lpq;
739 ops.search_first = unixuid_search_first;
740 ops.search_next = unixuid_search_next;
741 ops.search_close = unixuid_search_close;
742 ops.trans = unixuid_trans;
743 ops.logoff = unixuid_logoff;
745 ops.name = "unixuid";
747 /* we register under all 3 backend types, as we are not type specific */
748 ops.type = NTVFS_DISK;
749 ret = register_backend("ntvfs", &ops);
750 if (!NT_STATUS_IS_OK(ret)) goto failed;
752 ops.type = NTVFS_PRINT;
753 ret = register_backend("ntvfs", &ops);
754 if (!NT_STATUS_IS_OK(ret)) goto failed;
756 ops.type = NTVFS_IPC;
757 ret = register_backend("ntvfs", &ops);
758 if (!NT_STATUS_IS_OK(ret)) goto failed;