4.3. Setting up permissions for USB ports

As USB is designed for hotplugging of devices, the operating system also needs a mechanism that dynamically creates devices (device files) for the devices currently connected and switched on.

The operating system has to determine which users may access a device dynamically. As the operating system cannot determine this by itself, there have to be some helper applications.

If you are using pre-built packages for your distribution (such as SuSE or Redhat RPMs or Debian DEBs, Gentoo Ebuilds, FreeBSD pots, ...), simply installing those packages should do this configuration for you. In reality, however, you often still have to do a varying amount of work. Read the documentation for your package (usually somewhere in /usr/share/doc/*gphoto2*/) and this guide section to find out if and what work there still is or may be to do for you.

If you are installing and setting up libgphoto2 yourself, then the following sections explain the configuration of these helpers.

4.3.1. USB ports on Linux

Important

This section is currently (2006-12) under review. However, with the old text being so outdated, we have decided to publish this work in progress as-is. Slightly disorganized but accurate information is more useful than horribly outdated one.

The Linux Kernel contains both generic USB interface drivers and higher level USB device drivers for some devices like USB mice or USB thumb drivers. The generic interface drivers can be used from user space applications to connect to USB devices not specifically supported by the kernel itself. Any application using libgphoto2 is an example of such a user space application.

Unfortunately, for some devices there are drivers both in the kernel and in libgphoto2, creating a conflict situation. If that happens with your device and you want to use libgphoto2 instead of the kernel driver, you may have a problem. In later kernels and current libusb versions , libgphoto2 will try to unload the kernel driver for the interface as soon as libgphoto2 wants to claim the device. On older kernels, you need to prevent the kernel from loading its kernel space driver in some fashion.

Hotplugging of devices is a central feature of USB, and thus the Linux Kernel's USB system must also handle the addition of new devices at run-time. Over the course of time, multiple solutions for this have been invented: linux-hotplug (kernels 2.4), udev (kernel 2.6), and nowadays HAL (which provides complete desktop integration). The basic mechanism is the same: When the Kernel notices that a new USB device has been plugged in (or switched on), it runs a program. That program can then walk through its configured set of rules and apply them to the new device.

4.3.2. USB ports on Linux using HAL

This section describes how to set up USB device permissions using HAL. Due to this article's author's cluelessness about HAL, it just describes the HAL setup provided by the Fedora Core 6 (FC6) gphoto2 RPM package.

The libgphoto2 specific part of the HAL configuration consists of two parts: The device list and a policy. Each is stored in its own file.

The device list file contains a list of all devices supported by libgphoto2 in any fashion and giving HAL information as to the device's capabilities. You can generate this file using the print-camera-list utility shipped with libgphoto2:

host:~# /usr/lib/libgphoto2/print-camera-list hal-fdi > libgphoto2.fdi

The FC6 gphoto2 package stores this file as /usr/share/hal/fdi/information/20thirdparty/10-camera-libgphoto2.fdi. Its content looks like:

<?xml version="1.0" encoding="ISO-8859-1"?> <!-- -*- SGML -*- -->
<!-- This file was generated by libgphoto2 print-camera-list - - fdi -->
<deviceinfo version="0.2">
 <device>
  <match key="info.bus" string="usb">
   <match key="usb.vendor_id" int="1363">
    <match key="usb.product_id" int="514">
     <merge key="info.category" type="string">camera</merge>
     <append key="info.capabilities" type="strlist">camera</append>
     <merge key="camera.access_method" type="string">proprietary</merge>
     <merge key="camera.libgphoto2.name" type="string">AEG Snap 300</merge>
     <merge key="camera.libgphoto2.support" type="bool">true</merge>
    </match>
   </match>
     ...
   <match key="usb.vendor_id" int="10096">
    <match key="usb.product_id" int="36956">
     <merge key="info.category" type="string">camera</merge>
     <append key="info.capabilities" type="strlist">camera</append>
     <merge key="camera.access_method" type="string">proprietary</merge>
     <merge key="camera.libgphoto2.name" type="string">Vivitar Vivicam35</merge>
     <merge key="camera.libgphoto2.support" type="bool">true</merge>
    </match>
   </match>
  </match>
 </device>
</deviceinfo>

Note that FC6's hal RPM already ships the following /usr/share/hal/fdi/information/10freedesktop/10-camera-ptp.fdi file which matches all PTP class cameras, so their being missing in the device list file generated by print-camera-list does not matter:

<?xml version="1.0" encoding="UTF-8"?>
<deviceinfo version="0.2">
  <device>
    <match key="info.bus" string="usb">
      <match key="usb.interface.class" int="0x06">
        <match key="usb.interface.subclass" int="0x01">
          <match key="usb.interface.protocol" int="0x01">
            <merge key="info.category" type="string">camera</merge>
	    <append key="info.capabilities" type="strlist">camera</append>
            <merge key="camera.access_method" type="string">ptp</merge>
          </match>
        </match>
      </match>
    </match>
  </device>
</deviceinfo>

The policy file defines what HAL is to do with devices which have a "camera" capability. The FC6 gphoto2 package stores the policy file as /usr/share/hal/fdi/policy/20thirdparty/90-gphoto-camera-policy.fdi. It just calls a script, as the content shows:

<?xml version="1.0" encoding="UTF-8"?> <!-- -*- SGML -*- --> 
<deviceinfo version="0.2">
  <device>
    <match key="info.capabilities" contains="camera">
      <match key="camera.access_method" string="proprietary">
        <append key="info.callouts.add" type="strlist">/usr/libexec/gphoto-set-procperm</append>
      </match>
      <match key="camera.access_method" string="ptp">
        <append key="info.callouts.add" type="strlist">/usr/libexec/gphoto-set-procperm</append>
      </match>
    </match>
  </device>
</deviceinfo>

The FC6 gphoto2 package stores the permission setup script as /usr/libexec/gphoto-set-procperm. It uses printf(1) to construct the name of the device file from USB bus and device numbers given by HAL, waits a few seconds to make sure the device file actually exists, and then finally hands ownership of the device file to the pam_console user:

#!/bin/bash

console_user=`cat /var/run/console/console.lock` 

if [ -z "$console_user" ] ; then
  exit 1 
fi

if [ -z "$HAL_PROP_USB_BUS_NUMBER" -o -z "$HAL_PROP_USB_LINUX_DEVICE_NUMBER" ] ; then
  exit 2 
fi

if [ $HAL_PROP_USB_BUS_NUMBER -lt 0 -o  $HAL_PROP_USB_LINUX_DEVICE_NUMBER -lt 0 ] ; then
  exit 3 
fi

bus_num=`printf %.3u $HAL_PROP_USB_BUS_NUMBER`
dev_num=`printf %.3u $HAL_PROP_USB_LINUX_DEVICE_NUMBER`

NUM_TRIES_LEFT=5
while [ $NUM_TRIES_LEFT -ge 0 ] && [ ! -c /dev/bus/usb/$bus_num/$dev_num ]; do
        sleep 1
        NUM_TRIES_LEFT=$(($NUM_TRIES_LEFT - 1))
done
[ -c /dev/bus/usb/$bus_num/$dev_num ] || exit 4

chown $console_user /dev/bus/usb/$bus_num/$dev_num 

NUM_TRIES_LEFT=5
while [ $NUM_TRIES_LEFT -ge 0 ] && [ ! -f /proc/bus/usb/$bus_num/$dev_num ]; do
        sleep 1
        NUM_TRIES_LEFT=$(($NUM_TRIES_LEFT - 1))
done
[ -f /proc/bus/usb/$bus_num/$dev_num ] || exit 5

chown $console_user /proc/bus/usb/$bus_num/$dev_num

4.3.3. USB ports on Linux using udev

udev is the mechanism called by Linux Kernel 2.6 to add and remove device files in /dev. udev is an integral part of the system, and thus installed directly in /, not in /usr/. This means that helper programs and scripts are installed in /lib/udev/, and the udev rules are stored in /etc/udev/rules.d/.

There are multiple versions of udev around with slightly different rule formats, so libgphoto2's /usr/lib/libgphoto2/print-camera supports a version argument.

# call script /lib/udev/foobar
host:~# /usr/lib/libgphoto2/print-camera-list \
    udev-rules version 0.98 script foobar \
    > /etc/udev/rules.d/90-libgphoto2.rules

# call script /path/to/foobar
host:~# /usr/lib/libgphoto2/print-camera-list \
    udev-rules version 0.98 script /path/to/foobar \
    > /etc/udev/rules.d/90-libgphoto2.rules

# set up permissions with "chmod 0660 $device; chgrp plugdev $device"
host:~# /usr/lib/libgphoto2/print-camera-list \
    udev-rules version 0.98 group plugdev mode 0660 \
    > /etc/udev/rules.d/90-libgphoto2.rules
	

These udev rule files contain two sorts of matches: Lots of listings by USB VendorID/ProductID, and one special case each for matching PTP and MTP devices. These two special cases run special scripts/programs, which should also be installed in /lib/udev/.

#!/bin/sh
# UNTESTED SCRIPT (but you get the idea)

test "x$ACTION" != "xadd" || exit 0
test "x$SUBSYSTEM" != "xusb_device" || exit 0

if test -e "$DEVNAME"
then
  user="photoripper"
  chown "$user" "$DEVNAME"
  chmod 0600 "$DEVNAME"

  # SUBSYSTEM == "usb_device" implies that DEVNAME == "/dev/bus/usb/123/456"
  # Determine device ID and bus ID.
  dev="$(basename "$DEVNAME")"
  bus="$(basename "$(dirname "$DEVNAME")")"

  # Download all files from that camera to incoming directory with
  # lowercase filenames
  command="/usr/bin/gphoto2 --port usb:${bus},${dev} --get-all-files"
  command="$command --filename /var/local/photodump/incoming/%:"
  echo "Executing command: $command"
  su "$photoripper" -c "$command"
else
  echo "photoripper: Given device named $DEVNAME not found."
  exit 1
fi

4.3.4. USB ports on Linux using linux-hotplug

Please note that this method is outdated, in Linux kernel 2.6, 3.x and newer versions, udev rules are used for rule setting.

linux-hotplug was the first solution for hooks to run when hotplugging devices, introduced with the 2.4 kernel's USB code.

linux-hotplug stores its files in pairs: One file /etc/hotplug/usb/usbcam.usermap is a list of device descriptions, and the other /etc/hotplug/usb/usbcam is a script to call in case a newly added device matches that description.

libgphoto2 supports linux-hotplug via a device list generated using print-camera-list and a few example scripts shipped in packaging/linux-hotplug/.

host:~# /usr/lib/libgphoto2/print-camera-list usb-usermap \
    > /etc/hotplug/usb/usbcam.usermap

4.3.5. USB ports on Linux (obsoleted by udev, dirty world-writable hack)

In ancient times, before the arrival of udev, one usually needed to mount the "usbdevfs" or later "usbfs" to /proc/bus/usb. One particular mount option allowed the whole usb filesystem (i.e. all mice, card readers, and all other USB devices) to be made group or world writeable.

Obviously, this kind of security is no security and should thus be avoided. Additionally, since udev exists now, just use udev. You can look up how to shoot yourself in the foot with usbdevfs... where? Well, just use udev. After all, this is almost the year 2007, not 1997.

4.3.6. USB ports on Linux (OLD)

libgphoto2 provides a user space driver for cameras, which conflicts with having a kernel driver for the camera. So in order to use libgphoto2, you have to disable all kernel drivers which want to handle the camera themselves (e.g. the Linux dc2xx or stv680 drivers). You can check whether these modules are loaded by executing lsmod.

We will not cover basic USB setup in detail here. For more information on how to get USB working on your hardware and your system at all, we'd like to refer you to http://www.linux-usb.org/USB-guide/ and especially http://www.linux-usb.org/USB-guide/c122.html . These pages explains the USB basics in a better way than we could do.

Now that you've got your basic USB system working, you have basically two options to allow user access to USB devices on your Linux system:

  1. allow a certain user and/or group or the whole world access to all USB devices by mounting /proc/bus/usb[1] with adequate user and/or group permissions (default is world-readable and root-only-writable, which is good)
  2. use hotplug (http://linux-hotplug.sourceforge.net/) and allow access only to the USB devices you want to be accessible (you need /proc/bus/usb mounted here as well, but not mounted writable by anybody else than root)

Solution b has a huge advantage over solution a: It doesn't allow the user/group to interfere with or eavesdrop on any other USB devices which might be attached, such as USB keyboards, fingerprint reader or similar. The following section thus describe setting up b.

4.3.7. Setting up linux-hotplug (OLD)

On Linux systems, from the 2.4 kernel series on, the kernel supports hotplugging. You may have to compile a kernel with hotplug support if you're not already running one. You may have to install the hotplug package (http://linux-hotplug.sourceforge.net/) if you don't have it installed already.

Note (TODO).  print-usb-usermap is deprecated as of 2.1.99.1. Use print-camera-list instead. Description of udev rules and HAL setup missing here.

To find out whether your kernel has hotplug support, look for the file /proc/sys/kernel/hotplug. If it exists, your kernel is hotplug enabled. If


alice@host:~$ cat /proc/sys/kernel/hotplug
          

prints the path to your hotplug binary (usually /sbin/hotplug) and this binary exists, you are ready to rock.

Also note that the following solution does not provide absolute security and that you should definitely know the security implications of the respective usbcam script you are going to use.

  1. You must have the files devices and drivers in your /proc/bus/usb directory. Please check this.

    If everything is OK, proceed with step 2. If not, check the following paragraph for hints.

    Load your USB driver (e.g. OHCI or UHCI) and mount the USB device filesystem[1], i.e. e.g.

    
    host:~# modprobe usb-uhci
    host:~# modprobe usb-ohci
    host:~# mount -t usbfs usb /proc/bus/usb
                  

    Modern distributions like Redhat 7.2 handle this automatically if you have your USB hardware enabled. Check your BIOS settings if lspci doesn't list any USB hardware.

  2. Make hotplug recognise all USB cameras which your version of libgphoto2(3) supports.

    Many of the modern[2] (as of mid-2003) distributions, you don't have to do much. Just write the output of /usr/lib/libgphoto2/print-usb-usermap[3] to the /etc/hotplug/usb/usbcam.usermap file:

    
    host:~# /usr/lib/libgphoto2/print-usb-usermap > /etc/hotplug/usb/usbcam.usermap
                  

    That's it. Proceed with step 3.

    However, if your distribution is an older one which still wants you to modify /etc/hotplug/usb.usermap, or if modifying /etc/hotplug/usb/usbcam.usermap hasn't been enough, read on.

    In the file /etc/hotplug/usb.usermap remove all lines beginning with usbcam. We are going to add new lines there and don't want to have the old ones get in the way.

    Add the output of /usr/lib/libgphoto2/print-usb-usermap[3] to the /etc/hotplug/usb.usermap file:

    
    host:~# /usr/lib/libgphoto2/print-usb-usermap >> /etc/hotplug/usb.usermap
                  

  3. Choose the right /etc/hotplug/usb/usbcam script for you.

    Example scripts are found in packaging/linux-hotplug/ in the source tree and in the doc dir (usually /usr/share/doc/gphoto2/ or something similar) under linux-hotplug/ after installation.

    Choose a script which fits your requirements best, adapt it for your needs, and copy it to the file /etc/hotplug/usb/usbcam. The script must be called /etc/hotplug/usb/usbcam, not /etc/hotplug/usb/usbcam.user or something similar.

    All the scripts shipped with gPhoto2 also have extensive commentary explaining their usage in more detail.

    usbcam.group
    If you want multiple users to have access to the camera, add all of these users to one group - either a special group camera or a generic group users will do - and use that group in usbcam.group. There is a specially marked line in the script you have to change accordingly.
    usbcam.console
    The most simple solution for single user workstations is using usbcam.console. This changes the permissions so that the user owning the console according to the pam_console module to access the camera. This works only if you're logging in with pam_console, i.e. e.g. using gdm on Redhat Linux, and then only for the user logged in last. It won't work on Debian GNU/Linux at all (they claim security reasons, but I didn't investigate further into that matter).
    usbcam.user
    If you want only one user to have access to the camera, use usbcam.user and change it accordingly. There is a specially marked line in the script you have to change.
    usbcam.x11-app
    If you want only one user to have access to the camera and your favourite X11 libgphoto2 frontend launched automatically, use usbcam.x11-app and change it accordingly. There are a few specially marked lines in the script you have to change.
  4. Make the script file executable:

    
    host:~# chmod +x /etc/hotplug/usb/usbcam
    	      

    Important

    Please do not forget that the script name is /etc/hotplug/usb/usbcam, not /etc/hotplug/usb/usbcam.whatever!

  5. Test your setup.

    Plug in the camera and switch it on. If you already did so, please unplug and/or switch off first. The kernel will now notice that your camera has been connected and, hopefully find no kernel driver for the device, and will then ask hotplug to do something about the new device file.

    Hotplug will then look into /etc/hotplug/usb/*.usermap and find that the usbcam script is to be called for the newly attached device. Thus /etc/hotplug/usb/usbcam is executed, hopefully setting the device permissions correctly.

    Your /var/log/messages syslog file will contain some messages to that effect.

    You will probably want to check whether the respective device file has its permissions set up correctly. Have a look at /proc/bus/usb with ls -lR /proc/bus/usb. There should be at least one device file (named something like 015) with the permissions set according to your wishes.

    Run the id command to find out whether your process belongs to the proper groups. If you have just added a user to a new group, only processes started after a new login will actually belong to the newly added group.

  6. Run gphoto2(1) or any other libgphoto2(3) frontend and enjoy:

    
    alice@host:~$ gphoto2 --list-ports
    alice@host:~$ gphoto2 --auto-detect
    alice@host:~$ gphoto2 --summary
    alice@host:~$ gphoto2 --storage-info
    alice@host:~$ gphoto2 --list-files
    alice@host:~$ gphoto2 --get-all-files
    	    

Note

The fact that we are using the name usbcam for setting up permissions for gphoto2 has a reason. In fact, the permission setup you're doing here has nothing to do with gphoto2 specifically - any user space software wanting to access your USB camera will be able to make use of your camera only if the permissions are correctly set up. So I (hun) chose the identifier and script name usbcam and not gphoto2cam something similar.

4.3.8. USB ports on FreeBSD

Note

This section only deals with FreeBSD 5 and over because older versions of FreeBSD do not have devfs, and thus do not handle dynamic devices at all (create static devices using MAKEDEV(8) there).

The editors would like to thank these FreeBSD users for their help (in no particular order): Tomasz Gucio, Georg Wagner, Michael Lyngbøl, Conan Webb, Bram Abbekerk, Roland Smith, and Guillermo A. Amaral (gamaral).

FreeBSD uses a dynamically created devices filesystem (devfs). In order to use the camera as non-root user, you need to tell the devfs framework what permissions it is to use when it dynamically creates these USB devices.

Follow the following steps as the root user to grant write access for the group usb to USB devices.

  1. Create a group (using pw(8) called something like usb. Add all users as group members which are supposed to have read/write access to attached USB devices. This includes not only cameras, but also possibly scanners and other devices.

  2. For FreeBSD 7 and under add these lines to /etc/devfs.rules:

    [usb_devices=10]
    add path 'ugen*' mode 0660 group usb
    add path 'da*s*' mode 0660 group usb
    	    

    The ugen* line will set the permissions for cameras using special camera protocols. The da*s* line will set up the same permissions for the slices of USB Mass Storage devices, such as a number of USB digicams.

    For FreeBSD 8 and over add these lines to /etc/devfs.rules:

    [usb_devices=10]
    add path 'usb/*' mode 0660 group usb
    add path 'da*s*' mode 0660 group usb
    	    

    The usb/* line will set the permissions for cameras using special camera protocols. The da*s* line will set up the same permissions for the slices of USB Mass Storage devices, such as a number of USB digicams.

  3. Add a line to /etc/rc.conf:

    # Set the default devfs ruleset.
    devfs_system_ruleset="usb_devices"
    	    
  4. Tomasz Gucio and Conan Webb report that user processes need write access to the usb* devices when they are supposed to write to ugen*. If you really need that, add lines like the following to /etc/devfs.conf. (FIXME: Can this be verified or invalidated?) This is *not* required for FreeBSD 8.

    perm    usb0    0660
    own     usb0    root:usb
    perm    usb1    0660
    own     usb1    root:usb
    	    
  5. Activate your changes by running the following command (no reboot required):

    
    host:~# /etc/rc.d/devfs start
    	    

Your system should be all set up now. Now you can test it as your normal non-root user:

  1. Make sure that you're actually member of the usb group. Check this by running the id and, if the group membership is not show, login anew.

  2. Now connect your camera, and you'll get a line like

    ugen1: Canon Inc. Canon Digital Camera, rev 1.10/0.01, addr 2
    	    

    and the permissions to the device files should look something like this on FreeBSD 7 and under:

    alice@host:~$ ls -l /dev/ugen*
    crw-rw----  1 root  usb       242,  16 Apr  8 15:55 /dev/ugen1
    crw-rw----  1 root  usb       242,  17 Apr  8 15:55 /dev/ugen1.1
    crw-rw----  1 root  usb       242,  18 Apr  8 15:55 /dev/ugen1.2
    crw-rw----  1 root  usb       242,  19 Apr  8 15:55 /dev/ugen1.3
    alice@host:~$ 
    	    

    on FreeBSD 8 and over they should look something like this:

    alice@host:~$ ls -l /dev/usb/
    crw-rw----  1 root  usb       242,  16 Apr  8 15:55 /dev/usb/0.1.0
    crw-rw----  1 root  usb       242,  17 Apr  8 15:55 /dev/usb/0.1.1
    crw-rw----  1 root  usb       242,  18 Apr  8 15:55 /dev/usb/1.1.0
    crw-rw----  1 root  usb       242,  19 Apr  8 15:55 /dev/usb/1.1.1
    alice@host:~$ 
    	    

FIXME for the FreeBSD instructions:

  1. How to write rules which only affect a certain set of devices, defined e.g. by USB Vendor/Product ID or USB device class?

4.3.9. USB ports on other systems (non-FreeBSD BSDs, MacOS X, OS/2)

FIXME: This chapter still is to be written. If you know about USB on these systems and/or are willing to contribute text or hints, please contact the developers at .



[1] The filesystem is called usbdevfs in 2.2 and older 2.4 kernels.

[2] FIXME: how can you determine whether a specific system is "modern" in this sense? If you know how, please tell us.

[3] In older versions of gphoto2 (gphoto2 2.0, gphoto2 2.1.0, and the unreleased developer versions in between and shortly after 2.1.0), the functionality of print-usb-usermap was contained in the command gphoto2 --print-usb-usermap.