r3737: - Get rid of the register_subsystem() and register_backend() functions.
[Samba/aatanasov.git] / source / ntvfs / unixuid / vfs_unixuid.c
blob4520df59fc19eac6a4fc7eabae504c95dbedfd05
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 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.
24 #include "includes.h"
25 #include "auth/auth.h"
26 #include "smb_server/smb_server.h"
28 struct unixuid_private {
29 void *samctx;
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 };
43 int ret;
44 const char *s;
45 void *ctx;
46 struct ldb_message **res;
47 const char *sidstr;
48 uint_t atype;
50 ctx = talloc(req, 0);
51 sidstr = dom_sid_string(ctx, sid);
53 ret = samdb_search(private->samctx, ctx, NULL, &res, attrs, "objectSid=%s", sidstr);
54 if (ret != 1) {
55 DEBUG(0,("sid_to_unixuid: unable to find sam record for sid %s\n", sidstr));
56 talloc_free(ctx);
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));
64 talloc_free(ctx);
65 return NT_STATUS_ACCESS_DENIED;
68 /* first try to get the uid directly */
69 s = samdb_result_string(res[0], "unixID", NULL);
70 if (s != NULL) {
71 *uid = strtoul(s, NULL, 0);
72 talloc_free(ctx);
73 return NT_STATUS_OK;
76 /* next try via the UnixName attribute */
77 s = samdb_result_string(res[0], "unixName", NULL);
78 if (s != NULL) {
79 struct passwd *pwd = getpwnam(s);
80 if (!pwd) {
81 DEBUG(0,("unixName %s for sid %s does not exist as a local user\n", s, sidstr));
82 talloc_free(ctx);
83 return NT_STATUS_ACCESS_DENIED;
85 *uid = pwd->pw_uid;
86 talloc_free(ctx);
87 return NT_STATUS_OK;
90 /* finally try via the sAMAccountName attribute */
91 s = samdb_result_string(res[0], "sAMAccountName", NULL);
92 if (s != NULL) {
93 struct passwd *pwd = getpwnam(s);
94 if (!pwd) {
95 DEBUG(0,("sAMAccountName '%s' for sid %s does not exist as a local user\n", s, sidstr));
96 talloc_free(ctx);
97 return NT_STATUS_ACCESS_DENIED;
99 *uid = pwd->pw_uid;
100 talloc_free(ctx);
101 return NT_STATUS_OK;
104 DEBUG(0,("sid_to_unixuid: no unixID, unixName or sAMAccountName for sid %s\n", sidstr));
106 talloc_free(ctx);
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 };
119 int ret;
120 const char *s;
121 void *ctx;
122 struct ldb_message **res;
123 const char *sidstr;
124 uint_t atype;
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);
130 if (ret != 1) {
131 DEBUG(0,("sid_to_unixgid: unable to find sam record for sid %s\n", sidstr));
132 talloc_free(ctx);
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));
140 talloc_free(ctx);
141 return NT_STATUS_ACCESS_DENIED;
144 /* first try to get the gid directly */
145 s = samdb_result_string(res[0], "unixID", NULL);
146 if (s != NULL) {
147 *gid = strtoul(s, NULL, 0);
148 talloc_free(ctx);
149 return NT_STATUS_OK;
152 /* next try via the UnixName attribute */
153 s = samdb_result_string(res[0], "unixName", NULL);
154 if (s != NULL) {
155 struct group *grp = getgrnam(s);
156 if (!grp) {
157 DEBUG(0,("unixName '%s' for sid %s does not exist as a local group\n", s, sidstr));
158 talloc_free(ctx);
159 return NT_STATUS_ACCESS_DENIED;
161 *gid = grp->gr_gid;
162 talloc_free(ctx);
163 return NT_STATUS_OK;
166 /* finally try via the sAMAccountName attribute */
167 s = samdb_result_string(res[0], "sAMAccountName", NULL);
168 if (s != NULL) {
169 struct group *grp = getgrnam(s);
170 if (!grp) {
171 DEBUG(0,("sAMAccountName '%s' for sid %s does not exist as a local group\n", s, sidstr));
172 talloc_free(ctx);
173 return NT_STATUS_ACCESS_DENIED;
175 *gid = grp->gr_gid;
176 talloc_free(ctx);
177 return NT_STATUS_OK;
180 DEBUG(0,("sid_to_unixgid: no unixID, unixName or sAMAccountName for sid %s\n", sidstr));
182 talloc_free(ctx);
183 return NT_STATUS_ACCESS_DENIED;
186 struct unix_sec_ctx {
187 uid_t uid;
188 gid_t gid;
189 uint_t ngroups;
190 gid_t *groups;
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);
199 if (sec == NULL) {
200 return NULL;
202 sec->uid = geteuid();
203 sec->gid = getegid();
204 sec->ngroups = getgroups(0, NULL);
205 if (sec->ngroups == -1) {
206 talloc_free(sec);
207 return NULL;
209 sec->groups = talloc_array_p(sec, gid_t, sec->ngroups);
210 if (sec->groups == NULL) {
211 talloc_free(sec);
212 return NULL;
215 if (getgroups(sec->ngroups, sec->groups) != sec->ngroups) {
216 talloc_free(sec);
217 return NULL;
220 return sec;
224 set the current security context from a unix_sec_ctx
226 static NTSTATUS set_unix_security(struct unix_sec_ctx *sec)
228 seteuid(0);
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;
239 return NT_STATUS_OK;
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)
250 int i;
251 NTSTATUS status;
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)) {
261 return status;
264 status = sid_to_unixgid(ntvfs, req, token->user_sids[1], &(*sec)->gid);
265 if (!NT_STATUS_IS_OK(status)) {
266 return 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)) {
278 return status;
282 return NT_STATUS_OK;
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;
295 NTSTATUS status;
297 *sec = save_unix_security(req);
298 if (*sec == NULL) {
299 return NT_STATUS_NO_MEMORY;
302 if (req->session->session_info->nt_user_token == private->last_token) {
303 newsec = private->last_sec_ctx;
304 } else {
305 status = nt_token_to_unix_security(ntvfs, req, token, &newsec);
306 if (!NT_STATUS_IS_OK(status)) {
307 talloc_free(ctx);
308 return 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)) {
320 talloc_free(ctx);
321 return status;
324 talloc_free(ctx);
326 return NT_STATUS_OK;
330 this pass through macro operates on request contexts
332 #define PASS_THRU_REQ(ntvfs, req, op, args) do { \
333 NTSTATUS status2; \
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"); \
339 } while (0)
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;
350 NTSTATUS status;
352 private = talloc_p(req->tcon, struct unixuid_private);
353 if (!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);
371 return status;
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;
381 NTSTATUS status;
383 talloc_free(private);
385 status = ntvfs_next_disconnect(ntvfs, tcon);
387 return status;
392 delete a file
394 static NTSTATUS unixuid_unlink(struct ntvfs_module_context *ntvfs,
395 struct smbsrv_request *req, struct smb_unlink *unl)
397 NTSTATUS status;
399 PASS_THRU_REQ(ntvfs, req, unlink, (ntvfs, req, unl));
401 return status;
405 ioctl interface
407 static NTSTATUS unixuid_ioctl(struct ntvfs_module_context *ntvfs,
408 struct smbsrv_request *req, union smb_ioctl *io)
410 NTSTATUS status;
412 PASS_THRU_REQ(ntvfs, req, ioctl, (ntvfs, req, io));
414 return status;
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)
423 NTSTATUS status;
425 PASS_THRU_REQ(ntvfs, req, chkpath, (ntvfs, req, cp));
427 return status;
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)
436 NTSTATUS status;
438 PASS_THRU_REQ(ntvfs, req, qpathinfo, (ntvfs, req, info));
440 return status;
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)
449 NTSTATUS status;
451 PASS_THRU_REQ(ntvfs, req, qfileinfo, (ntvfs, req, info));
453 return status;
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)
463 NTSTATUS status;
465 PASS_THRU_REQ(ntvfs, req, setpathinfo, (ntvfs, req, st));
467 return status;
471 open a file
473 static NTSTATUS unixuid_openfile(struct ntvfs_module_context *ntvfs,
474 struct smbsrv_request *req, union smb_open *io)
476 NTSTATUS status;
478 PASS_THRU_REQ(ntvfs, req, openfile, (ntvfs, req, io));
480 return status;
484 create a directory
486 static NTSTATUS unixuid_mkdir(struct ntvfs_module_context *ntvfs,
487 struct smbsrv_request *req, union smb_mkdir *md)
489 NTSTATUS status;
491 PASS_THRU_REQ(ntvfs, req, mkdir, (ntvfs, req, md));
493 return status;
497 remove a directory
499 static NTSTATUS unixuid_rmdir(struct ntvfs_module_context *ntvfs,
500 struct smbsrv_request *req, struct smb_rmdir *rd)
502 NTSTATUS status;
504 PASS_THRU_REQ(ntvfs, req, rmdir, (ntvfs, req, rd));
506 return status;
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)
515 NTSTATUS status;
517 PASS_THRU_REQ(ntvfs, req, rename, (ntvfs, req, ren));
519 return status;
523 copy a set of files
525 static NTSTATUS unixuid_copy(struct ntvfs_module_context *ntvfs,
526 struct smbsrv_request *req, struct smb_copy *cp)
528 NTSTATUS status;
530 PASS_THRU_REQ(ntvfs, req, copy, (ntvfs, req, cp));
532 return status;
536 read from a file
538 static NTSTATUS unixuid_read(struct ntvfs_module_context *ntvfs,
539 struct smbsrv_request *req, union smb_read *rd)
541 NTSTATUS status;
543 PASS_THRU_REQ(ntvfs, req, read, (ntvfs, req, rd));
545 return status;
549 write to a file
551 static NTSTATUS unixuid_write(struct ntvfs_module_context *ntvfs,
552 struct smbsrv_request *req, union smb_write *wr)
554 NTSTATUS status;
556 PASS_THRU_REQ(ntvfs, req, write, (ntvfs, req, wr));
558 return status;
562 seek in a file
564 static NTSTATUS unixuid_seek(struct ntvfs_module_context *ntvfs,
565 struct smbsrv_request *req, struct smb_seek *io)
567 NTSTATUS status;
569 PASS_THRU_REQ(ntvfs, req, seek, (ntvfs, req, io));
571 return status;
575 flush a file
577 static NTSTATUS unixuid_flush(struct ntvfs_module_context *ntvfs,
578 struct smbsrv_request *req, struct smb_flush *io)
580 NTSTATUS status;
582 PASS_THRU_REQ(ntvfs, req, flush, (ntvfs, req, io));
584 return status;
588 close a file
590 static NTSTATUS unixuid_close(struct ntvfs_module_context *ntvfs,
591 struct smbsrv_request *req, union smb_close *io)
593 NTSTATUS status;
595 PASS_THRU_REQ(ntvfs, req, close, (ntvfs, req, io));
597 return status;
601 exit - closing files
603 static NTSTATUS unixuid_exit(struct ntvfs_module_context *ntvfs,
604 struct smbsrv_request *req)
606 NTSTATUS status;
608 PASS_THRU_REQ(ntvfs, req, exit, (ntvfs, req));
610 return status;
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;
620 NTSTATUS status;
622 PASS_THRU_REQ(ntvfs, req, logoff, (ntvfs, req));
624 private->last_token = NULL;
626 return status;
630 async setup
632 static NTSTATUS unixuid_async_setup(struct ntvfs_module_context *ntvfs,
633 struct smbsrv_request *req,
634 void *private)
636 NTSTATUS status;
638 PASS_THRU_REQ(ntvfs, req, async_setup, (ntvfs, req, private));
640 return status;
644 cancel an async request
646 static NTSTATUS unixuid_cancel(struct ntvfs_module_context *ntvfs,
647 struct smbsrv_request *req)
649 NTSTATUS status;
651 PASS_THRU_REQ(ntvfs, req, cancel, (ntvfs, req));
653 return status;
657 lock a byte range
659 static NTSTATUS unixuid_lock(struct ntvfs_module_context *ntvfs,
660 struct smbsrv_request *req, union smb_lock *lck)
662 NTSTATUS status;
664 PASS_THRU_REQ(ntvfs, req, lock, (ntvfs, req, lck));
666 return status;
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)
676 NTSTATUS status;
678 PASS_THRU_REQ(ntvfs, req, setfileinfo, (ntvfs, req, info));
680 return status;
685 return filesystem space info
687 static NTSTATUS unixuid_fsinfo(struct ntvfs_module_context *ntvfs,
688 struct smbsrv_request *req, union smb_fsinfo *fs)
690 NTSTATUS status;
692 PASS_THRU_REQ(ntvfs, req, fsinfo, (ntvfs, req, fs));
694 return status;
698 return print queue info
700 static NTSTATUS unixuid_lpq(struct ntvfs_module_context *ntvfs,
701 struct smbsrv_request *req, union smb_lpq *lpq)
703 NTSTATUS status;
705 PASS_THRU_REQ(ntvfs, req, lpq, (ntvfs, req, lpq));
707 return status;
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 *))
718 NTSTATUS status;
720 PASS_THRU_REQ(ntvfs, req, search_first, (ntvfs, req, io, search_private, callback));
722 return status;
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 *))
731 NTSTATUS status;
733 PASS_THRU_REQ(ntvfs, req, search_next, (ntvfs, req, io, search_private, callback));
735 return status;
738 /* close a search */
739 static NTSTATUS unixuid_search_close(struct ntvfs_module_context *ntvfs,
740 struct smbsrv_request *req, union smb_search_close *io)
742 NTSTATUS status;
744 PASS_THRU_REQ(ntvfs, req, search_close, (ntvfs, req, io));
746 return status;
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)
753 NTSTATUS status;
755 PASS_THRU_REQ(ntvfs, req, trans, (ntvfs, req, trans2));
757 return status;
761 initialise the unixuid backend, registering ourselves with the ntvfs subsystem
763 NTSTATUS ntvfs_unixuid_init(void)
765 NTSTATUS ret;
766 struct ntvfs_ops ops;
768 ZERO_STRUCT(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;
817 failed:
818 return ret;