#!/usr/bin/python import re import subprocess import os DEVICES = [ ('0x1050', '0x0111', 'Yubico Yubikey NEO OTP+CCID'), ('0x1050', '0x0112', 'Yubico Yubikey NEO CCID'), ('0x1050', '0x0115', 'Yubico Yubikey NEO U2F+CCID'), ('0x1050', '0x0116', 'Yubico Yubikey NEO OTP+U2F+CCID'), ('0x1050', '0x0404', 'Yubico Yubikey 4 CCID'), ('0x1050', '0x0405', 'Yubico Yubikey 4 OTP+CCID'), ('0x1050', '0x0406', 'Yubico Yubikey 4 U2F+CCID'), ('0x1050', '0x0407', 'Yubico Yubikey 4 OTP+U2F+CCID') ] FNAME = "/etc/libccid_Info.plist" UDEV = """ ACTION!="add|change", GOTO="u2f_end" KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0113|0114|0115|0116|0120|0402|0403|0406|0407|0410", TAG+="uaccess" LABEL="u2f_end" """ UDEV_FNAME = "/etc/udev/rules.d/70-u2f.rules" def add_device(dev, content): # Parsing XML with regexes, what a wonderful idea! names = re.search('ifdFriendlyName\s*(.*?)', content, re.DOTALL) if names.group(1).find('%s' % dev[2]) > 0: # Already added return content print "Adding: %s" % dev[2] pos = names.start(1) content = content[:pos] + '\n\t\t%s' % dev[2] + content[pos:] vids = re.search('ifdVendorID\s*(.*?)', content, re.DOTALL) pos = vids.start(1) content = content[:pos] + '\n\t\t%s' % dev[0] + content[pos:] pids = re.search('ifdProductID\s*(.*?)', content, re.DOTALL) pos = pids.start(1) content = content[:pos] + '\n\t\t%s' % dev[1] + content[pos:] return content def main(): # Patch libccid file: if os.path.isfile(FNAME): print "Updating %s..." % FNAME with open(FNAME, 'r') as f: content = f.read() for dev in DEVICES: content = add_device(dev, content) with open(FNAME, 'w') as f: f.write(content) print "Restarting PCSCD..." subprocess.call(['service', 'pcscd', 'restart']) else: print "libccid_Info.plist not found, skipping..." # Add Udev rule: if os.path.isfile(UDEV_FNAME): print "Udev rule: %s already exists, skipping..." % UDEV_FNAME else: print "Adding Udev rule for U2F..." with open(UDEV_FNAME, 'w') as f: f.write(UDEV) print "Done!" if __name__ == '__main__': main()