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;
46 sidstr = dom_sid_string(ctx, sid);
48 ret = samdb_search(private->samctx, ctx, NULL, &res, attrs, "objectSid=%s", sidstr);
50 DEBUG(2,("Unable to map sid %s to unix uid\n", sidstr));
52 return NT_STATUS_ACCESS_DENIED;
55 /* make sure its a user, not a group */
56 if (samdb_result_uint(res[0], "sAMAccountType", 0) != ATYPE_NORMAL_ACCOUNT) {
57 DEBUG(0,("sid_to_unixuid: sid %s is not ATYPE_NORMAL_ACCOUNT\n", sidstr));
59 return NT_STATUS_ACCESS_DENIED;
62 /* first try to get the uid directly */
63 s = samdb_result_string(res[0], "UnixID", NULL);
65 *uid = strtoul(s, NULL, 0);
70 /* next try via the UnixName attribute */
71 s = samdb_result_string(res[0], "UnixName", NULL);
73 struct passwd *pwd = getpwnam(s);
75 DEBUG(0,("UnixName %s for sid %s does not exist as a local user\n", s, sidstr));
77 return NT_STATUS_ACCESS_DENIED;
84 /* finally try via the sAMAccountName attribute */
85 s = samdb_result_string(res[0], "sAMAccountName", NULL);
87 struct passwd *pwd = getpwnam(s);
89 DEBUG(0,("sAMAccountName '%s' for sid %s does not exist as a local user\n", s, sidstr));
91 return NT_STATUS_ACCESS_DENIED;
98 DEBUG(0,("No sAMAccountName for sid %s!?\n", sidstr));
101 return NT_STATUS_ACCESS_DENIED;
106 map a sid to a unix gid
108 static NTSTATUS sid_to_unixgid(struct ntvfs_module_context *ntvfs,
109 struct smbsrv_request *req, struct dom_sid *sid, gid_t *gid)
111 struct unixuid_private *private = ntvfs->private_data;
112 const char *attrs[] = { "sAMAccountName", "UnixID", "UnixName", "sAMAccountType", NULL };
116 struct ldb_message **res;
119 ctx = talloc(req, 0);
120 sidstr = dom_sid_string(ctx, sid);
122 ret = samdb_search(private->samctx, ctx, NULL, &res, attrs, "objectSid=%s", sidstr);
124 DEBUG(2,("Unable to map sid %s to unix gid\n", sidstr));
126 return NT_STATUS_ACCESS_DENIED;
129 /* make sure its not a user */
130 if (samdb_result_uint(res[0], "sAMAccountType", 0) == ATYPE_NORMAL_ACCOUNT) {
131 DEBUG(0,("sid_to_unixgid: sid %s is a ATYPE_NORMAL_ACCOUNT\n", sidstr));
133 return NT_STATUS_ACCESS_DENIED;
136 /* first try to get the gid directly */
137 s = samdb_result_string(res[0], "UnixID", NULL);
139 *gid = strtoul(s, NULL, 0);
144 /* next try via the UnixName attribute */
145 s = samdb_result_string(res[0], "UnixName", NULL);
147 struct group *grp = getgrnam(s);
149 DEBUG(0,("UnixName '%s' for sid %s does not exist as a local group\n", s, sidstr));
151 return NT_STATUS_ACCESS_DENIED;
158 /* finally try via the sAMAccountName attribute */
159 s = samdb_result_string(res[0], "sAMAccountName", NULL);
161 struct group *grp = getgrnam(s);
163 DEBUG(0,("sAMAccountName '%s' for sid %s does not exist as a local group\n", s, sidstr));
165 return NT_STATUS_ACCESS_DENIED;
172 DEBUG(0,("No sAMAccountName for sid %s!?\n", sidstr));
175 return NT_STATUS_ACCESS_DENIED;
178 struct unix_sec_ctx {
186 pull the current security context into a unix_sec_ctx
188 static struct unix_sec_ctx *save_unix_security(TALLOC_CTX *mem_ctx)
190 struct unix_sec_ctx *sec = talloc_p(mem_ctx, struct unix_sec_ctx);
194 sec->uid = geteuid();
195 sec->gid = getegid();
196 sec->ngroups = getgroups(0, NULL);
197 if (sec->ngroups == -1) {
201 sec->groups = talloc_array_p(sec, gid_t, sec->ngroups);
202 if (sec->groups == NULL) {
207 if (getgroups(sec->ngroups, sec->groups) != sec->ngroups) {
216 set the current security context from a unix_sec_ctx
218 static NTSTATUS set_unix_security(struct unix_sec_ctx *sec)
222 if (setgroups(sec->ngroups, sec->groups) != 0) {
223 return NT_STATUS_ACCESS_DENIED;
225 if (setegid(sec->gid) != 0) {
226 return NT_STATUS_ACCESS_DENIED;
228 if (seteuid(sec->uid) != 0) {
229 return NT_STATUS_ACCESS_DENIED;
235 form a unix_sec_ctx from the current session info
237 static NTSTATUS authinfo_to_unix_security(struct ntvfs_module_context *ntvfs,
238 struct smbsrv_request *req,
239 struct auth_serversupplied_info *info,
240 struct unix_sec_ctx **sec)
244 *sec = talloc_p(req, struct unix_sec_ctx);
246 status = sid_to_unixuid(ntvfs, req, info->user_sid, &(*sec)->uid);
247 if (!NT_STATUS_IS_OK(status)) {
251 status = sid_to_unixgid(ntvfs, req, info->primary_group_sid, &(*sec)->gid);
252 if (!NT_STATUS_IS_OK(status)) {
256 (*sec)->ngroups = info->n_domain_groups;
257 (*sec)->groups = talloc_array_p(*sec, gid_t, (*sec)->ngroups);
258 if ((*sec)->groups == NULL) {
259 return NT_STATUS_NO_MEMORY;
262 for (i=0;i<(*sec)->ngroups;i++) {
263 status = sid_to_unixgid(ntvfs, req, info->domain_groups[i], &(*sec)->groups[i]);
264 if (!NT_STATUS_IS_OK(status)) {
273 setup our unix security context according to the session authentication info
275 static NTSTATUS unixuid_setup_security(struct ntvfs_module_context *ntvfs,
276 struct smbsrv_request *req, struct unix_sec_ctx **sec)
278 struct auth_serversupplied_info *info = req->session->session_info->server_info;
279 void *ctx = talloc(req, 0);
280 struct unix_sec_ctx *newsec;
283 *sec = save_unix_security(req);
285 return NT_STATUS_NO_MEMORY;
288 status = authinfo_to_unix_security(ntvfs, req, info, &newsec);
289 if (!NT_STATUS_IS_OK(status)) {
294 status = set_unix_security(newsec);
295 if (!NT_STATUS_IS_OK(status)) {
306 this pass through macro operates on request contexts
308 #define PASS_THRU_REQ(ntvfs, req, op, args) do { \
310 struct unix_sec_ctx *sec; \
311 status = unixuid_setup_security(ntvfs, req, &sec); \
312 if (NT_STATUS_IS_OK(status)) status = ntvfs_next_##op args; \
313 status2 = set_unix_security(sec); \
314 if (!NT_STATUS_IS_OK(status2)) smb_panic("Unable to reset security context"); \
320 connect to a share - used when a tree_connect operation comes in.
322 static NTSTATUS unixuid_connect(struct ntvfs_module_context *ntvfs,
323 struct smbsrv_request *req, const char *sharename)
325 struct unixuid_private *private;
328 private = talloc_p(req->tcon, struct unixuid_private);
330 return NT_STATUS_NO_MEMORY;
333 private->samctx = samdb_connect(private);
334 if (private->samctx == NULL) {
335 return NT_STATUS_INTERNAL_DB_CORRUPTION;
338 ntvfs->private_data = private;
340 PASS_THRU_REQ(ntvfs, req, connect, (ntvfs, req, sharename));
346 disconnect from a share
348 static NTSTATUS unixuid_disconnect(struct ntvfs_module_context *ntvfs,
349 struct smbsrv_tcon *tcon)
351 struct unixuid_private *private = ntvfs->private_data;
354 talloc_free(private);
356 status = ntvfs_next_disconnect(ntvfs, tcon);
365 static NTSTATUS unixuid_unlink(struct ntvfs_module_context *ntvfs,
366 struct smbsrv_request *req, struct smb_unlink *unl)
370 PASS_THRU_REQ(ntvfs, req, unlink, (ntvfs, req, unl));
378 static NTSTATUS unixuid_ioctl(struct ntvfs_module_context *ntvfs,
379 struct smbsrv_request *req, union smb_ioctl *io)
383 PASS_THRU_REQ(ntvfs, req, ioctl, (ntvfs, req, io));
389 check if a directory exists
391 static NTSTATUS unixuid_chkpath(struct ntvfs_module_context *ntvfs,
392 struct smbsrv_request *req, struct smb_chkpath *cp)
396 PASS_THRU_REQ(ntvfs, req, chkpath, (ntvfs, req, cp));
402 return info on a pathname
404 static NTSTATUS unixuid_qpathinfo(struct ntvfs_module_context *ntvfs,
405 struct smbsrv_request *req, union smb_fileinfo *info)
409 PASS_THRU_REQ(ntvfs, req, qpathinfo, (ntvfs, req, info));
415 query info on a open file
417 static NTSTATUS unixuid_qfileinfo(struct ntvfs_module_context *ntvfs,
418 struct smbsrv_request *req, union smb_fileinfo *info)
422 PASS_THRU_REQ(ntvfs, req, qfileinfo, (ntvfs, req, info));
429 set info on a pathname
431 static NTSTATUS unixuid_setpathinfo(struct ntvfs_module_context *ntvfs,
432 struct smbsrv_request *req, union smb_setfileinfo *st)
436 PASS_THRU_REQ(ntvfs, req, setpathinfo, (ntvfs, req, st));
444 static NTSTATUS unixuid_open(struct ntvfs_module_context *ntvfs,
445 struct smbsrv_request *req, union smb_open *io)
449 PASS_THRU_REQ(ntvfs, req, open, (ntvfs, req, io));
457 static NTSTATUS unixuid_mkdir(struct ntvfs_module_context *ntvfs,
458 struct smbsrv_request *req, union smb_mkdir *md)
462 PASS_THRU_REQ(ntvfs, req, mkdir, (ntvfs, req, md));
470 static NTSTATUS unixuid_rmdir(struct ntvfs_module_context *ntvfs,
471 struct smbsrv_request *req, struct smb_rmdir *rd)
475 PASS_THRU_REQ(ntvfs, req, rmdir, (ntvfs, req, rd));
481 rename a set of files
483 static NTSTATUS unixuid_rename(struct ntvfs_module_context *ntvfs,
484 struct smbsrv_request *req, union smb_rename *ren)
488 PASS_THRU_REQ(ntvfs, req, rename, (ntvfs, req, ren));
496 static NTSTATUS unixuid_copy(struct ntvfs_module_context *ntvfs,
497 struct smbsrv_request *req, struct smb_copy *cp)
501 PASS_THRU_REQ(ntvfs, req, copy, (ntvfs, req, cp));
509 static NTSTATUS unixuid_read(struct ntvfs_module_context *ntvfs,
510 struct smbsrv_request *req, union smb_read *rd)
514 PASS_THRU_REQ(ntvfs, req, read, (ntvfs, req, rd));
522 static NTSTATUS unixuid_write(struct ntvfs_module_context *ntvfs,
523 struct smbsrv_request *req, union smb_write *wr)
527 PASS_THRU_REQ(ntvfs, req, write, (ntvfs, req, wr));
535 static NTSTATUS unixuid_seek(struct ntvfs_module_context *ntvfs,
536 struct smbsrv_request *req, struct smb_seek *io)
540 PASS_THRU_REQ(ntvfs, req, seek, (ntvfs, req, io));
548 static NTSTATUS unixuid_flush(struct ntvfs_module_context *ntvfs,
549 struct smbsrv_request *req, struct smb_flush *io)
553 PASS_THRU_REQ(ntvfs, req, flush, (ntvfs, req, io));
561 static NTSTATUS unixuid_close(struct ntvfs_module_context *ntvfs,
562 struct smbsrv_request *req, union smb_close *io)
566 PASS_THRU_REQ(ntvfs, req, close, (ntvfs, req, io));
574 static NTSTATUS unixuid_exit(struct ntvfs_module_context *ntvfs,
575 struct smbsrv_request *req)
579 PASS_THRU_REQ(ntvfs, req, exit, (ntvfs, req));
585 logoff - closing files
587 static NTSTATUS unixuid_logoff(struct ntvfs_module_context *ntvfs,
588 struct smbsrv_request *req)
592 PASS_THRU_REQ(ntvfs, req, logoff, (ntvfs, req));
600 static NTSTATUS unixuid_lock(struct ntvfs_module_context *ntvfs,
601 struct smbsrv_request *req, union smb_lock *lck)
605 PASS_THRU_REQ(ntvfs, req, lock, (ntvfs, req, lck));
611 set info on a open file
613 static NTSTATUS unixuid_setfileinfo(struct ntvfs_module_context *ntvfs,
614 struct smbsrv_request *req,
615 union smb_setfileinfo *info)
619 PASS_THRU_REQ(ntvfs, req, setfileinfo, (ntvfs, req, info));
626 return filesystem space info
628 static NTSTATUS unixuid_fsinfo(struct ntvfs_module_context *ntvfs,
629 struct smbsrv_request *req, union smb_fsinfo *fs)
633 PASS_THRU_REQ(ntvfs, req, fsinfo, (ntvfs, req, fs));
639 return print queue info
641 static NTSTATUS unixuid_lpq(struct ntvfs_module_context *ntvfs,
642 struct smbsrv_request *req, union smb_lpq *lpq)
646 PASS_THRU_REQ(ntvfs, req, lpq, (ntvfs, req, lpq));
652 list files in a directory matching a wildcard pattern
654 static NTSTATUS unixuid_search_first(struct ntvfs_module_context *ntvfs,
655 struct smbsrv_request *req, union smb_search_first *io,
656 void *search_private,
657 BOOL (*callback)(void *, union smb_search_data *))
661 PASS_THRU_REQ(ntvfs, req, search_first, (ntvfs, req, io, search_private, callback));
666 /* continue a search */
667 static NTSTATUS unixuid_search_next(struct ntvfs_module_context *ntvfs,
668 struct smbsrv_request *req, union smb_search_next *io,
669 void *search_private,
670 BOOL (*callback)(void *, union smb_search_data *))
674 PASS_THRU_REQ(ntvfs, req, search_next, (ntvfs, req, io, search_private, callback));
680 static NTSTATUS unixuid_search_close(struct ntvfs_module_context *ntvfs,
681 struct smbsrv_request *req, union smb_search_close *io)
685 PASS_THRU_REQ(ntvfs, req, search_close, (ntvfs, req, io));
690 /* SMBtrans - not used on file shares */
691 static NTSTATUS unixuid_trans(struct ntvfs_module_context *ntvfs,
692 struct smbsrv_request *req, struct smb_trans2 *trans2)
696 PASS_THRU_REQ(ntvfs, req, trans, (ntvfs, req, trans2));
702 initialise the unixuid backend, registering ourselves with the ntvfs subsystem
704 NTSTATUS ntvfs_unixuid_init(void)
707 struct ntvfs_ops ops;
711 /* fill in the name and type */
712 ops.name = "unixuid";
713 ops.type = NTVFS_DISK;
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 /* register ourselves with the NTVFS subsystem. */
746 ret = register_backend("ntvfs", &ops);
748 if (!NT_STATUS_IS_OK(ret)) {
749 DEBUG(0,("Failed to register unixuid backend!\n"));