Merge lp:~raphink/byobu/acl into lp:byobu

Proposed by Raphaël Pinson
Status: Needs review
Proposed branch: lp:~raphink/byobu/acl
Merge into: lp:byobu
Diff against target: 266 lines (+218/-4)
1 file modified
usr/bin/byobu-config (+218/-4)
To merge this branch: bzr merge lp:~raphink/byobu/acl
Reviewer Review Type Date Requested Status
Dustin Kirkland  Needs Fixing
Review via email: mp+18205@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Raphaël Pinson (raphink) wrote :

Hi :-Dustin,

This branch adds a menu entry in byobu-config to deal with basic ACLs.

Ideally, I wanted to have a menu with existing ACLs to modify them, and another one to add new ACLs. As it turned out, I couldn't find out how to read the current ACLs for the screen. The only command I've found is ^A:displays, but it's a paged display that cannot be parsed, and it doesn't list all ACLs. As a result, you have to specify the full ACLs for every change.

To apply the ACLs, I chose to use a tempfile since there were a few commands to launch. You might prefer to launch the commands one by one instead.

Finally, there's the issue of the setuid root bit, but screen prints a message about that when an invited user tries to join the screen, so it's clear enough this way (with a bit of doc probably).

Cheers,

Raphaël

lp:~raphink/byobu/acl updated
905. By Raphaël Pinson <raphink@rpinson>

Main menu has height 10 now

906. By Raphaël Pinson <raphink@rpinson>

Dump ACL when made and allow to modify them

907. By Raphaël Pinson <raphink@rpinson>

No need to remove acls from the "Add ACL" menu

908. By Raphaël Pinson <raphink@rpinson>

Check for setuid root to allow multiuser functions

909. By Raphaël Pinson <raphink@rpinson>

Nicer check for setuid root

910. By Raphaël Pinson <raphink@rpinson>

Fix execuseracl call

911. By Raphaël Pinson <raphink@rpinson>

Reimplement "Remove all rights" in updateacl

Revision history for this message
Dustin Kirkland  (kirkland) wrote :

Hi Rafael-

First of all, thanks a bunch for the branch. I think it's a great idea to expose and make screen sharing easier for Byobu users.

As for the implementation, I'm not sure putting all of this into byobu-config is the best way to go about it. Let's discuss it a little. (I'm just now getting Lucid behind me, and opening the byobu tree for Maverick).

What do you think about creating two new utilities, /usr/bin/byobu-share and /usr/bin/byobu-unshare, that toggle the acl's on and off?

Perhaps byobu-share takes a whitespace list of users to share with. The assumption (if unspecified) is read-only. Or the user can add --rw to share in read-write mode.

I suggest that we get byobu-share and byobu-unshare working well first, and once we're satisfied with it (and the surround security concerns), then we add a menu option that just calls these external utilities.

As an Ubuntu developer, I'm a little concerned that the security team might not like such a package in Ubuntu Main (but I'll try to deal with that separately from Byobu as an upstream project).

What do you think? Would you be willing to separate this functionality into two separate scripts (either shell or python is fine) that does this?

review: Needs Fixing
Revision history for this message
Raphaël Pinson (raphink) wrote :

Hi Dustin,

2010/4/24 Dustin Kirkland <email address hidden>

> Review: Needs Fixing
>

Yep, I totally agree that it needs fixing.

First of all, thanks a bunch for the branch. I think it's a great idea to
> expose and make screen sharing easier for Byobu users.
>
> As for the implementation, I'm not sure putting all of this into
> byobu-config is the best way to go about it. Let's discuss it a little.
> (I'm just now getting Lucid behind me, and opening the byobu tree for
> Maverick).
>
> What do you think about creating two new utilities, /usr/bin/byobu-share
> and /usr/bin/byobu-unshare, that toggle the acl's on and off?
>
>
Well as you probably noticed, I haven't touched this branch for a while. The
reason is that I couldn't properly access the acls that screen knows about
at a given time. This is a known bug/feature request in screen, that has
been in the whishlist since about 10 years (from reading the changelog on
this subject).

As a result, the changes I've made to byobu allow me to set acls in screen
(provided the setuid root bit is set on the binary of course) but not to
modify them or even display the currently set acls. I came up with a model
that stored the acls that byobu created so that I could find them and modify
them, but there are several issues with this way of doing things:
 * if the users use the builtin acl commands in screen, I have no idea what
they changed and I can't display the new acls ;
 * I currently can't properly support multi-session, which means byobu
thinks the set acls for a session applies to all sessions even though
they've never been applied there ;
 * I don't flush the known acls when the session stops, so when a new
session is started, byobu thinks acls are already applied when they are not.

All this to say that really this feature needs a patch in screen itself, to
allow accessing the current acls somewhere (and not in a non-parseable pager
like screen often displays info). I've begun looking at the code for acls,
but my C skills are very poor, and the code is quite complicated I find.

> As an Ubuntu developer, I'm a little concerned that the security team might
> not like such a package in Ubuntu Main (but I'll try to deal with that
> separately from Byobu as an upstream project).
>
>
I agree entirely with this. Perhaps there could be a debconf question in the
screen package to ask users if they want screen set with a setuid root bit.
After all, this feature is not only useful for byobu, and dealing with it in
debconf would allow to do it cleanly with packaging tools, when most users
would override the setuid bit manually.

I'd be happy to discuss this with you some time soon.

Raphael

Unmerged revisions

911. By Raphaël Pinson <raphink@rpinson>

Reimplement "Remove all rights" in updateacl

910. By Raphaël Pinson <raphink@rpinson>

Fix execuseracl call

909. By Raphaël Pinson <raphink@rpinson>

Nicer check for setuid root

908. By Raphaël Pinson <raphink@rpinson>

Check for setuid root to allow multiuser functions

907. By Raphaël Pinson <raphink@rpinson>

No need to remove acls from the "Add ACL" menu

906. By Raphaël Pinson <raphink@rpinson>

Dump ACL when made and allow to modify them

905. By Raphaël Pinson <raphink@rpinson>

Main menu has height 10 now

904. By Raphaël Pinson <raphink@rpinson>

Added Remove all ACL button

903. By Raphaël Pinson <raphink@rpinson>

Add ACL menu

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'usr/bin/byobu-config'
2--- usr/bin/byobu-config 2010-01-12 14:46:44 +0000
3+++ usr/bin/byobu-config 2010-02-03 16:43:15 +0000
4@@ -22,7 +22,7 @@
5 # ./debian/rules get-po
6
7
8-import sys, os, os.path, time, string, commands, gettext, glob, snack
9+import sys, os, os.path, time, string, commands, gettext, glob, snack, pwd, tempfile, stat
10 from ConfigParser import SafeConfigParser
11 from snack import *
12
13@@ -37,7 +37,9 @@
14 DOC = "%s/.%s/%s" % (HOME, PKG, DOC)
15 DEF_ESC="A"
16 RELOAD = "If you are using the default set of keybindings, press\n<F5> or <ctrl-a-R> to activate these changes.\n\nOtherwise, exit this screen session and start a new one."
17-RELOAD_FLAG="/var/run/screen/S-"+USER+"/"+PKG+".reload-required"
18+SOCKET_DIR="/var/run/screen/S-"+USER+"/"
19+RELOAD_FLAG=SOCKET_DIR+PKG+".reload-required"
20+ACL_FILE=SOCKET_DIR+PKG+".acl"
21 RELOAD_CMD="screen -X at 0 source $HOME/."+PKG+"/profile"
22 ESC = ''
23 snack.hotkeys[ESC] = ord(ESC)
24@@ -89,7 +91,7 @@
25 installtext=_("Byobu currently does not launch at login (toggle on)")
26
27
28- li = Listbox(height = 9, width = 60, returnExit = 1)
29+ li = Listbox(height = 10, width = 60, returnExit = 1)
30 li.append(_("Help"), 1)
31 li.append(_("Change Byobu's background color"), 2)
32 li.append(_("Change Byobu's foreground color"), 3)
33@@ -98,7 +100,8 @@
34 li.append(_("Change escape sequence"), 6)
35 li.append(_("Create new windows"), 7)
36 li.append(_("Manage default windows"), 8)
37- li.append(installtext, 9)
38+ li.append(_("Invite users or modify ACLs"), 9)
39+ li.append(installtext, 10)
40 bb = ButtonBar(screen, (("Exit", "exit", ESC),), compact=1)
41
42 g = GridForm(screen, _(" Byobu Configuration Menu"), 1, 2)
43@@ -404,6 +407,215 @@
44
45 return 100
46
47+def execuseracl(userlist, actions, acl):
48+ commandfile=tempfile.mkstemp()
49+ f=open(commandfile[1], 'w')
50+ try:
51+ for user in userlist:
52+ f.write("aclumask %s%s\n" % (user, acl))
53+ f.write("aclchg %s %s \"#?\"\n" % (user, acl))
54+ f.write("aclchg %s +x \"%s\"\n" % (user, " ".join(actions)))
55+ f.write("multiuser on\n")
56+ except IOError:
57+ return None
58+ finally:
59+ f.close()
60+ commands.getoutput("screen -X source %s" % commandfile[1])
61+
62+ return 100
63+
64+def getuseracl():
65+ users=[]
66+ if not os.path.isfile(ACL_FILE):
67+ return users
68+
69+ aclfile=open(ACL_FILE, 'r')
70+ try:
71+ acls=aclfile.read().splitlines()
72+ except IOError:
73+ return None
74+ finally:
75+ aclfile.close()
76+
77+ for acl in acls:
78+ users.append(acl.split(':'))
79+
80+ return users
81+
82+def updateacls(acls):
83+ aclfile=open(ACL_FILE, 'w')
84+ try:
85+ for acl in acls:
86+ aclfile.write("%s\n" % ":".join(acl))
87+ except IOError:
88+ return None
89+ finally:
90+ aclfile.close()
91+
92+def adduseracl(screen, size, acls):
93+ rl=Label("Select users:")
94+ count=0
95+ userlist=[]
96+ loggedusers=[]
97+ for line in commands.getoutput('who').splitlines():
98+ fields=line.split()
99+ if fields[0] not in userlist:
100+ loggedusers.append(fields[0])
101+
102+ allusers=pwd.getpwall()
103+
104+ # Dump users already with ACLs
105+ acledusers=[]
106+ for acl in acls:
107+ acledusers.append(acl[0])
108+
109+ # Sort users with logged users first
110+ # then other users >= 1000
111+ # then root, then others
112+ loggeduserslist=[]
113+ otheruserslist=[]
114+ otherslist=[]
115+ for user in allusers:
116+ if user[0] is not "root" and user[0] not in acledusers:
117+ if user[0] in loggedusers:
118+ loggeduserslist.append(user[0])
119+ elif user[2] >= 1000:
120+ otheruserslist.append(user[0])
121+ else:
122+ otherslist.append(user[0])
123+
124+ loggeduserslist.sort()
125+ otheruserslist.sort()
126+ otherslist.sort()
127+
128+ userlist.extend(loggeduserslist)
129+ userlist.extend(otheruserslist)
130+ if "root" not in acledusers:
131+ userlist.append("root")
132+ userlist.extend(otherslist)
133+
134+ if len(userlist) > 10:
135+ scroll=1
136+ size=10
137+ else:
138+ scroll=0
139+ size = len(userlist)
140+ r=CheckboxTree(size, scroll=scroll)
141+
142+ invitedusers=[]
143+ for user in userlist:
144+ r.append(user,count,selected=0)
145+ count=count+1
146+ bb = ButtonBar(screen, ((_("Apply"), "apply"), (_("Cancel"), "cancel", ESC)), compact = 1)
147+ g = GridForm(screen, _("Add new ACL:"), 2, 6)
148+ acl=Entry(7, text="+r-w-x", returnExit=1)
149+ acll=Label(_("ACL: "))
150+
151+
152+ g.add(rl, 0, 0, anchorLeft=1, anchorTop=1, padding=(4,0,0,1))
153+ g.add(r, 1, 0)
154+
155+ # TODO: use a list of avail actions instead?
156+ actions=Entry(20, text="prev next select detach")
157+ actionsl=Label(_("Allowed actions (* for all): "))
158+
159+ g.add(acll, 0, 2, anchorLeft=1,padding=(4,1,0,1))
160+ g.add(acl, 1, 2, anchorLeft=1)
161+ g.add(actionsl, 0, 3, anchorLeft=1, anchorTop=1,padding=(4,0,0,1))
162+ g.add(actions, 1, 3, anchorLeft=1)
163+
164+ g.add(bb, 0, 5, padding=(4,1,0,0))
165+
166+ if bb.buttonPressed(g.runOnce()) != "cancel":
167+ count=0
168+ for user in userlist:
169+ if r.getEntryValue(count)[1]:
170+ invitedusers.append(user)
171+ useracl=(user, acl.value(), actions.value())
172+ acls.append(useracl)
173+ count=count+1
174+ execuseracl(invitedusers, actions.value().split(), acl.value())
175+ return 100
176+
177+def updateacl(screen, size, acls, id):
178+ useracl=acls[id]
179+
180+ bb = ButtonBar(screen, ((_("Apply"), "apply"), (_("Cancel"), "cancel", ESC)), compact = 1)
181+ g = GridForm(screen, _("Update ACL for user %s:" % useracl[0]), 2, 6)
182+
183+ acl=Entry(7, text=useracl[1], returnExit=1)
184+ acll=Label(_("ACL: "))
185+
186+ actions=Entry(20, text=useracl[2], returnExit=1)
187+ actionsl=Label(_("Allowed actions (* for all): "))
188+
189+ rmall=Checkbox(_("Remove all ACL for this user"))
190+
191+ g.add(acll, 0, 2, anchorLeft=1,padding=(4,1,0,1))
192+ g.add(acl, 1, 2, anchorLeft=1)
193+ g.add(actionsl, 0, 3, anchorLeft=1, anchorTop=1,padding=(4,0,0,1))
194+ g.add(actions, 1, 3, anchorLeft=1)
195+
196+ g.add(rmall, 1, 4, anchorLeft=1, padding=(4,1,0,1))
197+
198+ g.add(bb, 0, 5, padding=(4,1,0,0))
199+
200+ if bb.buttonPressed(g.runOnce()) != "cancel":
201+ if rmall.value():
202+ commands.getoutput("screen -X acldel %s" % useracl[0])
203+ acls.pop(id)
204+ else:
205+ userlist=[]
206+ userlist.append(useracl[0])
207+ execuseracl(userlist, actions.value().split(), acl.value())
208+ acls[id]=(useracl[0], acl.value(), actions.value())
209+
210+ return 100
211+
212+def inviteusers(screen, size):
213+ acls=getuseracl()
214+ bb = ButtonBar(screen, ((_("Apply"), "apply"), (_("Cancel"), "cancel", ESC)), compact = 1)
215+ g = GridForm(screen, _("Invite users of modify ACL:"), 2, 6)
216+
217+ # Check if screen is setuid root (mode=3633)
218+ mode = os.stat('/usr/bin/screen')
219+ if not mode.st_mode & stat.S_ISUID:
220+ msgtxt=_("""
221+/usr/bin/screen must be setuid root to use this option.
222+
223+Execute "chmod 6755 /usr/bin/screen" as root
224+ and relaunch byobu.
225+""")
226+ msg = Textbox(height = 6, width = 60, text=(msgtxt))
227+ ok = Button("OK")
228+ g.add(msg, 0, 0)
229+ g.add(ok, 0, 1)
230+
231+ g.runOnce()
232+ return 100
233+
234+ lil=Label("Select a user:")
235+ li = Listbox(height = 6, width = 60, returnExit = 1)
236+ count=0
237+ for acl in acls:
238+ li.append(acl[0], count)
239+ count=count+1
240+ li.append("Add new ACL", count)
241+
242+ g.add(lil, 0, 0, anchorLeft=1, anchorTop=1, padding=(4,0,0,1))
243+ g.add(li, 1, 0)
244+
245+ g.add(bb, 0, 5, padding=(4,1,0,0))
246+
247+ if bb.buttonPressed(g.runOnce()) != "cancel":
248+ if li.current() == count:
249+ adduseracl(screen, size, acls)
250+ else:
251+ updateacl(screen, size, acls, li.current())
252+ updateacls(acls)
253+
254+ return 100
255+
256 def install(screen, size, isInstalled):
257 if not isInstalled:
258 out = commands.getoutput("byobu-launcher-install")
259@@ -530,6 +742,8 @@
260 elif tag == 8:
261 tag = defaultwindows(screen, size)
262 elif tag == 9:
263+ tag = inviteusers(screen, size)
264+ elif tag == 10:
265 tag = install(screen, size, isInstalled)
266 isInstalled=(tag == 100)
267

Subscribers

People subscribed via source and target branches