computerlyrik/dymoprint

Permission Denied on printer

nathancatlow opened this issue · 12 comments

Access is denied on printer when using udev TAG+="uaccess" rule;

# cat /etc/udev/rules.d/91-dymo-1001.rules 
ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="0922", ATTRS{idProduct}=="1001", MODE="0660" TAG+="uaccess"

Responsibility for setting the permission based on the 'uaccess' TAG is done in (arch linux);

/usr/lib/udev/rules.d/73-seat-late.rules

The dymo rule must come lexically before that rule, so need to rename the rule.

# cd /etc/udev/rules.d
# mv 91-dymo-1001.rules 50-dymo-1001.rules

This took some searching, the filename probably needs to be changed.

Thanks for the report. I suspect you're not using the latest version. I'm currently not recommending setting the uaccess tag.

The rule to add should be similar to that currently in the README:

image

Could you please upgrade and try again?

Sorry to be a buzz-kill, I would not have this rule on my system, this gives all and any user (others) on the system read/write capability on the device. This includes daemons, the user 'nobody' etc. This could be logged as a security issue.

It becomes more acute because the dymoprint also has a built-in permanent r/w local drive, who knows if usb commands can write to that drive and place viruses/trojans or whatever.

Traditionally distributions used the 'plugdev' group for this ('lp' also for printers) but even this was deemed less secure, hence the introduction of TAG+='uaccess'.

I didn't realise that the rule had to be below 70, so had massively frustrating and varying results until I changed the name of the file to be '50-dymo-1001.rules', now it works perfectly and no reboot was required.

IMHO using 'uaccess' is the way to go, I think a lot of issues were caused by the rule being prefixed by '91-'.

Anyway it is your choice, hopefully this should give a bit of background and people can have the information they need to make it work securely. Thank you for your time, still lots of love for this project.

@nathancatlow we held a discussion about that a while ago, and if you could come up with a rule file template that will work for 99% of Linux users and address your security concerns, it will be greatly appreciated.
Note that "lp" group doesn't seem to exist on some distros, similarly "plugdev" is not a thing in Arch world.

Thanks a lot @nathancatlow for the context, I really appreciate it. And great summary @tomek-szczesny.

It would be great if we can find a more secure way to grant access, but this seems very complicated due to variations between distributions. It's also very difficult to test. I'm open to proposals.

The thread mentioned in #67 (comment) was #56, and @nathancatlow is actually a commenter there.

We might decide to go the route of looking at which groups exist, and trying to infer stuff about the udev config, but in general this type of code seems extremely difficult to maintain and update.

Sorry, I have limited time to look at this sort of stuff, especially an unexpected 2hr deep-dive into the internals of udev. I like to at least have an answer for you and not just pile in with more problems. When I discovered it was the '91' prefix I almost wept with despair after rebooting, working/not working etc just to then have it work straight away when prefixed with '50'.

You will not be able to do a 'one-size-fits-all' solution, distributions change all the time. but something like the following should give you a head start (pretty much what @maresb said.

#!/bin/bash
if grep -q 'TAG+="uaccess"' /usr/lib/udev/rules.d/*.rules; then
  echo echo \"ACTION==\"add\", SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0922\", ATTRS{idProduct}==\"1001\", MODE=\"0660\" TAG+=\"uaccess\" \| sudo tee /etc/udev/rules.d/50-dymo-1001.rules;
elif grep -q '^plugdev:' /etc/group; then
  echo echo \"ACTION==\"add\", SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0922\", ATTRS{idProduct}==\"1001\", GROUP=\"plugdev\", MODE=\"0660\" \| sudo tee /etc/udev/rules.d/50-dymo-1001.rules;
elif grep -q '^lp:' /etc/group; then
  echo echo \"ACTION==\"add\", SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0922\", ATTRS{idProduct}==\"1001\", GROUP=\"lp\", MODE=\"0660\" \| sudo tee /etc/udev/rules.d/50-dymo-1001.rules;
fi;

Thanks a lot @nathancatlow for the suggestion. I don't think this is something we can solve right away, so I think it's perfectly fine to gather information at this stage.

A few notes on your proposal:

I'm inclined to do this in Python inside of dymoprint rather than Bash.

On my system (Ubuntu 20.04) the udev rules directory is /etc/udev/rules.d/ while for you it's /usr/lib/udev/rules.d/. So already the current instructions fail since they suggest writing to the wrong directory.

We probably want to check which groups the current user is a member of. It's not so helpful to grant access to a group where the user isn't a member.

I think that granting access to both "lp" and "plugdev", regardless if such groups even exist, is a good start.

Speaking of paths:

udev rules written by the administrator go in /etc/udev/rules.d/, their file name has to end with .rules. The udev rules shipped with various packages are found in /usr/lib/udev/rules.d/. If there are two files by the same name under /usr/lib and /etc, the ones in /etc take precedence.

I love Arch Wiki.

Ah, great find! My take is that since we are making a Python package and not a system package, we require administrator intervention which implies we should ask the user to write to /etc/udev/rules.d/.

Yes, the ones in /etc/udev/rules.d are local additions (and might be empty). By searching /usr/lib/udev/rules.d I was trying to establish that 'uaccess' tags were already used by the default rules and infer that they were supported by the system in question.

The user won't be a member of 'lp' or 'plugdev' by default, unless they have already installed a printer or usb pluggable device, this can also be checked through the /etc/group file and using the os library to get current username.

There is no reason that this cannot be all done in python, to print out a more correct line than the default one plus an optional usermod

#!/usr/bin/python
import os
import glob
import re

prefix="echo ACTION==\"add\", SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"0922\", ATTRS{idProduct}==\"1001\", MODE=\"0660\""
postfix=" | sudo tee /etc/udev/rules.d/50-dymo-1001.rules;"

def grep( fname, regex_pattern):
	pattern = re.compile(regex_pattern)
	
	for line in open(fname, "r"):	
		if pattern.search(line):
			return line

def addUserToGroup(group, line):
	pattern = re.compile( "[:,]" + os.getlogin() + "(,|$)")
	if pattern.search(line):
		return
		
	print ( "sudo usermod -a -G " + group + " " + os.getlogin() )

rfiles = glob.glob('/usr/lib/udev/rules.d/*.rules')
for fn in rfiles:

	res = grep(fn, "TAG\+=\"uaccess\"" )
	if res: 
		print( prefix + ", TAG+=\"uaccess\"" + postfix )
		exit()

res = grep("/etc/group", "^plugdev:" )
if res != None:
	print( prefix + ", GROUP=\"plugdev\"" + postfix )
	addUserToGroup("plugdev", res)
	exit()
	
res = grep("/etc/group", "^lp:" )
if res != None:
	print( prefix + ", GROUP=\"lp\"" + postfix )
	addUserToGroup("lp", res)
		
	exit()

Disclaimer, I'm a python noob.

Just wanted to add this doesn't necessarily have to be an installation feature. This procedure could be carried out by launching dymoprint with a special option.
The point of this exercise is to make it easy enough for a linux noob.