From patchwork Mon Apr 1 04:51:19 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steve French X-Patchwork-Id: 10879113 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 821701669 for ; Mon, 1 Apr 2019 04:51:37 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 417D928723 for ; Mon, 1 Apr 2019 04:51:37 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3F5632877E; Mon, 1 Apr 2019 04:51:37 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DC_PNG_UNO_LARGO, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4F64128872 for ; Mon, 1 Apr 2019 04:51:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727351AbfDAEve (ORCPT ); Mon, 1 Apr 2019 00:51:34 -0400 Received: from mail-pg1-f178.google.com ([209.85.215.178]:34012 "EHLO mail-pg1-f178.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725860AbfDAEve (ORCPT ); Mon, 1 Apr 2019 00:51:34 -0400 Received: by mail-pg1-f178.google.com with SMTP id v12so4112204pgq.1; Sun, 31 Mar 2019 21:51:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=e4q3UnywIGlhN/60TnVC5Khr7Jhu98TCOxIdZG3osu8=; b=Vgh8oJ9MxkDXQrmCxGGnBtnHBcQfwm7a9ooKN46GgBpzHhRoHf6Tz8fcuP80f9eokC WntEc/FqWcyFJEPoP+5ik6kElSjkrMcs9xttTIh1s0QnAdVrsCSUjAfLaJpiXmjRf0Aw Q6+zhLx41aBGeO/RREOZf9Tn/YdmOR6ZcP0xTQ/qjv8R5E3xWvWtBc8JaUqqjD5bDfFA 24ixSzxdHUWXtTEe4FIxaUIFGb56uQML2LZ5ajhouaUMKHQl+6rFqpEWDoLJns3MD8HQ IBn7+XwjOCGybpbEWelJEmXBWZof3CY/BwKIX4o6GgMsmNEbYmmu/1fMXvOKKHcrcW22 iCEA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=e4q3UnywIGlhN/60TnVC5Khr7Jhu98TCOxIdZG3osu8=; b=SJyGVC6eDT+sObyf1R0Yd+3gaAI0sswNL3ff6JjGqSX+uHsVUL/9JDncleYUFQArue qX+PU4sS3vfhrW/Nxaf/CtbcgPax0i4yX4mdbV/6If3410/xCInayULwF5C8lSt/4O8M GyV0zOLztT7ICdKaory4QnVkDu6v95ubnOs7F8Jn1oVAinf4O7fEZFk7dTYh2CXdwf0h oFifVBvePEd4SWVIoHptlkFDSNuFJ/9gvkt0abl7VMnnkfoecyVh0ujUhoa26vTN90PH oiuxnbSmequlLBstwYOk4y+01kx+8uQJnqPfXCQ2ainjtKAzDNKF0zow34s6IYSMn3Uh FNGw== X-Gm-Message-State: APjAAAXUmr3IEJqU/HEdJ10jjWB5BVgXxfcBqk3CrWhT/ozi8564RtgX nPutnIg6q496n8yDPYng+NxQxEY6aAGPNVIkk5M= X-Google-Smtp-Source: APXvYqxRZFBIXhGFAQBkWO3j+1J6Bs2VFbglmHNX/7oDBEcTigTV6giSiduUkAYjVkQtgWBolOoZt3wZBhrFIkpW5vw= X-Received: by 2002:a63:fa54:: with SMTP id g20mr4118039pgk.242.1554094291437; Sun, 31 Mar 2019 21:51:31 -0700 (PDT) MIME-Version: 1.0 References: <20190401035417.13738-1-lsahlber@redhat.com> <20190401035417.13738-2-lsahlber@redhat.com> In-Reply-To: <20190401035417.13738-2-lsahlber@redhat.com> From: Steve French Date: Sun, 31 Mar 2019 23:51:19 -0500 Message-ID: Subject: Fwd: [PATCH] secdesc-ui.py: a UI to view the security descriptors on SMB2+ shares To: ronnie sahlberg Cc: CIFS , linux-fsdevel , LKML , samba-technical Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The tool that Ronnie proposed below looks useful (see below) and attached screenshot. With this as a sample (along with 'smbinfo' tool in cifs-utils) and a starting point, those with python/GUI interest should be able to extend it in very interesting ways now that we have the ability to query server information much more broadly. Managing ACLs, quotas, snapshots, alerts and many other fun features across such a broad set of servers (from Samba, to Windows, Azure and the Cloud, Macs, NetApp and various filers). Ronnie, Great idea. ---------- Forwarded message --------- From: Ronnie Sahlberg Date: Sun, Mar 31, 2019 at 10:54 PM Subject: [PATCH] secdesc-ui.py: a UI to view the security descriptors on SMB2+ shares To: linux-cifs Cc: Steve French , Pavel Shilovsky , Ronnie Sahlberg a simple python program with a basic UI to view the security descriptor for SMB2+ resources. With a basic starting point like this my hope is we can get some interest from people with python skills that may want to make it better until it becomes a full-fledged utility. Signed-off-by: Ronnie Sahlberg --- secdesc-ui.py | 421 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 421 insertions(+) create mode 100755 secdesc-ui.py + os.close(f) + + s = struct.unpack_from(' len(sid): + max = len(sid) + self.lb.insert(idx, sid) + if not self.lb.curselection(): + self.lb.selection_set(idx) + self.lb.config(width=max) + self.lb.bind("", self.select_sid) + + self.bas = Button(self.tf, text='Basic', relief=SUNKEN, + command=self.click_bas) + self.bas.grid(row=2, column=2, sticky='NW') + + self.adv = Button(self.tf, text='Advanced', + command=self.click_adv) + self.adv.grid(row=2, column=3, sticky='NW') + + # Basic Panel + self.bf_bas = Frame(master=self.tf, bd=1) + self.bf_bas.grid(row=3, column=0, columnspan=4, padx=5, pady=5) + self.bf_bas_name = Label(self.bf_bas, text='') + self.bf_bas_name.grid(row=0, column=0, columnspan=2, sticky='W') + + row = 1 + self.bf_bas_fc=Checkbutton(self.bf_bas, text='Full Control') + self.bf_bas_fc.grid(row=row, column=0, sticky='W') + self.bf_bas_fc.config(state=DISABLED) + row += 1 + + self.bf_bas_mo=Checkbutton(self.bf_bas, text='Modify') + self.bf_bas_mo.grid(row=row, column=0, sticky='W') + self.bf_bas_mo.config(state=DISABLED) + row += 1 + + self.bf_bas_re=Checkbutton(self.bf_bas, text='Read & Execute') + self.bf_bas_re.grid(row=row, column=0, sticky='W') + self.bf_bas_re.config(state=DISABLED) + row += 1 + + self.bf_bas_rd=Checkbutton(self.bf_bas, text='Read') + self.bf_bas_rd.grid(row=row, column=0, sticky='W') + self.bf_bas_rd.config(state=DISABLED) + row += 1 + + self.bf_bas_wr=Checkbutton(self.bf_bas, text='Write') + self.bf_bas_wr.grid(row=row, column=0, sticky='W') + self.bf_bas_wr.config(state=DISABLED) + row += 1 + + self.bf_bas_sp=Checkbutton(self.bf_bas, text='Special') + self.bf_bas_sp.grid(row=row, column=0, sticky='W') + self.bf_bas_sp.config(state=DISABLED) + row += 1 + + self.show_bas = True + self.update_bf_bas() + + # Advanced Panel + self.bf_adv = Frame(master=self.tf, bd=1) + self.bf_adv.grid(row=3, column=0, columnspan=4, padx=5, pady=5) + self.bf_adv_name = Label(self.bf_adv, text='') + self.bf_adv_name.grid(row=0, column=0, columnspan=2, sticky='W') + + row = 1 + self.bf_adv_fc=Checkbutton(self.bf_adv, text='Full Control') + self.bf_adv_fc.grid(row=row, column=0, sticky='W') + self.bf_adv_fc.config(state=DISABLED) + row += 1 + + self.bf_adv_te=Checkbutton(self.bf_adv, text='Traverse-folder/execute-file') + self.bf_adv_te.grid(row=row, column=0, sticky='W') + self.bf_adv_te.config(state=DISABLED) + row += 1 + + self.bf_adv_lr=Checkbutton(self.bf_adv, text='List-folder/read-data') + self.bf_adv_lr.grid(row=row, column=0, sticky='W') + self.bf_adv_lr.config(state=DISABLED) + row += 1 + + self.bf_adv_ra=Checkbutton(self.bf_adv, text='Read-Attributes') + self.bf_adv_ra.grid(row=row, column=0, sticky='W') + self.bf_adv_ra.config(state=DISABLED) + row += 1 + + self.bf_adv_re=Checkbutton(self.bf_adv, text='Read-Extended-Attributes') + self.bf_adv_re.grid(row=row, column=0, sticky='W') + self.bf_adv_re.config(state=DISABLED) + row += 1 + + self.bf_adv_cw=Checkbutton(self.bf_adv, text='Create-files/write-data') + self.bf_adv_cw.grid(row=row, column=0, sticky='W') + self.bf_adv_cw.config(state=DISABLED) + row += 1 + + self.bf_adv_ca=Checkbutton(self.bf_adv, text='Create-folders/append-data') + self.bf_adv_ca.grid(row=row, column=0, sticky='W') + self.bf_adv_ca.config(state=DISABLED) + row += 1 + + row = 1 + self.bf_adv_wa=Checkbutton(self.bf_adv, text='Write-Attributes') + self.bf_adv_wa.grid(row=row, column=1, sticky='W') + self.bf_adv_wa.config(state=DISABLED) + row += 1 + + self.bf_adv_we=Checkbutton(self.bf_adv, text='Write-Extended-Attributes') + self.bf_adv_we.grid(row=row, column=1, sticky='W') + self.bf_adv_we.config(state=DISABLED) + row += 1 + + self.bf_adv_de=Checkbutton(self.bf_adv, text='Delete') + self.bf_adv_de.grid(row=row, column=1, sticky='W') + self.bf_adv_de.config(state=DISABLED) + row += 1 + + self.bf_adv_rp=Checkbutton(self.bf_adv, text='Read-Permissions') + self.bf_adv_rp.grid(row=row, column=1, sticky='W') + self.bf_adv_rp.config(state=DISABLED) + row += 1 + + self.bf_adv_cp=Checkbutton(self.bf_adv, text='Change-Permissions') + self.bf_adv_cp.grid(row=row, column=1, sticky='W') + self.bf_adv_cp.config(state=DISABLED) + row += 1 + + self.bf_adv_to=Checkbutton(self.bf_adv, text='Take-Ownership') + self.bf_adv_to.grid(row=row, column=1, sticky='W') + self.bf_adv_to.config(state=DISABLED) + row += 1 + + self.bf_adv.grid_remove() + + def select_sid(self, event): + self.click_bas() + + def click_bas(self): + self.adv.config(relief=RAISED) + self.bas.config(relief=SUNKEN) + self.bf_adv.grid_remove() + self.update_bf_bas() + self.bf_bas.grid() + self.show_bas = True + + def click_adv(self): + self.adv.config(relief=SUNKEN) + self.bas.config(relief=RAISED) + self.bf_bas.grid_remove() + self.update_bf_adv() + self.bf_adv.grid() + self.show_bas = False + + def update_bf_adv(self): + ace = self.sd.dacl.ace[self.lb.curselection()[0]] + self.bf_adv_name.config(text='Advanced Permissions for %s' % (ace.sid)) + if ace.mask == FULL_CONTROL: + self.bf_adv_fc.select() + else: + self.bf_adv_fc.deselect() + if ace.mask & TRAV_EXEC == TRAV_EXEC: + self.bf_adv_te.select() + else: + self.bf_adv_te.deselect() + if ace.mask & LIST_READ == LIST_READ: + self.bf_adv_lr.select() + else: + self.bf_adv_lr.deselect() + if ace.mask & READ_ATTR == READ_ATTR: + self.bf_adv_ra.select() + else: + self.bf_adv_ra.deselect() + if ace.mask & READ_XATT == READ_XATT: + self.bf_adv_re.select() + else: + self.bf_adv_re.deselect() + if ace.mask & CREA_WRIT == CREA_WRIT: + self.bf_adv_cw.select() + else: + self.bf_adv_cw.deselect() + if ace.mask & CREA_APPE == CREA_APPE: + self.bf_adv_ca.select() + else: + self.bf_adv_ca.deselect() + if ace.mask & WRIT_ATTR == WRIT_ATTR: + self.bf_adv_wa.select() + else: + self.bf_adv_wa.deselect() + if ace.mask & WRIT_XATT == WRIT_XATT: + self.bf_adv_we.select() + else: + self.bf_adv_we.deselect() + if ace.mask & DELE == DELE: + self.bf_adv_de.select() + else: + self.bf_adv_de.deselect() + if ace.mask & READ_PERM == READ_PERM: + self.bf_adv_rp.select() + else: + self.bf_adv_rp.deselect() + if ace.mask & CHAN_PERM == CHAN_PERM: + self.bf_adv_rp.select() + else: + self.bf_adv_rp.deselect() + if ace.mask & TAKE_OWNR == TAKE_OWNR: + self.bf_adv_to.select() + else: + self.bf_adv_to.deselect() + + def update_bf_bas(self): + ace = self.sd.dacl.ace[self.lb.curselection()[0]] + self.bf_bas_name.config(text='Permissions for %s' % (ace.sid)) + tmp = ace.mask + if ace.mask == FULL_CONTROL: + self.bf_bas_fc.select() + tmp &= ~FULL_CONTROL + else: + self.bf_bas_fc.deselect() + if ace.mask & CHANGE == CHANGE: + self.bf_bas_mo.select() + tmp &= ~CHANGE + else: + self.bf_bas_mo.deselect() + if ace.mask & EREAD == EREAD: + self.bf_bas_re.select() + tmp &= ~EREAD + else: + self.bf_bas_re.deselect() + if ace.mask & ALL_READ_BITS == ALL_READ_BITS: + self.bf_bas_rd.select() + tmp &= ~ALL_READ_BITS + else: + self.bf_bas_rd.deselect() + if ace.mask & EWRITE == EWRITE: + self.bf_bas_wr.select() + tmp &= ~EWRITE + else: + self.bf_bas_wr.deselect() + if tmp: + self.bf_bas_sp.select() + else: + self.bf_bas_sp.deselect() + +CIFS_QUERY_INFO = 0xc018cf07 + +def usage(): + print "Usage: %s " % (sys.argv[0]) + sys.exit() + +class SID: + def __init__(self, buf): + self.sub_authority_count = buf[1] + self.buffer = buf[:8 + self.sub_authority_count * 4] + self.revision = self.buffer[0] + if self.revision != 1: + raise ValueError('SID Revision %d not supported' % + (self.revision)) + self.identifier_authority = 0 + for x in self.buffer[2:8]: + self.identifier_authority = self.identifier_authority * 256 + x + self.sub_authority = [] + for i in range(self.sub_authority_count): + self.sub_authority.append(struct.unpack_from('