/* * smbiod.c * * Copyright (C) 2000, Charles Loep / Corel Corp. * Copyright (C) 2001, Urban Widmark */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "smb_debug.h" #include "request.h" #include "proto.h" enum smbiod_state { SMBIOD_DEAD, SMBIOD_STARTING, SMBIOD_RUNNING, }; static enum smbiod_state smbiod_state = SMBIOD_DEAD; static struct task_struct *smbiod_thread; static DECLARE_WAIT_QUEUE_HEAD(smbiod_wait); static LIST_HEAD(smb_servers); static DEFINE_SPINLOCK(servers_lock); #define SMBIOD_DATA_READY (1<<0) static unsigned long smbiod_flags; static int smbiod(void *); static int smbiod_start(void); /* * called when there's work for us to do */ void smbiod_wake_up(void) { if (smbiod_state == SMBIOD_DEAD) return; set_bit(SMBIOD_DATA_READY, &smbiod_flags); wake_up_interruptible(&smbiod_wait); } /* * start smbiod if none is running */ static int smbiod_start(void) { struct task_struct *tsk; int err = 0; if (smbiod_state != SMBIOD_DEAD) return 0; smbiod_state = SMBIOD_STARTING; __module_get(THIS_MODULE); spin_unlock(&servers_lock); tsk = kthread_run(smbiod, NULL, "smbiod"); if (IS_ERR(tsk)) { err = PTR_ERR(tsk); module_put(THIS_MODULE); } spin_lock(&servers_lock); if (err < 0) { smbiod_state = SMBIOD_DEAD; smbiod_thread = NULL; } else { smbiod_state = SMBIOD_RUNNING; smbiod_thread = tsk; } return err; } /* * register a server & start smbiod if necessary */ int smbiod_register_server(struct smb_sb_info *server) { int ret; spin_lock(&servers_lock); list_add(&server->entry, &smb_servers); VERBOSE("%p\n", server); ret = smbiod_start(); spin_unlock(&servers_lock); return ret; } /* * Unregister a server * Must be called with the server lock held. */ void smbiod_unregister_server(struct smb_sb_info *server) { spin_lock(&servers_lock); list_del_init(&server->entry); VERBOSE("%p\n", server); spin_unlock(&servers_lock); smbiod_wake_up(); smbiod_flush(server); } void smbiod_flush(struct smb_sb_info *server) { struct list_head *tmp, *n; struct smb_request *req; list_for_each_safe(tmp, n, &server->xmitq) { req = list_entry(tmp, struct smb_request, rq_queue); req->rq_errno = -EIO; list_del_init(&req->rq_queue); smb_rput(req); wake_up_interruptible(&req->rq_wait); } list_for_each_safe(tmp, n, &server->recvq) { req = list_entry(tmp, struct smb_request, rq_queue); req->rq_errno = -EIO; list_del_init(&req->rq_queue); smb_rput(req); wake_up_interruptible(&req->rq_wait); } } /* * Wake up smbmount and make it reconnect to the server. * This must be called with the server locked. * * FIXME: add smbconnect version to this */ int smbiod_retry(struct smb_sb_info *server) { struct list_head *head; struct smb_request *req; struct pid *pid = get_pid(server->conn_pid); int result = 0; VERBOSE("state: %d\n", server->state); if (server->state == CONN_VALID || server->state == CONN_RETRYING) goto out; smb_invalidate_inodes(server); /* * Some requests are meaningless after a retry, so we abort them. * One example are all requests using 'fileid' since the files are * closed on retry. */ head = server->xmitq.next; while (head != &server->xmitq) { req = list_entry(head, struct smb_request, rq_queue); head = head->next; req->rq_bytes_sent = 0; if (req->rq_flags & SMB_REQ_NORETRY) { VERBOSE("aborting request %p on xmitq\n", req); req->rq_errno = -EIO; list_del_init(&req->rq_queue); smb_rput(req); wake_up_interruptible(&req->rq_wait); } } /* * FIXME: test the code for retrying request we already sent */ head = server->recvq.next; while (head != &server->recvq) { req = list_entry(head, struct smb_request, rq_queue); head = head->next; #if 0 if (req->rq_flags & SMB_REQ_RETRY) { /* must move the request to the xmitq */ VERBOSE("retrying request %p on recvq\n", req); list_move(&req->rq_queue, &server->xmitq); continue; } #endif VERBOSE("aborting request %p on recvq\n", req); /* req->rq_rcls = ???; */ /* FIXME: set smb error code too? */ req->rq_errno = -EIO; list_del_init(&req->rq_queue); smb_rput(req); wake_up_interruptible(&req->rq_wait); } smb_close_socket(server); if (pid == 0) { /* FIXME: this is fatal, umount? */ printk(KERN_ERR "smb_retry: no connection process\n"); server->state = CONN_RETRIED; goto out; } /* * Change state so that only one retry per server will be started. */ server->state = CONN_RETRYING; /* * Note: use the "priv" flag, as a user process may need to reconnect. */ result = kill_pid(pid, SIGUSR1, 1); if (result) { /* FIXME: this is most likely fatal, umount? */ printk(KERN_ERR "smb_retry: signal failed [%d]\n", result); goto out; } VERBOSE("signalled pid %d\n", pid); /* FIXME: The retried requests should perhaps get a "time boost". */ out: put_pid(pid); return result; } /* * Currently handles lockingX packets. */ static void smbiod_handle_request(struct smb_sb_info *server) { PARANOIA("smbiod got a request ... and we don't implement oplocks!\n"); server->rstate = SMB_RECV_DROP; } /* * Do some IO for one server. */ static void smbiod_doio(struct smb_sb_info *server) { int result; int maxwork = 7; if (server->state != CONN_VALID) goto out; do { result = smb_request_recv(server); if (result < 0) { server->state = CONN_INVALID; smbiod_retry(server); goto out; /* reconnecting is slow */ } else if (server->rstate == SMB_RECV_REQUEST) smbiod_handle_request(server); } while (result > 0 && maxwork-- > 0); /* * If there is more to read then we want to be sure to wake up again. */ if (server->state != CONN_VALID) goto out; if (smb_recv_available(server) > 0) set_bit(SMBIOD_DATA_READY, &smbiod_flags); do { result = smb_request_send_server(server); if (result < 0) { server->state = CONN_INVALID; smbiod_retry(server); goto out; /* reconnecting is slow */ } } while (result > 0); /* * If the last request was not sent out we want to wake up again. */ if (!list_empty(&server->xmitq)) set_bit(SMBIOD_DATA_READY, &smbiod_flags); out: return; } /* * smbiod kernel thread */ static int smbiod(void *unused) { VERBOSE("SMB Kernel thread starting (%d) ...\n", current->pid); for (;;) { struct smb_sb_info *server; struct list_head *pos, *n; /* FIXME: Use poll? */ wait_event_interruptible(smbiod_wait, test_bit(SMBIOD_DATA_READY, &smbiod_flags)); if (signal_pending(current)) { spin_lock(&servers_lock); smbiod_state = SMBIOD_DEAD; spin_unlock(&servers_lock); break; } clear_bit(SMBIOD_DATA_READY, &smbiod_flags); spin_lock(&servers_lock); if (list_empty(&smb_servers)) { smbiod_state = SMBIOD_DEAD; spin_unlock(&servers_lock); break; } list_for_each_safe(pos, n, &smb_servers) { server = list_entry(pos, struct smb_sb_info, entry); VERBOSE("checking server %p\n", server); if (server->state == CONN_VALID) { spin_unlock(&servers_lock); smb_lock_server(server); smbiod_doio(server); smb_unlock_server(server); spin_lock(&servers_lock); } } spin_unlock(&servers_lock); } VERBOSE("SMB Kernel thread exiting (%d) ...\n", current->pid); module_put_and_exit(0); } 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
# Unix SMB/CIFS implementation.
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

"""Tests for samba.dcerpc.security."""

import samba.tests
from samba.dcerpc import security

class SecurityTokenTests(samba.tests.TestCase):

    def setUp(self):
        super(SecurityTokenTests, self).setUp()
        self.token = security.token()

    def test_is_system(self):
        self.assertFalse(self.token.is_system())

    def test_is_anonymous(self):
        self.assertFalse(self.token.is_anonymous())

    def test_has_builtin_administrators(self):
        self.assertFalse(self.token.has_builtin_administrators())

    def test_has_nt_authenticated_users(self):
        self.assertFalse(self.token.has_nt_authenticated_users())

    def test_has_priv(self):
        self.assertFalse(self.token.has_privilege(security.SEC_PRIV_SHUTDOWN))

    def test_set_priv(self):
        self.assertFalse(self.token.has_privilege(security.SEC_PRIV_SHUTDOWN))
        self.assertFalse(self.token.set_privilege(security.SEC_PRIV_SHUTDOWN))
        self.assertTrue(self.token.has_privilege(security.SEC_PRIV_SHUTDOWN))


class SecurityDescriptorTests(samba.tests.TestCase):

    def setUp(self):
        super(SecurityDescriptorTests, self).setUp()
        self.descriptor = security.descriptor()

    def test_from_sddl(self):
        desc = security.descriptor.from_sddl("O:AOG:DAD:(A;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)", security.dom_sid("S-2-0-0"))
        self.assertEquals(desc.group_sid, security.dom_sid('S-2-0-0-512'))
        self.assertEquals(desc.owner_sid, security.dom_sid('S-1-5-32-548'))
        self.assertEquals(desc.revision, 1)
        self.assertEquals(desc.sacl, None)
        self.assertEquals(desc.type, 0x8004)

    def test_from_sddl_invalidsddl(self):
        self.assertRaises(TypeError,security.descriptor.from_sddl, "foo",security.dom_sid("S-2-0-0"))

    def test_from_sddl_invalidtype1(self):
        self.assertRaises(TypeError, security.descriptor.from_sddl, security.dom_sid('S-2-0-0-512'),security.dom_sid("S-2-0-0"))

    def test_from_sddl_invalidtype2(self):
        sddl = "O:AOG:DAD:(A;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)"
        self.assertRaises(TypeError, security.descriptor.from_sddl, sddl,
                "S-2-0-0")

    def test_as_sddl(self):
        text = "O:AOG:DAD:(A;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)"
        dom = security.dom_sid("S-2-0-0")
        desc1 = security.descriptor.from_sddl(text, dom)
        desc2 = security.descriptor.from_sddl(desc1.as_sddl(dom), dom)
        self.assertEquals(desc1.group_sid, desc2.group_sid)
        self.assertEquals(desc1.owner_sid, desc2.owner_sid)
        self.assertEquals(desc1.sacl, desc2.sacl)
        self.assertEquals(desc1.type, desc2.type)

    def test_as_sddl_invalid(self):
        text = "O:AOG:DAD:(A;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)"
        dom = security.dom_sid("S-2-0-0")
        desc1 = security.descriptor.from_sddl(text, dom)
        self.assertRaises(TypeError, desc1.as_sddl,text)


    def test_as_sddl_no_domainsid(self):
        dom = security.dom_sid("S-2-0-0")
        text = "O:AOG:DAD:(A;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)"
        desc1 = security.descriptor.from_sddl(text, dom)
        desc2 = security.descriptor.from_sddl(desc1.as_sddl(), dom)
        self.assertEquals(desc1.group_sid, desc2.group_sid)
        self.assertEquals(desc1.owner_sid, desc2.owner_sid)
        self.assertEquals(desc1.sacl, desc2.sacl)
        self.assertEquals(desc1.type, desc2.type)

    def test_domsid_nodomsid_as_sddl(self):
        dom = security.dom_sid("S-2-0-0")
        text = "O:AOG:DAD:(A;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)"
        desc1 = security.descriptor.from_sddl(text, dom)
        self.assertNotEqual(desc1.as_sddl(), desc1.as_sddl(dom))

    def test_split(self):
        dom = security.dom_sid("S-2-0-7")
        self.assertEquals((security.dom_sid("S-2-0"), 7), dom.split())


class DomSidTests(samba.tests.TestCase):

    def test_parse_sid(self):
        sid = security.dom_sid("S-1-5-21")
        self.assertEquals("S-1-5-21", str(sid))

    def test_sid_equal(self):
        sid1 = security.dom_sid("S-1-5-21")
        sid2 = security.dom_sid("S-1-5-21")
        self.assertEquals(sid1, sid1)
        self.assertEquals(sid1, sid2)

    def test_random(self):
        sid = security.random_sid()
        self.assertTrue(str(sid).startswith("S-1-5-21-"))

    def test_repr(self):
        sid = security.random_sid()
        self.assertTrue(repr(sid).startswith("dom_sid('S-1-5-21-"))


class PrivilegeTests(samba.tests.TestCase):

    def test_privilege_name(self):
        self.assertEquals("SeShutdownPrivilege",
                security.privilege_name(security.SEC_PRIV_SHUTDOWN))

    def test_privilege_id(self):
        self.assertEquals(security.SEC_PRIV_SHUTDOWN,
                security.privilege_id("SeShutdownPrivilege"))