@ -0,0 +1,340 @@ | |||
GNU GENERAL PUBLIC LICENSE | |||
Version 2, June 1991 | |||
Copyright (C) 1989, 1991 Free Software Foundation, Inc. | |||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
Everyone is permitted to copy and distribute verbatim copies | |||
of this license document, but changing it is not allowed. | |||
Preamble | |||
The licenses for most software are designed to take away your | |||
freedom to share and change it. By contrast, the GNU General Public | |||
License is intended to guarantee your freedom to share and change free | |||
software--to make sure the software is free for all its users. This | |||
General Public License applies to most of the Free Software | |||
Foundation's software and to any other program whose authors commit to | |||
using it. (Some other Free Software Foundation software is covered by | |||
the GNU Library General Public License instead.) You can apply it to | |||
your programs, too. | |||
When we speak of free software, we are referring to freedom, not | |||
price. Our General Public Licenses are designed to make sure that you | |||
have the freedom to distribute copies of free software (and charge for | |||
this service if you wish), that you receive source code or can get it | |||
if you want it, that you can change the software or use pieces of it | |||
in new free programs; and that you know you can do these things. | |||
To protect your rights, we need to make restrictions that forbid | |||
anyone to deny you these rights or to ask you to surrender the rights. | |||
These restrictions translate to certain responsibilities for you if you | |||
distribute copies of the software, or if you modify it. | |||
For example, if you distribute copies of such a program, whether | |||
gratis or for a fee, you must give the recipients all the rights that | |||
you have. You must make sure that they, too, receive or can get the | |||
source code. And you must show them these terms so they know their | |||
rights. | |||
We protect your rights with two steps: (1) copyright the software, and | |||
(2) offer you this license which gives you legal permission to copy, | |||
distribute and/or modify the software. | |||
Also, for each author's protection and ours, we want to make certain | |||
that everyone understands that there is no warranty for this free | |||
software. If the software is modified by someone else and passed on, we | |||
want its recipients to know that what they have is not the original, so | |||
that any problems introduced by others will not reflect on the original | |||
authors' reputations. | |||
Finally, any free program is threatened constantly by software | |||
patents. We wish to avoid the danger that redistributors of a free | |||
program will individually obtain patent licenses, in effect making the | |||
program proprietary. To prevent this, we have made it clear that any | |||
patent must be licensed for everyone's free use or not licensed at all. | |||
The precise terms and conditions for copying, distribution and | |||
modification follow. | |||
GNU GENERAL PUBLIC LICENSE | |||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |||
0. This License applies to any program or other work which contains | |||
a notice placed by the copyright holder saying it may be distributed | |||
under the terms of this General Public License. The "Program", below, | |||
refers to any such program or work, and a "work based on the Program" | |||
means either the Program or any derivative work under copyright law: | |||
that is to say, a work containing the Program or a portion of it, | |||
either verbatim or with modifications and/or translated into another | |||
language. (Hereinafter, translation is included without limitation in | |||
the term "modification".) Each licensee is addressed as "you". | |||
Activities other than copying, distribution and modification are not | |||
covered by this License; they are outside its scope. The act of | |||
running the Program is not restricted, and the output from the Program | |||
is covered only if its contents constitute a work based on the | |||
Program (independent of having been made by running the Program). | |||
Whether that is true depends on what the Program does. | |||
1. You may copy and distribute verbatim copies of the Program's | |||
source code as you receive it, in any medium, provided that you | |||
conspicuously and appropriately publish on each copy an appropriate | |||
copyright notice and disclaimer of warranty; keep intact all the | |||
notices that refer to this License and to the absence of any warranty; | |||
and give any other recipients of the Program a copy of this License | |||
along with the Program. | |||
You may charge a fee for the physical act of transferring a copy, and | |||
you may at your option offer warranty protection in exchange for a fee. | |||
2. You may modify your copy or copies of the Program or any portion | |||
of it, thus forming a work based on the Program, and copy and | |||
distribute such modifications or work under the terms of Section 1 | |||
above, provided that you also meet all of these conditions: | |||
a) You must cause the modified files to carry prominent notices | |||
stating that you changed the files and the date of any change. | |||
b) You must cause any work that you distribute or publish, that in | |||
whole or in part contains or is derived from the Program or any | |||
part thereof, to be licensed as a whole at no charge to all third | |||
parties under the terms of this License. | |||
c) If the modified program normally reads commands interactively | |||
when run, you must cause it, when started running for such | |||
interactive use in the most ordinary way, to print or display an | |||
announcement including an appropriate copyright notice and a | |||
notice that there is no warranty (or else, saying that you provide | |||
a warranty) and that users may redistribute the program under | |||
these conditions, and telling the user how to view a copy of this | |||
License. (Exception: if the Program itself is interactive but | |||
does not normally print such an announcement, your work based on | |||
the Program is not required to print an announcement.) | |||
These requirements apply to the modified work as a whole. If | |||
identifiable sections of that work are not derived from the Program, | |||
and can be reasonably considered independent and separate works in | |||
themselves, then this License, and its terms, do not apply to those | |||
sections when you distribute them as separate works. But when you | |||
distribute the same sections as part of a whole which is a work based | |||
on the Program, the distribution of the whole must be on the terms of | |||
this License, whose permissions for other licensees extend to the | |||
entire whole, and thus to each and every part regardless of who wrote it. | |||
Thus, it is not the intent of this section to claim rights or contest | |||
your rights to work written entirely by you; rather, the intent is to | |||
exercise the right to control the distribution of derivative or | |||
collective works based on the Program. | |||
In addition, mere aggregation of another work not based on the Program | |||
with the Program (or with a work based on the Program) on a volume of | |||
a storage or distribution medium does not bring the other work under | |||
the scope of this License. | |||
3. You may copy and distribute the Program (or a work based on it, | |||
under Section 2) in object code or executable form under the terms of | |||
Sections 1 and 2 above provided that you also do one of the following: | |||
a) Accompany it with the complete corresponding machine-readable | |||
source code, which must be distributed under the terms of Sections | |||
1 and 2 above on a medium customarily used for software interchange; or, | |||
b) Accompany it with a written offer, valid for at least three | |||
years, to give any third party, for a charge no more than your | |||
cost of physically performing source distribution, a complete | |||
machine-readable copy of the corresponding source code, to be | |||
distributed under the terms of Sections 1 and 2 above on a medium | |||
customarily used for software interchange; or, | |||
c) Accompany it with the information you received as to the offer | |||
to distribute corresponding source code. (This alternative is | |||
allowed only for noncommercial distribution and only if you | |||
received the program in object code or executable form with such | |||
an offer, in accord with Subsection b above.) | |||
The source code for a work means the preferred form of the work for | |||
making modifications to it. For an executable work, complete source | |||
code means all the source code for all modules it contains, plus any | |||
associated interface definition files, plus the scripts used to | |||
control compilation and installation of the executable. However, as a | |||
special exception, the source code distributed need not include | |||
anything that is normally distributed (in either source or binary | |||
form) with the major components (compiler, kernel, and so on) of the | |||
operating system on which the executable runs, unless that component | |||
itself accompanies the executable. | |||
If distribution of executable or object code is made by offering | |||
access to copy from a designated place, then offering equivalent | |||
access to copy the source code from the same place counts as | |||
distribution of the source code, even though third parties are not | |||
compelled to copy the source along with the object code. | |||
4. You may not copy, modify, sublicense, or distribute the Program | |||
except as expressly provided under this License. Any attempt | |||
otherwise to copy, modify, sublicense or distribute the Program is | |||
void, and will automatically terminate your rights under this License. | |||
However, parties who have received copies, or rights, from you under | |||
this License will not have their licenses terminated so long as such | |||
parties remain in full compliance. | |||
5. You are not required to accept this License, since you have not | |||
signed it. However, nothing else grants you permission to modify or | |||
distribute the Program or its derivative works. These actions are | |||
prohibited by law if you do not accept this License. Therefore, by | |||
modifying or distributing the Program (or any work based on the | |||
Program), you indicate your acceptance of this License to do so, and | |||
all its terms and conditions for copying, distributing or modifying | |||
the Program or works based on it. | |||
6. Each time you redistribute the Program (or any work based on the | |||
Program), the recipient automatically receives a license from the | |||
original licensor to copy, distribute or modify the Program subject to | |||
these terms and conditions. You may not impose any further | |||
restrictions on the recipients' exercise of the rights granted herein. | |||
You are not responsible for enforcing compliance by third parties to | |||
this License. | |||
7. If, as a consequence of a court judgment or allegation of patent | |||
infringement or for any other reason (not limited to patent issues), | |||
conditions are imposed on you (whether by court order, agreement or | |||
otherwise) that contradict the conditions of this License, they do not | |||
excuse you from the conditions of this License. If you cannot | |||
distribute so as to satisfy simultaneously your obligations under this | |||
License and any other pertinent obligations, then as a consequence you | |||
may not distribute the Program at all. For example, if a patent | |||
license would not permit royalty-free redistribution of the Program by | |||
all those who receive copies directly or indirectly through you, then | |||
the only way you could satisfy both it and this License would be to | |||
refrain entirely from distribution of the Program. | |||
If any portion of this section is held invalid or unenforceable under | |||
any particular circumstance, the balance of the section is intended to | |||
apply and the section as a whole is intended to apply in other | |||
circumstances. | |||
It is not the purpose of this section to induce you to infringe any | |||
patents or other property right claims or to contest validity of any | |||
such claims; this section has the sole purpose of protecting the | |||
integrity of the free software distribution system, which is | |||
implemented by public license practices. Many people have made | |||
generous contributions to the wide range of software distributed | |||
through that system in reliance on consistent application of that | |||
system; it is up to the author/donor to decide if he or she is willing | |||
to distribute software through any other system and a licensee cannot | |||
impose that choice. | |||
This section is intended to make thoroughly clear what is believed to | |||
be a consequence of the rest of this License. | |||
8. If the distribution and/or use of the Program is restricted in | |||
certain countries either by patents or by copyrighted interfaces, the | |||
original copyright holder who places the Program under this License | |||
may add an explicit geographical distribution limitation excluding | |||
those countries, so that distribution is permitted only in or among | |||
countries not thus excluded. In such case, this License incorporates | |||
the limitation as if written in the body of this License. | |||
9. The Free Software Foundation may publish revised and/or new versions | |||
of the General Public License from time to time. Such new versions will | |||
be similar in spirit to the present version, but may differ in detail to | |||
address new problems or concerns. | |||
Each version is given a distinguishing version number. If the Program | |||
specifies a version number of this License which applies to it and "any | |||
later version", you have the option of following the terms and conditions | |||
either of that version or of any later version published by the Free | |||
Software Foundation. If the Program does not specify a version number of | |||
this License, you may choose any version ever published by the Free Software | |||
Foundation. | |||
10. If you wish to incorporate parts of the Program into other free | |||
programs whose distribution conditions are different, write to the author | |||
to ask for permission. For software which is copyrighted by the Free | |||
Software Foundation, write to the Free Software Foundation; we sometimes | |||
make exceptions for this. Our decision will be guided by the two goals | |||
of preserving the free status of all derivatives of our free software and | |||
of promoting the sharing and reuse of software generally. | |||
NO WARRANTY | |||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | |||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN | |||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | |||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED | |||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS | |||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE | |||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, | |||
REPAIR OR CORRECTION. | |||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | |||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | |||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, | |||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING | |||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED | |||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY | |||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER | |||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE | |||
POSSIBILITY OF SUCH DAMAGES. | |||
END OF TERMS AND CONDITIONS | |||
How to Apply These Terms to Your New Programs | |||
If you develop a new program, and you want it to be of the greatest | |||
possible use to the public, the best way to achieve this is to make it | |||
free software which everyone can redistribute and change under these terms. | |||
To do so, attach the following notices to the program. It is safest | |||
to attach them to the start of each source file to most effectively | |||
convey the exclusion of warranty; and each file should have at least | |||
the "copyright" line and a pointer to where the full notice is found. | |||
<one line to give the program's name and a brief idea of what it does.> | |||
Copyright (C) <year> <name of author> | |||
This program is free software; you can redistribute it and/or modify | |||
it under the terms of the GNU General Public License as published by | |||
the Free Software Foundation; either version 2 of the License, or | |||
(at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU General Public License for more details. | |||
You should have received a copy of the GNU General Public License | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
Also add information on how to contact you by electronic and paper mail. | |||
If the program is interactive, make it output a short notice like this | |||
when it starts in an interactive mode: | |||
Gnomovision version 69, Copyright (C) year name of author | |||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | |||
This is free software, and you are welcome to redistribute it | |||
under certain conditions; type `show c' for details. | |||
The hypothetical commands `show w' and `show c' should show the appropriate | |||
parts of the General Public License. Of course, the commands you use may | |||
be called something other than `show w' and `show c'; they could even be | |||
mouse-clicks or menu items--whatever suits your program. | |||
You should also get your employer (if you work as a programmer) or your | |||
school, if any, to sign a "copyright disclaimer" for the program, if | |||
necessary. Here is a sample; alter the names: | |||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program | |||
`Gnomovision' (which makes passes at compilers) written by James Hacker. | |||
<signature of Ty Coon>, 1 April 1989 | |||
Ty Coon, President of Vice | |||
This General Public License does not permit incorporating your program into | |||
proprietary programs. If your program is a subroutine library, you may | |||
consider it more useful to permit linking proprietary applications with the | |||
library. If this is what you want to do, use the GNU Library General | |||
Public License instead of this License. |
@ -0,0 +1,181 @@ | |||
* 0.4.0 | |||
- Both pam_usb and its tools (adm, hotplug) have been redesigned from the | |||
ground up and rewritten from scratch. | |||
- Hardware recognition is now done through HAL which provides a stable | |||
interface over kernel changes. | |||
- Certificates have been replaced by one time pads. That will prevent | |||
copies of the USB device to be used for authentication. | |||
- Device's manufacturer properties verification. pam_usb now verifies | |||
device informations (vendor, product, serial number, UUID) in the | |||
authentication process. | |||
- Configuration is now handled in a central place, the pamusb.conf | |||
configuration file. This XML file contains configuration entries for | |||
users, devices and services. | |||
- pamusb-agent (formely usbhotplug) make use of DBUS signals (sent by HAL) | |||
instead of kernel hotplugging. Also, its configuration has been merged | |||
into the pamusb.conf configuration file. | |||
- A new tool named pamusb-check has been added. It can perform authentication | |||
the way the PAM module does. It can be useful for testing and scripting | |||
purposes. | |||
* 0.3.3 | |||
- The option keypath is now splitted into local_keypath and device_keypath. | |||
- Fixed a bug that occurred when the TTY entry was empty. | |||
- pam_usb doesn't get anymore the tty name from PAM_TTY as it used to be | |||
empty on some systems. | |||
- Better defaults. The default options have been set to fit most needs, | |||
you are no longer required to use !check_device on 2.6. | |||
- Verbose mode. By default, pam_usb now prints some informations during | |||
the login process (access granted, the reason why access was refused, etc). | |||
This can be turned off using the brand new 'quiet' option. | |||
- Other small fixes. | |||
* 0.3.2 | |||
- Now pam_usb will also try to autodetect /dev/sdN devices (not just | |||
/dev/sdNX). | |||
- Fixed a bug that happened when the application using PAM didn't set | |||
PAM_TTY correctly. | |||
- Added the use_first_pass and try_first_pass options. | |||
Now if you enter your password on another PAM module (such as pam_mount | |||
or pam_ssh), pam_usb will use that password to decrypt the private key. | |||
* 0.3.1 | |||
- Lot of misc fixes (memory management, Makefiles, sanity checks, etc). | |||
I'd like to thank the PaX Team <pageexec@freemail.hu> who did almost | |||
the whole job. | |||
- Added the hostname option which allows to select what hostname should | |||
be used for authentication (useful for shared public keys over lan). | |||
Thanks to Nicolas Chauvat <chauvat@nerim.net> who reported the issue, | |||
the idea and the patch for this feature. | |||
* 0.3.0 | |||
- Not much changes in this version beside a gcc fix, but the 0.2 branch | |||
reached too many new features so i wanted to name this release 0.3.0 | |||
as i should have done with 0.2.3 | |||
- Fixed a gcc 3.3 compile issue, and all related warning. | |||
I would like to thank the following guys for having reported this bug so fast: | |||
Lalande Fabrice <fabrice.lalande@orange.fr> | |||
Marco <gaedol@softhome.net> | |||
Neil Dunbar <neil.dunbar@hp.com> | |||
* 0.2.3 | |||
- Added the usbhotplug tool. | |||
usbhotplug is a hotplug agent that will automagically start a lock handler | |||
when the usb device is removed and an unlock handler when the usb device | |||
is plugged back in and authenticated through pam_usb. | |||
The default handlers will start xlock when the usb device is removed, | |||
and will kill it when the usb device is plugged back in and authenticated. | |||
I'd like to thank Wout Mertens <wmertens@cisco.com> as we had a couple | |||
of discussions about hotplug which helped me implementing this tool. | |||
- The parser can now understand "option" and "!option" instead of | |||
option=1 and option=-1 (e.g. debug !check_device). | |||
Thanks to Jean-Christophe JASKULA <jean.christophe.jasku-la@wanadoo.fr> who | |||
suggested me that and provided an initial patch. | |||
- Fixed a loop bug on serial number checking. Thanks to Zs <horzsol@freemail.hu> | |||
for reporting the bug and a patch to fix it. | |||
- Added the direct_open option which allows to open the private key | |||
using O_DIRECT to avoid disk caching (works only on devices that | |||
supports it). Thanks to myles <myles@tenhand.com> who suggested me that. | |||
- Added some sanity checks here and there because it seems that the PAM | |||
API can return weird stuff from time to time. | |||
- Handling the mount point creation/remotion in a better way which seems | |||
to fix a couple of mntpoint problems. | |||
* 0.2.2 | |||
- Added the keep_mounted option, which allows to not umount the mount point | |||
once logged (useful if the gpg/ssh key is stored on there) | |||
- Fixed the mntpoint option: do not delete the directory if it's not a | |||
temporary one. | |||
- Added the support to pass multiple filesystems name with the fs= | |||
option (comma separated list). Changed the default fs to "ext2,vfat" | |||
- Added the log_file option. Takes a filename as a argument. | |||
Combined with debug=1 it can log debug messages to a file. | |||
- Not mounting the device as read-only anymore. Instead, the mount_opts | |||
option has been created. It accepts a comma separated list of mount | |||
options (accepted options are: ro,bind,sync,remount,nosuid,noexec,nodev). | |||
- Fixed an issue which made the allow_remote feature not working correctly | |||
with gdm/kdm. | |||
- Introduced the local_hosts and local_consoles options. They contain a | |||
comma separated lists of hosts and consoles allowed to log in while using | |||
allow_remote=-1 | |||
* 0.2.1 | |||
- Changed the naming method from x.y to x.y.z | |||
- pam_usb is now able to distinguish local users from remote (as in | |||
logged via ssh), and denies the authentication of non-local users. | |||
Setting allow_remote to 1 disable this feature. | |||
- Mounting is now done in read-only. | |||
- Added the missing mandatory PAM functions. | |||
* 0.2_rc2 | |||
- Workaround to make pam_usb not use /proc so it can run on Linux 2.6 | |||
By setting check_device to -1, pam_usb will neither check the device's | |||
serial number, nor if it's attached. It's not a real problem if you | |||
don't need serial number checking, but don't combine it with | |||
check_if_mounted. | |||
- Added the force_device capability. Now you can specify a device that | |||
will be mounted without going in guessing mode. If the device cannot | |||
be mounted, it'll switch back to the default guess mode. | |||
Useful if guess mode fails, if you don't want it to try several | |||
devices before getting the right one (so you can login faster), or if | |||
you want to login using a floppy disk, a cdrom or whatever you want. | |||
- Modified the serial number authentication method so now if no serial | |||
numbers are avaible on a device, it will try to use the GUID. | |||
Thanks to Damien Braillard <damien.b@freesurf.ch> who reported the | |||
issue, suggested a way to fix it, and provided a first patch for it. | |||
* 0.2_rc1 | |||
- Radically changed the way pam_usb authenticates the user on the | |||
system. Now it works with a pair of DSA keys. | |||
Thanks to Wout Mertens <wmertens@cisco.com> who told me that i could | |||
use a couple of SSH keys to fix the authentication issue. | |||
That gave me the idea to use a set of private/public keys. | |||
Thanks to Ilkka Mattila <ilkka@lyseo.edu.ouka.fi> who helped me to | |||
find out a better way to implement the key challenge: extracting the | |||
public key was inadequate. | |||
Also thanks to those who brought up weird scenarios and/or tested | |||
pre-releases of pam_usb, in alphabetical order: | |||
Ilkka Mattila <ilkka@lyseo.edu.ouka.fi> | |||
Joonas Kortesalmi | |||
Thomas Stewart <thomas@stewarts.org.uk> | |||
Tuure Laurinolli <tuure@laurinolli.net> | |||
* 0.1: | |||
- Now pam_usb doesn't require a mount point. Instead, it creates | |||
a temporary directory under /tmp. | |||
Thanks to Loic Jaquemet <jaquemet@fiifo.u-psud.fr> who gave me the idea. | |||
- Compiles with gcc 2.95 thanks to Tobias Bayer <tobi.bayer@gmx.de> bug | |||
report. | |||
* 0.1-beta2: | |||
- procfile and device entries autodetection have been fixed thanks to | |||
Thomas Stewart <thomas@stewarts.org.uk> bug reports. | |||
- devfs support added. Thanks to Loic Jaquemet <jaquemet@fiifo.u-psud.fr> | |||
for the bug report. | |||
* 0.1-beta1: | |||
- Initial release |
@ -0,0 +1,87 @@ | |||
# Set to 'yes' to include debugging informations, e.g. DEBUG=yes make -e | |||
DEBUG := no | |||
# compiler/linker options | |||
CC := gcc | |||
CFLAGS := $(CFLAGS) -Wall -fPIC `pkg-config --cflags libxml-2.0` \ | |||
`pkg-config --cflags hal-storage` | |||
LIBS := `pkg-config --libs libxml-2.0` \ | |||
`pkg-config --libs hal-storage` | |||
# common source files | |||
SRCS := src/conf.c \ | |||
src/log.c \ | |||
src/xpath.c \ | |||
src/hal.c \ | |||
src/pad.c \ | |||
src/volume.c \ | |||
src/local.c \ | |||
src/device.c | |||
OBJS := $(SRCS:.c=.o) | |||
# pam_usb | |||
PAM_USB_SRCS := src/pam.c | |||
PAM_USB_OBJS := $(PAM_USB_SRCS:.c=.o) | |||
PAM_USB := pam_usb.so | |||
PAM_USB_LDFLAGS := -shared | |||
PAM_USB_DEST := $(DESTDIR)/lib/security | |||
# pamusb-check | |||
PAMUSB_CHECK_SRCS := src/pamusb-check.c | |||
PAMUSB_CHECK_OBJS := $(PAMUSB_CHECK_SRCS:.c=.o) | |||
PAMUSB_CHECK := pamusb-check | |||
# Tools | |||
PAMUSB_CONF := pamusb-conf | |||
PAMUSB_AGENT := pamusb-agent | |||
TOOLS_DEST := $(DESTDIR)/usr/bin | |||
TOOLS_SRC := tools | |||
# Conf | |||
CONFS := doc/pamusb.conf | |||
CONFS_DEST := $(DESTDIR)/etc | |||
# Doc | |||
DOCS := doc/QUICKSTART doc/CONFIGURATION doc/UPGRADING doc/FAQ | |||
DOCS_DEST := $(DESTDIR)/usr/share/doc/pamusb | |||
# Man | |||
MANS := doc/pamusb-conf.1.gz doc/pamusb-agent.1.gz doc/pamusb-check.1.gz | |||
MANS_DEST := $(DESTDIR)/usr/share/man/man1 | |||
# Binaries | |||
RM := rm | |||
INSTALL := install | |||
MKDIR := mkdir | |||
ifeq (yes, ${DEBUG}) | |||
CFLAGS := ${CFLAGS} -ggdb | |||
endif | |||
all : $(PAM_USB) $(PAMUSB_CHECK) | |||
$(PAM_USB) : $(OBJS) $(PAM_USB_OBJS) | |||
$(CC) -o $(PAM_USB) $(PAM_USB_LDFLAGS) $(LDFLAGS) $(OBJS) $(PAM_USB_OBJS) $(LIBS) | |||
$(PAMUSB_CHECK) : $(OBJS) $(PAMUSB_CHECK_OBJS) | |||
$(CC) -o $(PAMUSB_CHECK) $(LDFLAGS) $(OBJS) $(PAMUSB_CHECK_OBJS) $(LIBS) | |||
%.o : %.c | |||
${CC} -c ${CFLAGS} $< -o $@ | |||
clean : | |||
$(RM) -f $(PAM_USB) $(PAMUSB_CHECK) $(OBJS) $(PAMUSB_CHECK_OBJS) $(PAM_USB_OBJS) | |||
install : all | |||
$(MKDIR) -p $(CONFS_DEST) $(DOCS_DEST) $(MANS_DEST) $(TOOLS_DEST) $(PAM_USB_DEST) | |||
$(INSTALL) -m755 $(PAM_USB) $(PAM_USB_DEST) | |||
$(INSTALL) -m755 $(PAMUSB_CHECK) $(TOOLS_SRC)/$(PAMUSB_CONF) $(TOOLS_SRC)/$(PAMUSB_AGENT) $(TOOLS_DEST) | |||
$(INSTALL) -b -m644 $(CONFS) $(CONFS_DEST) | |||
$(INSTALL) -m644 $(DOCS) $(DOCS_DEST) | |||
$(INSTALL) -m644 $(MANS) $(MANS_DEST) | |||
deinstall : | |||
$(RM) -f $(PAM_USB_DEST)/$(PAM_USB) | |||
$(RM) -f $(TOOLS_DEST)/$(PAMUSB_CHECK) $(TOOLS_DEST)/$(PAMUSB_CONF) $(TOOLS_DEST)/$(PAMUSB_AGENT) | |||
$(RM) -rf $(DOCS_DEST) | |||
$(RM) -f $(MANS_DEST)/pusb_* |
@ -0,0 +1,256 @@ | |||
====== Configuration ====== | |||
===== Introduction ===== | |||
* The configuration file is formatted in XML and subdivided in 4 sections: | |||
- Default options, shared among every device, user and service | |||
- Devices declaration and settings | |||
- Users declaration and settings | |||
- Services declaration and settings | |||
* The syntax is the following: | |||
<configuration> | |||
<defaults> | |||
<!-- default options --> | |||
</defaults> | |||
<devices> | |||
<!-- devices definitions --> | |||
</devices> | |||
<users> | |||
<!-- users definitions --> | |||
</users> | |||
<services> | |||
<!-- services definitions --> | |||
</services> | |||
</configuration> | |||
* Location of the configuration file | |||
By default, pam_usb.so and its tools will look for the configuration file | |||
located in /etc/pamusb.conf, but you can tell it to use a different file by | |||
using the -c option: | |||
# /etc/pam.d/common-auth | |||
auth sufficient pam_usb.so -c /some/other/path.conf | |||
auth required pam_unix.so nullok_secure | |||
You will also have to use the -c option when calling pam_usb's tools. For | |||
instance, when calling pamusb-agent: | |||
pamusb-agent -c /some/other/path.conf | |||
===== Options ===== | |||
^ Name ^ Type ^ Default value ^ Description ^ | |||
| enable | Boolean | true | Enable pam_usb | |||
| | |||
| debug | Boolean | false | Enable debug messages | |||
| | |||
| quiet | Boolean | false | Quiet mode (no verbose | |||
output) | | |||
| color_log | Boolean | true | Enable colored output | |||
| | |||
| one_time_pad | Boolean | true | Enable the use of one | |||
time pads | | |||
| probe_timeout | Integer | 10 | Time (in seconds) to | |||
wait for the volume to be detected| | |||
| hostname | String | Computer's hostname | Computer name. Must be | |||
unique accross computers using the same device | | |||
| system_pad_directory | String | .pamusb | Relative path to the | |||
user's home used to store one time pads | | |||
| device_pad_directory | String | .pamusb | Relative path to the | |||
device used to store one time pads| | |||
* Example: | |||
<configuration> | |||
<defaults> | |||
<!-- Disable colored output by default --> | |||
<option name="color_log">false</option> | |||
<!-- Enable debug output --> | |||
<option name="debug">true</option> | |||
</defaults> | |||
<users> | |||
<user id="root"> | |||
<!-- Enable colored output for user "root" --> | |||
<option name="color_log">true</option> | |||
</user> | |||
<user id="scox"> | |||
<!-- Disable debug output for user "scox" --> | |||
<option name="debug">false</option> | |||
</users> | |||
<devices> | |||
<device id="sandisk"> | |||
<!-- Wait 15 seconds instead of the default 10 seconds for the "sandisk" | |||
device to be detected --> | |||
<option name="probe_timeout">15</option> | |||
</devices> | |||
<services> | |||
<service id="su"> | |||
<!-- Disable pam_usb for "su" ("su" will ask for a password as usual) --> | |||
<option name="enable">false<option> | |||
</service> | |||
</services> | |||
</configuration> | |||
===== Devices ===== | |||
^ Name ^ Type ^ Description ^ | |||
Example ^ | |||
| id | Attribute | Arbitrary device name | | |||
MyDevice | | |||
| vendor | Element | device's vendor name | | |||
SanDisk Corp. | | |||
| model | Element | device's model name | | |||
Cruzer Titanium | | |||
| serial | Element | serial number of the device | | |||
SNDKXXXXXXXXXXXXXXXX | | |||
| volume_uuid | Element | UUID of the device's volume used to store pads | | |||
6F6B-42FC | | |||
* Example: | |||
<device id="MyDevice"> | |||
<vendor>SanDisk Corp.</vendor> | |||
<model>Cruzer Titanium</model> | |||
<serial>SNDKXXXXXXXXXXXXXXXX</serial> | |||
<volume_uuid>6F6B-42FC</volume_uuid> | |||
</device> | |||
===== Users ===== | |||
^ Name ^ Type ^ Description ^ | |||
Example ^ | |||
| id | Attribute | Login of the user | root | |||
| | |||
| device | Element | id of the device associated to the user | | |||
MyDevice | | |||
| agent | Element | Agent commands, for use with pamusb-agent | See | |||
below | | |||
* Example: | |||
<user id="scox"> | |||
<device>MyDevice</device> | |||
<!-- When the user "scox" removes the usb device, lock the screen and pause | |||
beep-media-player --> | |||
<hotplug event="lock">gnome-screensaver-command --lock</hotplug> | |||
<hotplug event="lock">beep-media-player --pause</hotplug> | |||
<!-- Resume operations when the usb device is plugged back and authenticated --> | |||
<hotplug event="unlock">gnome-screensaver-command --deactivate</hotplug> | |||
<hotplug event="unlock">beep-media-player --play</hotplug> | |||
</user> | |||
===== Services ===== | |||
^ Name ^ Type ^ Description ^ Example ^ | |||
| id | Attribute | Name of the service | su | | |||
<service id="su"> | |||
<!-- | |||
Here you can put service specific options such as "enable", "debug" etc. | |||
See the options section of this document. | |||
--> | |||
</service> | |||
===== Full example ===== | |||
This example demonstrates how to write a pam_usb configuration file and how to | |||
combine and override options. | |||
<configuration> | |||
<!-- Default options --> | |||
<defaults> | |||
<!-- Enable debug output by default--> | |||
<option name="debug">true</option> --> | |||
<!-- Disable one time pads by default --> | |||
<option name="one_time_pad">false</option> --> | |||
</defaults> | |||
<!-- Device settings --> | |||
<devices> | |||
<device id="MyDevice"> | |||
<!-- This part was generated by pamusb-conf --> | |||
<vendor>SanDisk Corp.</vendor> | |||
<model>Cruzer Titanium</model> | |||
<serial>SNDKXXXXXXXXXXXXXXXX</serial> | |||
<volume_uuid>6F6B-42FC</volume_uuid> | |||
<!-- | |||
Override the debug option previously enabled by "defaults". | |||
Everytime a user associated to that device tries to authenticate, | |||
debugging will be disabled. | |||
For other users using different devices, the debugging will still be | |||
enabled. | |||
--> | |||
<option name="debug">disable</option> | |||
</device> | |||
</devices> | |||
<!-- User settings --> | |||
<users> | |||
<!-- Authenticate user "root" with device "MyDevice". --> | |||
<user id="root"> | |||
<device>MyDevice</device> | |||
<!-- | |||
One time pads were disabled in the "defaults" section. | |||
Now we want to enable them for the user "root" so we override the option: | |||
--> | |||
<option name="one_time_pad">true</option> | |||
</user> | |||
<!-- Authenticate user "scox" with device "MyDevice". --> | |||
<user id="scox"> | |||
<device>MyDevice</device> | |||
<!-- We want pam_usb to work in quiet mode when authenticating "scox", so we | |||
override the "quiet" option --> | |||
<option name="quiet">true</option> | |||
<!-- Agent settings, used by pamusb-agent --> | |||
<hotplug event="lock">gnome-screensaver-command --lock</hotplug> | |||
<hotplug event="unlock">gnome-screensaver-command --deactivate</hotplug> | |||
</user> | |||
</users> | |||
<!-- Services settings (e.g. gdm, su, sudo...) --> | |||
<services> | |||
<!-- Disable pam_usb for gdm (a password will be asked as usual) --> | |||
<service id="gdm"> | |||
<option name="enable">false</option> | |||
</service> | |||
<!-- | |||
We already disabled one time pads in the defaults section, but then | |||
re-enabled them for the | |||
user "root" in the users section. | |||
Now we want to speed up console login for user root, so we simply override | |||
again the one_time_pad option | |||
for the "login" (console) service. | |||
--> | |||
<service id="login"> | |||
<option name="one_time_pad">false</option> | |||
</service> | |||
</services> | |||
</configuration> | |||
</code> |
@ -0,0 +1,21 @@ | |||
====== Frequently Asked Questions ====== | |||
> Q: Can I use my USB drive as usual ? | |||
>> A: Yes. pam_usb only occupies a few kilobytes of the device's space. | |||
> Q: What if I lose or break my USB key ? Will I be able to log back in ? | |||
>> A: Sure. Your usual password will be asked. | |||
> Q: How is the USB key identified ? | |||
>> A: The USB device is both identified by its manufacturer attributes (vendor, | |||
product, serial number) and by a few random bytes called one time pads that | |||
pam_usb writes and updates on the USB device upon authentication. | |||
> Q: What if someone copies the content of my flash drive ? Will she/he be able | |||
to log into my account ? | |||
>> A: Even if that person manages to fake your device's attributes (vendor, | |||
product, serial number, UUID), the one time pad they copied will be outdated as | |||
soon as you authenticate. | |||
> Q: Is my USB drive compatible with pam_usb ? | |||
>> A: About every USB flash drive will work with pam_usb. |
@ -0,0 +1,227 @@ | |||
====== Quickstart ====== | |||
Before going ahead, make sure to follow the upgrading instructions if you're | |||
using an older version of pam_usb. | |||
===== Installing ==== | |||
==== Installing from sources ==== | |||
* Step 1: Download the latest release | |||
* Step 2: Unpack the distribution tarball | |||
$ tar -zxvf pam_usb-<version>.tar.gz | |||
$ cd pam_usb-<version> | |||
* Step 3: Make sure that you have installed the required dependencies | |||
pam_usb depends on libxml2, PAM and HAL. pam_usb's tools (pamusb-agent, | |||
pamusb-conf) depends on python, python-celementtree and python-gobject. | |||
* Step 3: Compile and install | |||
$ make | |||
# make install | |||
==== Installing from Subversion ==== | |||
If you want to use the development version, you can fetch the sources from | |||
subversion | |||
$ svn co https:pamusb.svn.sourceforge.net/svnroot/pamusb/trunk/pam_usb | |||
===== Setting up ===== | |||
==== Devices and Users ==== | |||
* Once you've connected your USB device to the computer, use pamusb-conf to add | |||
it to the configuration file: | |||
# pamusb-conf --add-device MyDevice | |||
Please select the device you wish to add. | |||
* Using "SanDisk Corp. Cruzer Titanium (SNDKXXXXXXXXXXXXXXXX)" (only option) | |||
Which volume would you like to use for storing data ? | |||
* Using "/dev/sda1 (UUID: <6F6B-42FC>)" (only option) | |||
Name : MyDevice | |||
Vendor : SanDisk Corp. | |||
Model : Cruzer Titanium | |||
Serial : SNDKXXXXXXXXXXXXXXXX | |||
Volume UUID : 6F6B-42FC (/dev/sda1) | |||
Save to /etc/pamusb.conf ? | |||
[Y/n] y | |||
Done. | |||
Note that MyDevice can be any arbitrary name you'd like. Also, you can add as | |||
many devices as you want. | |||
* Users | |||
Now that we have added the devices, we have to configure the users. | |||
# pamusb-conf --add-user root | |||
Which device would you like to use for authentication ? | |||
* Using "MyDevice" (only option) | |||
User : root | |||
Device : MyDevice | |||
Save to /etc/pamusb.conf ? | |||
[Y/n] y | |||
Done. | |||
Repeat this step for every other username you'd like to use pam_usb with (e.g. | |||
pamusb-conf --add-user MyUsername). | |||
* In order to check if everything went fine, we are going to use the | |||
pamusb-check tool which will simulate an authentication event. | |||
# pamusb-check root | |||
* Authentication request for user "root" (pamusb-check) | |||
* Device "MyDevice" is connected (good). | |||
* Performing one time pad verification... | |||
* Verification match, updating one time pads... | |||
* Access granted. | |||
==== PAM Module ==== | |||
The PAM module pam_usb.so is used to let applications authenticate you using | |||
your USB device instead of asking your password. The default password-based | |||
authentication will be used as fallback if the device authentication goes wrong. | |||
* Depending on the operating system you're using, you have to tell PAM to use | |||
pam_usb.so as default authentication method. There should be a file named | |||
either common-auth (Gentoo) under /etc/pam.d/. If you do NOT have neither of | |||
those files, you'll have to edit each pam.d service file you want to use (e.g. | |||
/etc/pam.d/su, /etc/pam.d/gdm and so on). | |||
* Locate the following line on /etc/pam.d/common-auth or /etc/pam.d/system-auth: | |||
auth required pam_unix.so nullok_secure | |||
* And change it to look something like that: | |||
auth sufficient pam_usb.so | |||
auth required pam_unix.so nullok_secure | |||
* You should now be able to authenticate the users configured in pamusb.conf | |||
using your USB device: | |||
scox $ su | |||
* pam_usb v.SVN | |||
* Authentication request for user "root" (su) | |||
* Device "MyDevice" is connected (good). | |||
* Performing one time pad verification... | |||
* Verification match, updating one time pads... | |||
* Access granted. | |||
* Try to authenticate to a different application. pam_usb.so should work with | |||
any application using xscreensaver and many more). | |||
==== Agent ==== | |||
The pam_usb agent (pamusb-agent) allows you to automatically execute commands | |||
upon locking and unlocking events. Those events are generated when you insert or | |||
remove your authentication device. | |||
To configure the commands, you have to edit pam_usb's configuration file | |||
(/etc/pamusb.conf) and add agent entries into your user section. | |||
For instance, you could automatically start your screensaver as soon as you | |||
remove the device, and deactivate it when you plug the device back. | |||
* GNOME (gnome-screensaver): | |||
<user id="scox"> | |||
<device>MyDevice</device> | |||
<agent event="lock">gnome-screensaver-command --lock</agent> | |||
<agent event="unlock">gnome-screensaver-command --deactivate</agent> | |||
</user> | |||
* KDE (kscreensaver): | |||
<user id="scox"> | |||
<device>MyDevice</device> | |||
<agent event="lock">dcop kdesktop KScreensaverIface lock</agent> | |||
<agent event="unlock">dcop kdesktop KScreensaverIface quit</agent> | |||
</user> | |||
You can execute more commands by adding extra <agent> entries. | |||
$ pamusb-agent | |||
pamusb-agent[18329]: pamusb-agent up and running. | |||
pamusb-agent[18329]: Watching device "MyDevice" for user "scox" | |||
pamusb-agent[18329]: Device "MyDevice" has been removed, locking down user | |||
"scox"... | |||
pamusb-agent[18329]: Running "gnome-screensaver-command --lock" | |||
pamusb-agent[18329]: Locked. | |||
pamusb-agent[18329]: Device "MyDevice" has been inserted. Performing | |||
verification... | |||
pamusb-agent[18329]: Executing "/usr/bin/pamusb-check --quiet | |||
--config=/etc/pamusb.conf --service=pamusb-agent scox" | |||
pamusb-agent[18329]: Authentication succeeded. Unlocking user "scox"... | |||
pamusb-agent[18329]: Running "gnome-screensaver-command --deactivate" | |||
pamusb-agent[18329]: Unlocked. | |||
Depending on your desktop environment, you have to add pamusb-agent to the list | |||
of autostarted applications so it will be started automatically. | |||
* GNOME: | |||
- Open System -> Preferences -> Sessions | |||
- Select Startup Programs and press Add | |||
- Enter pamusb-agent and press OK | |||
- Press Close | |||
* KDE: | |||
- cd ~/.kde/Autostart | |||
- ln -s /usr/bin/pamusb-agent pamusb-agent | |||
===== Troubleshooting ===== | |||
==== Log Analysis ==== | |||
Both pam_usb.so and pamusb-agent use the syslog facility to log authentication | |||
attempts. | |||
This can be useful for GUI-driven applications (for instance GDM) where you | |||
don't get to see console output. | |||
Messages are logged with the AUTH facility, they are usually written to | |||
/var/log/auth.log but may vary | |||
depending on the operating system you're using. | |||
# tail -f /var/log/auth.log | |||
pamusb-agent[25429]: Device "sandisk" has been inserted. Performing | |||
verification... | |||
pamusb-agent[25429]: Executing "/usr/bin/pamusb-check --quiet | |||
--config=/etc/pamusb.conf --service=pamusb-agent scox" | |||
pam_usb[25485]: Authentication request for user "scox" (pamusb-agent) | |||
pam_usb[25485]: Device "sandisk" is connected (good). | |||
pam_usb[25485]: Access granted. | |||
pamusb-agent[25429]: Authentication succeeded. Unlocking user "scox"... | |||
pamusb-agent[25429]: Unlocked. | |||
==== Enabling debug ==== | |||
Enabling debug messages may help you find out what's wrong. | |||
To enable them, edit /etc/pamusb.conf and set the following option: | |||
<defaults> | |||
<option name="debug">true</option> | |||
</defaults> | |||
If you wish, you could enable debug messages only for a specific user, device or | |||
service. | |||
For instance, if you want to enable debug messages only for the sudo service, | |||
you could do the following: | |||
<services> | |||
<service id="sudo"> | |||
<option name="debug">true</option> | |||
</service> | |||
</services> | |||
===== It works - What next ? ===== | |||
* Have a look at the configuration documentation |
@ -0,0 +1,58 @@ | |||
====== Upgrading ====== | |||
If you're already using a pam_usb version prior to 0.4.0, you will have to | |||
remove the older version before installing. | |||
You do not have to do this if you're already using >=0.4.0 or Subversion. | |||
===== Remove pam_usb.so from pam.d ===== | |||
$ grep -r pam_usb.so /etc/pam.d | |||
/etc/pam.d/su:auth sufficient pam_usb.so | |||
/etc/pam.d/gdm:auth sufficient pam_usb.so | |||
[...] | |||
Edit every matching file and remove the pam_usb.so lines. | |||
At the end of the operation, there shouldn't be any file contanining a reference | |||
to pam_usb.so: | |||
$ grep -r pam_usb /etc/pam.d | |||
$ | |||
===== Remove .auth directories ===== | |||
Older versions of pam_usb used to create .auth directories in both the device | |||
and the user's home directory. Those directories aren't used anymore, so feel | |||
free to remove them: | |||
# rm -rf /root/.auth | |||
# rm -rf /home/scox/.auth | |||
# rm -rf /media/usbdisk/.auth | |||
===== Remove configuration files ===== | |||
As configuration files of pam_usb 0.4.0 aren't backward compatible, the old | |||
/etc/pam_usb is no more needed. | |||
# rm -rf /etc/pam_usb | |||
===== Deinstall pam_usb ===== | |||
If you installed the old pam_usb version using your operating system's package | |||
manager, then remove it by the same mean. | |||
Otherwise, you can remove it by hand by performing the following instructions: | |||
# rm -f /usr/bin/usbadm /usr/share/man/usbadm.1.gz | |||
# rm -f /usr/bin/usbhotplug /etc/hotplug.d/default/pamusb.hotplug | |||
/etc/pam.d/usbhotplug | |||
# rm -f /lib/security/pam_usb.so | |||
===== Next ===== | |||
Go aheand and install the new version. |
@ -0,0 +1,49 @@ | |||
<!-- | |||
pamusb.conf: Configuration file for pam_usb. | |||
See http://www.pamusb.org/doc/configuring | |||
--> | |||
<configuration> | |||
<!-- Default options --> | |||
<defaults> | |||
<!-- Example: | |||
<option name="debug">true</option> | |||
--> | |||
</defaults> | |||
<!-- Device settings --> | |||
<devices> | |||
<!-- Example: | |||
Note: You should use pamusb-conf to add devices automatically. | |||
<device id="MyDevice"> | |||
<vendor>SanDisk Corp.</vendor> | |||
<model>Cruzer Titanium</model> | |||
<serial>SNDKXXXXXXXXXXXXXXXX</serial> | |||
<volume_uuid>6F6B-42FC</volume_uuid> | |||
<option name="probe_timeout">10</option> | |||
</device> | |||
--> | |||
</devices> | |||
<!-- User settings --> | |||
<users> | |||
<!-- Example: | |||
<user id="scox"> | |||
<device>MyDevice</device> | |||
<option name="quiet">true</option> | |||
<agent event="lock">gnome-screensaver-command -lock</agent> | |||
<agent event="unlock">gnome-screensaver-command -deactivate</agent> | |||
</user> | |||
--> | |||
</users> | |||
<!-- Services settings (e.g. gdm, su, sudo...) --> | |||
<services> | |||
<!-- Example: Speed up hotplugging by disabling one time pads --> | |||
<service id="pamusb-agent"> | |||
<option name="one_time_pad">false</option> | |||
</service> | |||
</services> | |||
</configuration> |
@ -0,0 +1,187 @@ | |||
/* | |||
* Copyright (c) 2003-2007 Andrea Luzzardi <scox@sig11.org> | |||
* | |||
* This file is part of the pam_usb project. pam_usb is free software; | |||
* you can redistribute it and/or modify it under the terms of the GNU General | |||
* Public License version 2, as published by the Free Software Foundation. | |||
* | |||
* pam_usb is distributed in the hope that it will be useful, but WITHOUT ANY | |||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |||
* details. | |||
* | |||
* You should have received a copy of the GNU General Public License along with | |||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||
* Place, Suite 330, Boston, MA 02111-1307 USA | |||
*/ | |||
#include <unistd.h> | |||
#include <string.h> | |||
#include <errno.h> | |||
#include "conf.h" | |||
#include "xpath.h" | |||
#include "log.h" | |||
static void pusb_conf_options_get_from(t_pusb_options *opts, | |||
const char *from, | |||
xmlDoc *doc) | |||
{ | |||
pusb_xpath_get_string_from(doc, from, "option[@name='hostname']", | |||
opts->hostname, sizeof(opts->hostname)); | |||
pusb_xpath_get_string_from(doc, from, "option[@name='system_pad_directory']", | |||
opts->system_pad_directory, | |||
sizeof(opts->system_pad_directory)); | |||
pusb_xpath_get_string_from(doc, from, "option[@name='device_pad_directory']", | |||
opts->device_pad_directory, | |||
sizeof(opts->device_pad_directory)); | |||
pusb_xpath_get_bool_from(doc, from, "option[@name='debug']", | |||
&(opts->debug)); | |||
pusb_xpath_get_bool_from(doc, from, "option[@name='quiet']", | |||
&(opts->quiet)); | |||
pusb_xpath_get_bool_from(doc, from, "option[@name='color_log']", | |||
&(opts->color_log)); | |||
pusb_xpath_get_bool_from(doc, from, "option[@name='enable']", | |||
&(opts->enable)); | |||
pusb_xpath_get_bool_from(doc, from, "option[@name='one_time_pad']", | |||
&(opts->one_time_pad)); | |||
pusb_xpath_get_int_from(doc, from, "option[@name='probe_timeout']", | |||
&(opts->probe_timeout)); | |||
} | |||
static int pusb_conf_parse_options(t_pusb_options *opts, | |||
xmlDoc *doc, | |||
const char *user, | |||
const char *service) | |||
{ | |||
char *xpath = NULL; | |||
size_t xpath_size; | |||
int i; | |||
struct s_opt_list opt_list[] = { | |||
{ CONF_DEVICE_XPATH, opts->device.name }, | |||
{ CONF_USER_XPATH, (char *)user }, | |||
{ CONF_SERVICE_XPATH, (char *)service }, | |||
{ NULL, NULL } | |||
}; | |||
pusb_conf_options_get_from(opts, "//configuration/defaults/", doc); | |||
for (i = 0; opt_list[i].name != NULL; ++i) | |||
{ | |||
xpath_size = strlen(opt_list[i].name) + strlen(opt_list[i].value) + 1; | |||
if (!(xpath = malloc(xpath_size))) | |||
{ | |||
log_error("malloc error\n"); | |||
return (0); | |||
} | |||
memset(xpath, 0x00, xpath_size); | |||
snprintf(xpath, xpath_size, opt_list[i].name, opt_list[i].value, ""); | |||
pusb_conf_options_get_from(opts, xpath, doc); | |||
free(xpath); | |||
} | |||
return (1); | |||
} | |||
static int pusb_conf_device_get_property(t_pusb_options *opts, | |||
xmlDoc *doc, | |||
const char *property, | |||
char *store, | |||
size_t size) | |||
{ | |||
char *xpath = NULL; | |||
size_t xpath_len; | |||
int retval; | |||
xpath_len = strlen(CONF_DEVICE_XPATH) + strlen(opts->device.name) + \ | |||
strlen(property) + 1; | |||
if (!(xpath = malloc(xpath_len))) | |||
{ | |||
log_error("malloc error!\n"); | |||
return (0); | |||
} | |||
memset(xpath, 0x00, xpath_len); | |||
snprintf(xpath, xpath_len, CONF_DEVICE_XPATH, opts->device.name, | |||
property); | |||
retval = pusb_xpath_get_string(doc, xpath, store, size); | |||
free(xpath); | |||
return (retval); | |||
} | |||
static int pusb_conf_parse_device(t_pusb_options *opts, xmlDoc *doc) | |||
{ | |||
if (!pusb_conf_device_get_property(opts, doc, "vendor", opts->device.vendor, | |||
sizeof(opts->device.vendor))) | |||
return (0); | |||
if (!pusb_conf_device_get_property(opts, doc, "model", opts->device.model, | |||
sizeof(opts->device.model))) | |||
return (0); | |||
if (!pusb_conf_device_get_property(opts, doc, "serial", opts->device.serial, | |||
sizeof(opts->device.serial))) | |||
return (0); | |||
pusb_conf_device_get_property(opts, doc, "volume_uuid", | |||
opts->device.volume_uuid, | |||
sizeof(opts->device.volume_uuid)); | |||
return (1); | |||
} | |||
int pusb_conf_init(t_pusb_options *opts) | |||
{ | |||
memset(opts, 0x00, sizeof(*opts)); | |||
if (gethostname(opts->hostname, sizeof(opts->hostname)) == -1) | |||
{ | |||
log_error("gethostname: %s\n", strerror(errno)); | |||
return (0); | |||
} | |||
strcpy(opts->system_pad_directory, ".pamusb"); | |||
strcpy(opts->device_pad_directory, ".pamusb"); | |||
opts->probe_timeout = 10; | |||
opts->enable = 1; | |||
opts->debug = 0; | |||
opts->quiet = 0; | |||
opts->color_log = 1; | |||
opts->one_time_pad = 1; | |||
return (1); | |||
} | |||
int pusb_conf_parse(const char *file, t_pusb_options *opts, | |||
const char *user, const char *service) | |||
{ | |||
xmlDoc *doc = NULL; | |||
int retval; | |||
char device_xpath[sizeof(CONF_USER_XPATH) + CONF_USER_MAXLEN + \ | |||
sizeof("device")]; | |||
log_debug("Parsing settings...\n", | |||
user, service); | |||
if (strlen(user) > CONF_USER_MAXLEN) | |||
{ | |||
log_error("Username \"%s\" is too long (max: %d).\n", user, | |||
CONF_USER_MAXLEN); | |||
return (0); | |||
} | |||
if (!(doc = xmlReadFile(file, NULL, 0))) | |||
{ | |||
log_error("Unable to parse \"%s\".\n", file); | |||
return (0); | |||
} | |||
snprintf(device_xpath, sizeof(device_xpath), CONF_USER_XPATH, user, | |||
"device"); | |||
retval = pusb_xpath_get_string(doc, | |||
device_xpath, | |||
opts->device.name, | |||
sizeof(opts->device.name)); | |||
if (!retval || !pusb_conf_parse_device(opts, doc)) | |||
{ | |||
log_error("No device configured for user \"%s\".\n", user); | |||
xmlFreeDoc(doc); | |||
xmlCleanupParser(); | |||
return (0); | |||
} | |||
if (!pusb_conf_parse_options(opts, doc, user, service)) | |||
{ | |||
xmlFreeDoc(doc); | |||
xmlCleanupParser(); | |||
return (0); | |||
} | |||
xmlFreeDoc(doc); | |||
xmlCleanupParser(); | |||
return (1); | |||
} |
@ -0,0 +1,63 @@ | |||
/* | |||
* Copyright (c) 2003-2007 Andrea Luzzardi <scox@sig11.org> | |||
* | |||
* This file is part of the pam_usb project. pam_usb is free software; | |||
* you can redistribute it and/or modify it under the terms of the GNU General | |||
* Public License version 2, as published by the Free Software Foundation. | |||
* | |||
* pam_usb is distributed in the hope that it will be useful, but WITHOUT ANY | |||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |||
* details. | |||
* | |||
* You should have received a copy of the GNU General Public License along with | |||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||
* Place, Suite 330, Boston, MA 02111-1307 USA | |||
*/ | |||
#ifndef PUSB_CONF_H_ | |||
# define PUSB_CONF_H_ | |||
# define PUSB_CONF_FILE "/etc/pamusb.conf" | |||
# define CONF_DEVICE_XPATH "//configuration/devices/device[@id='%s']/%s" | |||
# define CONF_USER_XPATH "//configuration/users/user[@id='%s']/%s" | |||
# define CONF_SERVICE_XPATH "//configuration/services/service[@id='%s']/%s" | |||
# define CONF_USER_MAXLEN 32 | |||
# include <limits.h> | |||
# include <linux/limits.h> | |||
# ifndef PATH_MAX | |||
# define PATH_MAX 4096 | |||
# endif | |||
typedef struct pusb_device | |||
{ | |||
char name[32]; | |||
char vendor[128]; | |||
char model[128]; | |||
char serial[128]; | |||
char volume_uuid[128]; | |||
} t_pusb_device; | |||
typedef struct pusb_options | |||
{ | |||
int probe_timeout; | |||
int enable; | |||
int debug; | |||
int quiet; | |||
int color_log; | |||
int one_time_pad; | |||
char hostname[32]; | |||
char system_pad_directory[PATH_MAX]; | |||
char device_pad_directory[PATH_MAX]; | |||
t_pusb_device device; | |||
} t_pusb_options; | |||
struct s_opt_list | |||
{ | |||
char *name; | |||
char *value; | |||
}; | |||
int pusb_conf_init(t_pusb_options *opts); | |||
int pusb_conf_parse(const char *file, t_pusb_options *opts, const char *user, const char *service); | |||
#endif /* !PUSB_CONF_H_ */ |
@ -0,0 +1,88 @@ | |||
/* | |||
* Copyright (c) 2003-2007 Andrea Luzzardi <scox@sig11.org> | |||
* | |||
* This file is part of the pam_usb project. pam_usb is free software; | |||
* you can redistribute it and/or modify it under the terms of the GNU General | |||
* Public License version 2, as published by the Free Software Foundation. | |||
* | |||
* pam_usb is distributed in the hope that it will be useful, but WITHOUT ANY | |||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |||
* details. | |||
* | |||
* You should have received a copy of the GNU General Public License along with | |||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||
* Place, Suite 330, Boston, MA 02111-1307 USA | |||
*/ | |||
#include <unistd.h> | |||
#include <string.h> | |||
#include <dbus/dbus.h> | |||
#include <libhal-storage.h> | |||
#include "conf.h" | |||
#include "hal.h" | |||
#include "log.h" | |||
#include "pad.h" | |||
#include "device.h" | |||
static int pusb_device_connected(t_pusb_options *opts, LibHalContext *ctx) | |||
{ | |||
char *udi = NULL; | |||
log_debug("Searching for \"%s\" in the hardware database...\n", | |||
opts->device.name); | |||
udi = pusb_hal_find_item(ctx, | |||
"usb_device.serial", opts->device.serial, | |||
"usb_device.vendor", opts->device.vendor, | |||
"info.product", opts->device.model, | |||
NULL); | |||
if (!udi) | |||
{ | |||
log_error("Device \"%s\" is not connected.\n", | |||
opts->device.name); | |||
return (0); | |||
} | |||
libhal_free_string(udi); | |||
log_info("Device \"%s\" is connected (good).\n", opts->device.name); | |||
return (1); | |||
} | |||
int pusb_device_check(t_pusb_options *opts, | |||
const char *user) | |||
{ | |||
DBusConnection *dbus = NULL; | |||
LibHalContext *ctx = NULL; | |||
int retval = 0; | |||
log_debug("Connecting to HAL...\n"); | |||
if (!(dbus = pusb_hal_dbus_connect())) | |||
return (0); | |||
if (!(ctx = pusb_hal_init(dbus))) | |||
{ | |||
pusb_hal_dbus_disconnect(dbus); | |||
return (0); | |||
} | |||
if (!pusb_device_connected(opts, ctx)) | |||
{ | |||
pusb_hal_dbus_disconnect(dbus); | |||
libhal_ctx_free(ctx); | |||
return (0); | |||
} | |||
if (opts->one_time_pad) | |||
{ | |||
log_info("Performing one time pad verification...\n"); | |||
retval = pusb_pad_check(opts, ctx, user); | |||
} | |||
else | |||
{ | |||
log_debug("One time pad is disabled, no more verifications to do.\n"); | |||
retval = 1; | |||
} | |||
pusb_hal_dbus_disconnect(dbus); | |||
libhal_ctx_free(ctx); | |||
return (retval); | |||
} |
@ -0,0 +1,23 @@ | |||
/* | |||
* Copyright (c) 2003-2007 Andrea Luzzardi <scox@sig11.org> | |||
* | |||
* This file is part of the pam_usb project. pam_usb is free software; | |||
* you can redistribute it and/or modify it under the terms of the GNU General | |||
* Public License version 2, as published by the Free Software Foundation. | |||
* | |||
* pam_usb is distributed in the hope that it will be useful, but WITHOUT ANY | |||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |||
* details. | |||
* | |||
* You should have received a copy of the GNU General Public License along with | |||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||
* Place, Suite 330, Boston, MA 02111-1307 USA | |||
*/ | |||
#ifndef PUSB_DEVICE_H_ | |||
# define PUSB_DEVICE_H_ | |||
int pusb_device_check(t_pusb_options *opts, const char *user); | |||
#endif /* !PUSB_DEVICE_H_ */ |
@ -0,0 +1,189 @@ | |||
/* | |||
* Copyright (c) 2003-2007 Andrea Luzzardi <scox@sig11.org> | |||
* | |||
* This file is part of the pam_usb project. pam_usb is free software; | |||
* you can redistribute it and/or modify it under the terms of the GNU General | |||
* Public License version 2, as published by the Free Software Foundation. | |||
* | |||
* pam_usb is distributed in the hope that it will be useful, but WITHOUT ANY | |||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |||
* details. | |||
* | |||
* You should have received a copy of the GNU General Public License along with | |||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||
* Place, Suite 330, Boston, MA 02111-1307 USA | |||
*/ | |||
#include <string.h> | |||
#include <stdarg.h> | |||
#include <dbus/dbus.h> | |||
#include <libhal-storage.h> | |||
#include "log.h" | |||
DBusConnection *pusb_hal_dbus_connect(void) | |||
{ | |||
DBusConnection *dbus = NULL; | |||
DBusError error; | |||
dbus_error_init(&error); | |||
if (!(dbus = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) | |||
{ | |||
log_error("Cannot connect to system bus: %s\n", | |||
error.message); | |||
dbus_error_free(&error); | |||
return (NULL); | |||
} | |||
return (dbus); | |||
} | |||
void pusb_hal_dbus_disconnect(DBusConnection *dbus) | |||
{ | |||
dbus_connection_unref(dbus); | |||
} | |||
LibHalContext *pusb_hal_init(DBusConnection *dbus) | |||
{ | |||
DBusError error; | |||
LibHalContext *ctx = NULL; | |||
dbus_error_init(&error); | |||
if (!(ctx = libhal_ctx_new())) | |||
{ | |||
log_error("Failed to create a HAL context\n"); | |||
return (NULL); | |||
} | |||
if (!libhal_ctx_set_dbus_connection(ctx, dbus)) | |||
{ | |||
log_error("Failed to attach dbus connection to hal\n"); | |||
libhal_ctx_free(ctx); | |||
return (NULL); | |||
} | |||
if (!libhal_ctx_init(ctx, &error)) | |||
{ | |||
log_error("libhal_ctx_init: %s\n", error.name, error.message); | |||
libhal_ctx_free(ctx); | |||
return (NULL); | |||
} | |||
return (ctx); | |||
} | |||
void pusb_hal_destroy(LibHalContext *ctx) | |||
{ | |||
libhal_ctx_free(ctx); | |||
} | |||
char *pusb_hal_get_property(LibHalContext *ctx, | |||
const char *udi, | |||
const char *name) | |||
{ | |||
DBusError error; | |||
char *data; | |||
dbus_error_init(&error); | |||
data = libhal_device_get_property_string(ctx, udi, | |||
name, &error); | |||
if (!data) | |||
{ | |||
log_debug("%s\n", error.message); | |||
dbus_error_free(&error); | |||
return (NULL); | |||
} | |||
return (data); | |||
} | |||
int pusb_hal_check_property(LibHalContext *ctx, | |||
const char *udi, | |||
const char *name, | |||
const char *value) | |||
{ | |||
char *data; | |||
int retval; | |||
data = pusb_hal_get_property(ctx, udi, name); | |||
if (!data) | |||
return (0); | |||
retval = (strcmp(data, value) == 0); | |||
libhal_free_string(data); | |||
return (retval); | |||
} | |||
char **pusb_hal_find_all_items(LibHalContext *ctx, | |||
const char *property, | |||
const char *value, | |||
int *count) | |||
{ | |||
DBusError error; | |||
char **devices; | |||
int n_devices; | |||
dbus_error_init(&error); | |||
*count = 0; | |||
devices = libhal_manager_find_device_string_match(ctx, | |||
property, | |||
value, | |||
&n_devices, | |||
&error); | |||
if (!devices) | |||
{ | |||
log_error("Unable to find item \"%s\": %s\n", property, | |||
error.message); | |||
dbus_error_free(&error); | |||
return (NULL); | |||
} | |||
if (!n_devices) | |||
{ | |||
libhal_free_string_array(devices); | |||
return (NULL); | |||
} | |||
*count = n_devices; | |||
return (devices); | |||
} | |||
char *pusb_hal_find_item(LibHalContext *ctx, | |||
const char *property, | |||
const char *value, | |||
...) | |||
{ | |||
char **devices; | |||
int n_devices; | |||
char *udi = NULL; | |||
va_list ap; | |||
int i; | |||
devices = pusb_hal_find_all_items(ctx, property, value, &n_devices); | |||
if (!devices) | |||
return (NULL); | |||
if (!n_devices) | |||
return (NULL); | |||
for (i = 0; i < n_devices; ++i) | |||
{ | |||
char *key = NULL; | |||
int match = 1; | |||
va_start(ap, value); | |||
while ((key = va_arg(ap, char *))) | |||
{ | |||
char *value = NULL; | |||
value = va_arg(ap, char *); | |||
if (!pusb_hal_check_property(ctx, devices[i], | |||
key, value)) | |||
{ | |||
match = 0; | |||
break; | |||
} | |||
match = 1; | |||
} | |||
if (match) | |||
{ | |||
udi = strdup(devices[i]); | |||
break; | |||
} | |||
va_end(ap); | |||
} | |||
libhal_free_string_array(devices); | |||
return (udi); | |||
} |
@ -0,0 +1,29 @@ | |||
/* | |||
* Copyright (c) 2003-2007 Andrea Luzzardi <scox@sig11.org> | |||
* | |||
* This file is part of the pam_usb project. pam_usb is free software; | |||
* you can redistribute it and/or modify it under the terms of the GNU General | |||
* Public License version 2, as published by the Free Software Foundation. | |||
* | |||
* pam_usb is distributed in the hope that it will be useful, but WITHOUT ANY | |||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |||
* details. | |||
* | |||
* You should have received a copy of the GNU General Public License along with | |||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||
* Place, Suite 330, Boston, MA 02111-1307 USA | |||
*/ | |||
#ifndef PUSB_HAL_H_ | |||
# define PUSB_HAL_H_ | |||
DBusConnection *pusb_hal_dbus_connect(void); | |||
void pusb_hal_dbus_disconnect(DBusConnection *dbus); | |||
LibHalContext *pusb_hal_init(DBusConnection *dbus); | |||
void pusb_hal_destroy(LibHalContext *ctx); | |||
char *pusb_hal_get_property(LibHalContext *ctx, const char *udi, const char *name); | |||
int pusb_hal_check_property(LibHalContext *ctx, const char *udi, const char *name, const char *value); | |||
char *pusb_hal_find_item(LibHalContext *ctx, const char *property, const char *value, ...); | |||
#endif /* !PUSB_HAL_H_ */ |
@ -0,0 +1,62 @@ | |||
/* | |||
* Copyright (c) 2003-2007 Andrea Luzzardi <scox@sig11.org> | |||
* | |||
* This file is part of the pam_usb project. pam_usb is free software; | |||
* you can redistribute it and/or modify it under the terms of the GNU General | |||
* Public License version 2, as published by the Free Software Foundation. | |||
* | |||
* pam_usb is distributed in the hope that it will be useful, but WITHOUT ANY | |||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |||
* details. | |||
* | |||
* You should have received a copy of the GNU General Public License along with | |||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||
* Place, Suite 330, Boston, MA 02111-1307 USA | |||
*/ | |||
#include <stdio.h> | |||
#include <string.h> | |||
#include <unistd.h> | |||
#include <utmp.h> | |||
#include "log.h" | |||
#include "conf.h" | |||
int pusb_local_login(t_pusb_options *opts, const char *user) | |||
{ | |||
struct utmp utsearch; | |||
struct utmp *utent; | |||
const char *from; | |||
int i; | |||
log_debug("Checking whether the caller is local or not...\n"); | |||
from = ttyname(STDIN_FILENO); | |||
if (!from || !(*from)) | |||
{ | |||
log_debug("Couldn't retrieve the tty name, aborting.\n"); | |||
return (1); | |||
} | |||
if (!strncmp(from, "/dev/", strlen("/dev/"))) | |||
from += strlen("/dev/"); | |||
log_debug("Authentication request from tty %s\n", from); | |||
strncpy(utsearch.ut_line, from, sizeof(utsearch.ut_line)); | |||
setutent(); | |||
utent = getutline(&utsearch); | |||
endutent(); | |||
if (!utent) | |||
{ | |||
log_debug("No utmp entry found for tty \"%s\"\n", | |||
from); | |||
return (1); | |||
} | |||
for (i = 0; i < 4; ++i) | |||
{ | |||
if (utent->ut_addr_v6[i] != 0) | |||
{ | |||
log_error("Remote authentication request: %s\n", utent->ut_host); | |||
return (0); | |||
} | |||
} | |||
log_debug("Caller is local (good)\n"); | |||
return (1); | |||
} |
@ -0,0 +1,23 @@ | |||
/* | |||
* Copyright (c) 2003-2007 Andrea Luzzardi <scox@sig11.org> | |||
* | |||
* This file is part of the pam_usb project. pam_usb is free software; | |||
* you can redistribute it and/or modify it under the terms of the GNU General | |||
* Public License version 2, as published by the Free Software Foundation. | |||
* | |||
* pam_usb is distributed in the hope that it will be useful, but WITHOUT ANY | |||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |||
* details. | |||
* | |||
* You should have received a copy of the GNU General Public License along with | |||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||
* Place, Suite 330, Boston, MA 02111-1307 USA | |||
*/ | |||
#ifndef PUSB_LOCAL_H_ | |||
# define PUSB_LOCAL_H_ | |||
int pusb_local_login(t_pusb_options *opts, const char *user); | |||
#endif /* !PUSB_LOCAL_H_ */ |
@ -0,0 +1,96 @@ | |||
/* | |||
* Copyright (c) 2003-2007 Andrea Luzzardi <scox@sig11.org> | |||
* | |||
* This file is part of the pam_usb project. pam_usb is free software; | |||
* you can redistribute it and/or modify it under the terms of the GNU General | |||
* Public License version 2, as published by the Free Software Foundation. | |||
* | |||
* pam_usb is distributed in the hope that it will be useful, but WITHOUT ANY | |||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |||
* details. | |||
* | |||
* You should have received a copy of the GNU General Public License along with | |||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||
* Place, Suite 330, Boston, MA 02111-1307 USA | |||
*/ | |||
#include <stdio.h> | |||
#include <syslog.h> | |||
#include <stdarg.h> | |||
#include "conf.h" | |||
#include "log.h" | |||
static t_pusb_options *pusb_opts = NULL; | |||
static void pusb_log_syslog(int level, const char *format, va_list ap) | |||
{ | |||
openlog("pam_usb", LOG_PID, LOG_AUTH); | |||
vsyslog(level, format, ap); | |||
closelog(); | |||
} | |||
static void pusb_log_output(int level, const char *format, va_list ap) | |||
{ | |||
if ((pusb_opts && !pusb_opts->quiet) || | |||
level == LOG_ERR) | |||
{ | |||
if (pusb_opts && pusb_opts->color_log) | |||
{ | |||
if (level == LOG_ERR) | |||
fprintf(stderr, "\033[01;31m*\033[00m "); | |||
else if (level == LOG_NOTICE) | |||
fprintf(stderr, "\033[01;32m*\033[00m "); | |||
} | |||
else | |||
fprintf(stderr, "* "); | |||
vfprintf(stderr, format, ap); | |||
} | |||
} | |||
void __log_debug(const char *file, int line, const char *fmt, ...) | |||
{ | |||
va_list ap; | |||
if (!pusb_opts || !pusb_opts->debug) | |||
return ; | |||
fprintf(stderr, "[%s:%03d] ", file, line); | |||
va_start(ap, fmt); | |||
vfprintf(stderr, fmt, ap); | |||
va_end(ap); | |||
va_start(ap, fmt); | |||
pusb_log_syslog(LOG_DEBUG, fmt, ap); | |||
va_end(ap); | |||
} | |||
void log_error(const char *fmt, ...) | |||
{ | |||
va_list ap; | |||
va_start(ap, fmt); | |||
pusb_log_syslog(LOG_ERR, fmt, ap); | |||
va_end(ap); | |||
va_start(ap, fmt); | |||
pusb_log_output(LOG_ERR, fmt, ap); | |||
va_end(ap); | |||
} | |||
void log_info(const char *fmt, ...) | |||
{ | |||
va_list ap; | |||
va_start(ap, fmt); | |||
pusb_log_syslog(LOG_NOTICE, fmt, ap); | |||
va_end(ap); | |||
va_start(ap, fmt); | |||
pusb_log_output(LOG_NOTICE, fmt, ap); | |||
va_end(ap); | |||
} | |||
void pusb_log_init(t_pusb_options *opts) | |||
{ | |||
pusb_opts = opts; | |||
} |
@ -0,0 +1,29 @@ | |||
/* | |||
* Copyright (c) 2003-2007 Andrea Luzzardi <scox@sig11.org> | |||
* | |||
* This file is part of the pam_usb project. pam_usb is free software; | |||
* you can redistribute it and/or modify it under the terms of the GNU General | |||
* Public License version 2, as published by the Free Software Foundation. | |||
* | |||
* pam_usb is distributed in the hope that it will be useful, but WITHOUT ANY | |||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |||
* details. | |||
* | |||
* You should have received a copy of the GNU General Public License along with | |||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||
* Place, Suite 330, Boston, MA 02111-1307 USA | |||
*/ | |||
#ifndef PUSB_LOG_H_ | |||
# define PUSB_LOG_H_ | |||
# define log_debug(s, ...) __log_debug(__FILE__, __LINE__, s, ##__VA_ARGS__) | |||
# include "conf.h" | |||
void __log_debug(const char *file, int line, const char *fmt, ...); | |||
void log_error(const char *fmt, ...); | |||
void log_info(const char *fmt, ...); | |||
void pusb_log_init(t_pusb_options *opts); | |||
#endif /* !PUSB_LOG_H_ */ |
@ -0,0 +1,222 @@ | |||
/* | |||
* Copyright (c) 2003-2007 Andrea Luzzardi <scox@sig11.org> | |||
* | |||
* This file is part of the pam_usb project. pam_usb is free software; | |||
* you can redistribute it and/or modify it under the terms of the GNU General | |||
* Public License version 2, as published by the Free Software Foundation. | |||
* | |||
* pam_usb is distributed in the hope that it will be useful, but WITHOUT ANY | |||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |||
* details. | |||
* | |||
* You should have received a copy of the GNU General Public License along with | |||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||
* Place, Suite 330, Boston, MA 02111-1307 USA | |||
*/ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <unistd.h> | |||
#include <errno.h> | |||
#include <sys/types.h> | |||
#include <sys/stat.h> | |||
#include <pwd.h> | |||
#include <time.h> | |||
#include <libhal-storage.h> | |||
#include "conf.h" | |||
#include "log.h" | |||
#include "volume.h" | |||
#include "pad.h" | |||
static FILE *pusb_pad_open_device(t_pusb_options *opts, | |||
LibHalVolume *volume, | |||
const char *user, | |||
const char *mode) | |||
{ | |||
FILE *f; | |||
char path[PATH_MAX]; | |||
const char *mnt_point; | |||
struct stat sb; | |||
mnt_point = (char *)libhal_volume_get_mount_point(volume); | |||
if (!mnt_point) | |||
return (NULL); | |||
memset(path, 0x00, PATH_MAX); | |||
snprintf(path, PATH_MAX, "%s/%s", mnt_point, opts->device_pad_directory); | |||
if (stat(path, &sb) != 0) | |||
{ | |||
log_debug("Directory %s does not exist, creating one.\n", path); | |||
if (mkdir(path, S_IRUSR | S_IWUSR | S_IXUSR) != 0) | |||
{ | |||
log_debug("Unable to create directory %s: %s\n", path, | |||
strerror(errno)); | |||
return (NULL); | |||
} | |||
memset(path, 0x00, PATH_MAX); | |||
} | |||
snprintf(path, PATH_MAX, "%s/%s/%s.%s.pad", mnt_point, | |||
opts->device_pad_directory, user, opts->hostname); | |||
f = fopen(path, mode); | |||
if (!f) | |||
{ | |||
log_debug("Cannot open device file: %s\n", strerror(errno)); | |||
return (NULL); | |||
} | |||
return (f); | |||
} | |||
static FILE *pusb_pad_open_system(t_pusb_options *opts, | |||
const char *user, | |||
const char *mode) | |||
{ | |||
FILE *f; | |||
char path[PATH_MAX]; | |||
struct passwd *user_ent = NULL; | |||
struct stat sb; | |||
if (!(user_ent = getpwnam(user)) || !(user_ent->pw_dir)) | |||
{ | |||
log_error("Unable to retrieve informations for user \"%s\": %s\n", | |||
strerror(errno)); | |||
return (0); | |||
} | |||
memset(path, 0x00, PATH_MAX); | |||
snprintf(path, PATH_MAX, "%s/%s", user_ent->pw_dir, | |||
opts->system_pad_directory); | |||
if (stat(path, &sb) != 0) | |||
{ | |||
log_debug("Directory %s does not exist, creating one.\n", path); | |||
if (mkdir(path, S_IRUSR | S_IWUSR | S_IXUSR) != 0) | |||
{ | |||
log_debug("Unable to create directory %s: %s\n", path, | |||
strerror(errno)); | |||
return (NULL); | |||
} | |||
chown(path, user_ent->pw_uid, user_ent->pw_gid); | |||
chmod(path, S_IRUSR | S_IWUSR | S_IXUSR); | |||
} | |||
memset(path, 0x00, PATH_MAX); | |||
snprintf(path, PATH_MAX, "%s/%s/%s.pad", user_ent->pw_dir, | |||
opts->system_pad_directory, opts->device.name); | |||
f = fopen(path, mode); | |||
if (!f) | |||
{ | |||
log_debug("Cannot open system file: %s\n", strerror(errno)); | |||
return (NULL); | |||
} | |||
return (f); | |||
} | |||
static int pusb_pad_protect(const char *user, int fd) | |||
{ | |||
struct passwd *user_ent = NULL; | |||
log_debug("Protecting pad file...\n"); | |||
if (!(user_ent = getpwnam(user))) | |||
{ | |||
log_error("Unable to retrieve informations for user \"%s\": %s\n", | |||
strerror(errno)); | |||
return (0); | |||
} | |||
if (fchown(fd, user_ent->pw_uid, user_ent->pw_gid) == -1) | |||
{ | |||
log_error("Unable to change owner of the pad: %s\n", | |||
strerror(errno)); | |||
return (0); | |||
} | |||
if (fchmod(fd, S_IRUSR | S_IWUSR) == -1) | |||
{ | |||
log_error("Unable to change mode of the pad: %s\n", | |||
strerror(errno)); | |||
return (0); | |||
} | |||
return (1); | |||
} | |||
static void pusb_pad_update(t_pusb_options *opts, | |||
LibHalVolume *volume, | |||
const char *user) | |||
{ | |||
FILE *f_device = NULL; | |||
FILE *f_system = NULL; | |||
char magic[1024]; | |||
int i; | |||
if (!(f_device = pusb_pad_open_device(opts, volume, user, "w+"))) | |||
{ | |||
log_error("Unable to update pads.\n"); | |||
return ; | |||
} | |||
pusb_pad_protect(user, fileno(f_device)); | |||
if (!(f_system = pusb_pad_open_system(opts, user, "w+"))) | |||
{ | |||
log_error("Unable to update pads.\n"); | |||
fclose(f_device); | |||
return ; | |||
} | |||
pusb_pad_protect(user, fileno(f_system)); | |||
log_debug("Generating %d bytes unique pad...\n", sizeof(magic)); | |||
srand(getpid() * time(NULL)); | |||
for (i = 0; i < sizeof(magic); ++i) | |||
magic[i] = (char)rand(); | |||
log_debug("Writing pad to the device...\n"); | |||
fwrite(magic, sizeof(char), sizeof(magic), f_system); | |||
log_debug("Writing pad to the system...\n"); | |||
fwrite(magic, sizeof(char), sizeof(magic), f_device); | |||
log_debug("Synchronizing filesystems...\n"); | |||
fclose(f_system); | |||
fclose(f_device); | |||
sync(); | |||
log_debug("One time pads updated.\n"); | |||
} | |||
static int pusb_pad_compare(t_pusb_options *opts, LibHalVolume *volume, | |||
const char *user) | |||
{ | |||
FILE *f_device = NULL; | |||
FILE *f_system = NULL; | |||
char magic_device[1024]; | |||
char magic_system[1024]; | |||
int retval; | |||
if (!(f_system = pusb_pad_open_system(opts, user, "r"))) | |||
return (1); | |||
if (!(f_device = pusb_pad_open_device(opts, volume, user, "r"))) | |||
{ | |||
fclose(f_system); | |||
return (0); | |||
} | |||
log_debug("Loading device pad...\n"); | |||
fread(magic_device, sizeof(char), sizeof(magic_device), f_device); | |||
log_debug("Loading system pad...\n"); | |||
fread(magic_system, sizeof(char), sizeof(magic_system), f_system); | |||
retval = memcmp(magic_system, magic_device, sizeof(magic_system)); | |||
fclose(f_system); | |||
fclose(f_device); | |||
if (!retval) | |||
log_debug("Pad match.\n"); | |||
return (retval == 0); | |||
} | |||
int pusb_pad_check(t_pusb_options *opts, LibHalContext *ctx, | |||
const char *user) | |||
{ | |||
LibHalVolume *volume = NULL; | |||
int retval; | |||
volume = pusb_volume_get(opts, ctx); | |||
if (!volume) | |||
return (0); | |||
retval = pusb_pad_compare(opts, volume, user); | |||
if (retval) | |||
{ | |||
log_info("Verification match, updating one time pads...\n"); | |||
pusb_pad_update(opts, volume, user); | |||
} | |||
else | |||
log_error("Pad checking failed !\n"); | |||
pusb_volume_destroy(volume); | |||
return (retval); | |||
} |
@ -0,0 +1,23 @@ | |||
/* | |||
* Copyright (c) 2003-2007 Andrea Luzzardi <scox@sig11.org> | |||
* | |||
* This file is part of the pam_usb project. pam_usb is free software; | |||
* you can redistribute it and/or modify it under the terms of the GNU General | |||
* Public License version 2, as published by the Free Software Foundation. | |||
* | |||
* pam_usb is distributed in the hope that it will be useful, but WITHOUT ANY | |||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |||
* details. | |||
* | |||
* You should have received a copy of the GNU General Public License along with | |||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||
* Place, Suite 330, Boston, MA 02111-1307 USA | |||
*/ | |||
#ifndef PUSB_OTP_H_ | |||
# define PUSB_OTP_H_ | |||
int pusb_pad_check(t_pusb_options *opts, LibHalContext *ctx, const char *user); | |||
#endif /* !PUSB_OTP_H_ */ |
@ -0,0 +1,111 @@ | |||
/* | |||
* Copyright (c) 2003-2007 Andrea Luzzardi <scox@sig11.org> | |||
* | |||
* This file is part of the pam_usb project. pam_usb is free software; | |||
* you can redistribute it and/or modify it under the terms of the GNU General | |||
* Public License version 2, as published by the Free Software Foundation. | |||
* | |||
* pam_usb is distributed in the hope that it will be useful, but WITHOUT ANY | |||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |||
* details. | |||
* | |||
* You should have received a copy of the GNU General Public License along with | |||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||
* Place, Suite 330, Boston, MA 02111-1307 USA | |||
*/ | |||
#define PAM_SM_AUTH | |||
#include <security/pam_modules.h> | |||
#include <security/_pam_macros.h> | |||
#include "version.h" | |||
#include "conf.h" | |||
#include "log.h" | |||
#include "local.h" | |||
#include "device.h" | |||
PAM_EXTERN | |||
int pam_sm_authenticate(pam_handle_t *pamh, int flags, | |||
int argc, const char **argv) | |||
{ | |||
t_pusb_options opts; | |||
const char *service; | |||
const char *user; | |||
const char *tty; | |||
char *conf_file = PUSB_CONF_FILE; | |||
int retval; | |||
retval = pam_get_item(pamh, PAM_SERVICE, (const void **)&service); | |||
if (retval != PAM_SUCCESS) | |||
{ | |||
log_error("Unable to retrieve the PAM service name.\n"); | |||
return (PAM_AUTH_ERR); | |||
} | |||
if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS || !user || !*user) | |||
{ | |||
log_error("Unable to retrieve the PAM user name.\n"); | |||
return (PAM_AUTH_ERR); | |||
} | |||
if (argc > 1) | |||
if (!strcmp(argv[0], "-c")) | |||
conf_file = (char *)argv[1]; | |||
pusb_conf_init(&opts); | |||
if (!pusb_conf_parse(conf_file, &opts, user, service)) | |||
return (PAM_AUTH_ERR); | |||
pusb_log_init(&opts); | |||
if (!opts.enable) | |||
{ | |||
log_debug("Not enabled, exiting...\n"); | |||
return (PAM_IGNORE); | |||
} | |||
log_info("pam_usb v%s\n", PUSB_VERSION); | |||
log_info("Authentication request for user \"%s\" (%s)\n", | |||
user, service); | |||
if (pam_get_item(pamh, PAM_TTY, (const void **)&tty) == PAM_SUCCESS) | |||
{ | |||
if (tty && !strcmp(tty, "ssh")) | |||
{ | |||
log_debug("SSH Authentication, aborting.\n"); | |||
return (0); | |||
} | |||
} | |||
if (!pusb_local_login(&opts, user)) | |||
{ | |||
log_error("Access denied.\n"); | |||
return (PAM_AUTH_ERR); | |||
} | |||
if (pusb_device_check(&opts, user)) | |||
{ | |||
log_info("Access granted.\n"); | |||
return (PAM_SUCCESS); | |||
} | |||
log_error("Access denied.\n"); | |||
return (PAM_AUTH_ERR); | |||
} | |||
PAM_EXTERN | |||
int pam_sm_setcred(pam_handle_t *pamh,int flags,int argc, | |||
const char **argv) | |||
{ | |||
return (PAM_SUCCESS); | |||
} | |||
#ifdef PAM_STATIC | |||
struct pam_module _pam_usb_modstruct = { | |||
"pam_usb", | |||
pam_sm_authenticate, | |||
pam_sm_setcred, | |||
NULL, | |||
NULL, | |||
NULL, | |||
NULL | |||
}; | |||
#endif |
@ -0,0 +1,140 @@ | |||
/* | |||
* Copyright (c) 2003-2007 Andrea Luzzardi <scox@sig11.org> | |||
* | |||
* This file is part of the pam_usb project. pam_usb is free software; | |||
* you can redistribute it and/or modify it under the terms of the GNU General | |||
* Public License version 2, as published by the Free Software Foundation. | |||
* | |||
* pam_usb is distributed in the hope that it will be useful, but WITHOUT ANY | |||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |||
* details. | |||
* | |||
* You should have received a copy of the GNU General Public License along with | |||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||
* Place, Suite 330, Boston, MA 02111-1307 USA | |||
*/ | |||
#include <stdio.h> | |||
#include <unistd.h> | |||
#include <string.h> | |||
#include <getopt.h> | |||
#include "conf.h" | |||
#include "log.h" | |||
#include "device.h" | |||
#include "local.h" | |||
static void pusb_check_conf_dump(t_pusb_options *opts, const char *username, | |||
const char *service) | |||
{ | |||
fprintf(stdout, "Configuration dump for user %s (service: %s):\n", | |||
username, service); | |||
fprintf(stdout, "enable\t\t\t: %s\n", opts->enable ? "true" : "false"); | |||
fprintf(stdout, "debug\t\t\t: %s\n", opts->debug ? "true" : "false"); | |||
fprintf(stdout, "quiet\t\t\t: %s\n", opts->quiet ? "true" : "false"); | |||
fprintf(stdout, "color_log\t\t: %s\n", opts->color_log ? "true" : "false"); | |||
fprintf(stdout, "one_time_pad\t\t: %s\n", | |||
opts->one_time_pad ? "true" : "false"); | |||
fprintf(stdout, "probe_timeout\t\t: %d\n", opts->probe_timeout); | |||
fprintf(stdout, "hostname\t\t: %s\n", opts->hostname); | |||
fprintf(stdout, "system_pad_directory\t: %s\n", | |||
opts->system_pad_directory); | |||
fprintf(stdout, "device_pad_directory\t: %s\n", | |||
opts->device_pad_directory); | |||
} | |||
static int pusb_check_perform_authentication(t_pusb_options *opts, | |||
const char *user, | |||
const char *service) | |||
{ | |||
int retval; | |||
if (!opts->enable) | |||
{ | |||
log_debug("Not enabled, exiting...\n"); | |||
return (0); | |||
} | |||
log_info("Authentication request for user \"%s\" (%s)\n", | |||
user, service); | |||
if (!pusb_local_login(opts, user)) | |||
{ | |||
log_error("Access denied.\n"); | |||
return (0); | |||
} | |||
retval = pusb_device_check(opts, user); | |||
if (retval) | |||
log_info("Access granted.\n"); | |||
else | |||
log_error("Access denied.\n"); | |||
return (retval); | |||
} | |||
static void pusb_check_usage(const char *name) | |||
{ | |||
fprintf(stderr, "Usage: %s [--help] [--config=path] [--service=name] [--dump] [--quiet]" \ | |||
" <username>\n", name); | |||
} | |||
int main(int argc, char **argv) | |||
{ | |||
t_pusb_options opts; | |||
char *conf_file = PUSB_CONF_FILE; | |||
char *service = "pamusb-check"; | |||
char *user = NULL; | |||
int quiet = 0; | |||
int dump = 0; | |||
int opt; | |||
int opt_index = 0; | |||
extern char *optarg; | |||
char *short_options = "hc:s:dq"; | |||
struct option long_options[] = { | |||
{ "help", 0, 0, 0}, | |||
{ "config", 1, 0, 0}, | |||
{ "service", 1, 0, 0}, | |||
{ "dump", 0, &dump, 1 }, | |||
{ "quiet", 0, &quiet, 1}, | |||
{ 0, 0, 0, 0} | |||
}; | |||
while ((opt = getopt_long(argc, argv, short_options, long_options, | |||
&opt_index)) != EOF) | |||
{ | |||
if (opt == 'h' || (!opt && !strcmp(long_options[opt_index].name, "help"))) | |||
{ | |||
pusb_check_usage(argv[0]); | |||
return (1); | |||
} | |||
else if (opt == 'c' || (!opt && !strcmp(long_options[opt_index].name, "config"))) | |||
conf_file = optarg; | |||
else if (opt == 's' || (!opt && !strcmp(long_options[opt_index].name, "service"))) | |||
service = optarg; | |||
else if (opt == '?') | |||
{ | |||
pusb_check_usage(argv[0]); | |||
return (1); | |||
} | |||
} | |||
if ((argc - 1) == optind) | |||
user = argv[optind]; | |||
else | |||
{ | |||
pusb_check_usage(argv[0]); | |||
return (1); | |||
} | |||
pusb_conf_init(&opts); | |||
if (!pusb_conf_parse(conf_file, &opts, user, service)) | |||
return (1); | |||
if (quiet) | |||
{ | |||
opts.quiet = 1; | |||
opts.debug = 0; | |||
} | |||
pusb_log_init(&opts); | |||
if (dump) | |||
{ | |||
pusb_check_conf_dump(&opts, user, service); | |||
return (1); | |||
} | |||
return (!pusb_check_perform_authentication(&opts, user, service)); | |||
} |
@ -0,0 +1,23 @@ | |||
/* | |||
* Copyright (c) 2003-2007 Andrea Luzzardi <scox@sig11.org> | |||
* | |||
* This file is part of the pam_usb project. pam_usb is free software; | |||
* you can redistribute it and/or modify it under the terms of the GNU General | |||
* Public License version 2, as published by the Free Software Foundation. | |||
* | |||
* pam_usb is distributed in the hope that it will be useful, but WITHOUT ANY | |||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |||
* details. | |||
* | |||
* You should have received a copy of the GNU General Public License along with | |||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||
* Place, Suite 330, Boston, MA 02111-1307 USA | |||
*/ | |||
#ifndef PUSB_VERSION_H_ | |||
# define PUSB_VERSION_H_ | |||
# define PUSB_VERSION "0.4.0" | |||
#endif /* !PUSB_VERSION_H_ */ |
@ -0,0 +1,152 @@ | |||
/* | |||
* Copyright (c) 2003-2007 Andrea Luzzardi <scox@sig11.org> | |||
* | |||
* This file is part of the pam_usb project. pam_usb is free software; | |||
* you can redistribute it and/or modify it under the terms of the GNU General | |||
* Public License version 2, as published by the Free Software Foundation. | |||
* | |||
* pam_usb is distributed in the hope that it will be useful, but WITHOUT ANY | |||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |||
* details. | |||
* | |||
* You should have received a copy of the GNU General Public License along with | |||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||
* Place, Suite 330, Boston, MA 02111-1307 USA | |||
*/ | |||
#include <stdio.h> | |||
#include <string.h> | |||
#include <errno.h> | |||
#include <unistd.h> | |||
#include <stdlib.h> | |||
#include <sys/types.h> | |||
#include <sys/mount.h> | |||
#include <libhal-storage.h> | |||
#include "conf.h" | |||
#include "log.h" | |||
#include "hal.h" | |||
#include "volume.h" | |||
static int pusb_volume_mount(t_pusb_options *opts, LibHalVolume **volume, | |||
LibHalContext *ctx) | |||
{ | |||
char command[1024]; | |||
char tempname[32]; | |||
const char *devname; | |||
const char *udi; | |||
const char *fs; | |||
snprintf(tempname, sizeof(tempname), "pam_usb%d", getpid()); | |||
if (!(devname = libhal_volume_get_device_file(*volume))) | |||
{ | |||
log_error("Unable to retrieve device filename\n"); | |||
return (0); | |||
} | |||
fs = libhal_volume_get_fstype(*volume); | |||
log_debug("Attempting to mount device %s with label %s\n", | |||
devname, tempname); | |||
if (!fs) | |||
snprintf(command, sizeof(command), "pmount -s %s %s", | |||
devname, tempname); | |||
else | |||
snprintf(command, sizeof(command), "pmount -s -t %s %s %s", | |||
fs, devname, tempname); | |||
log_debug("Executing \"%s\"\n", command); | |||
if (system(command) != 0) | |||
{ | |||
log_error("Mount failed\n"); | |||
return (0); | |||
} | |||
udi = libhal_volume_get_udi(*volume); | |||
if (!udi) | |||
{ | |||
log_error("Unable to retrieve volume UDI\n"); | |||
return (0); | |||
} | |||
udi = strdup(udi); | |||
libhal_volume_free(*volume); | |||
*volume = libhal_volume_from_udi(ctx, udi); | |||
free((char *)udi); | |||
log_debug("Mount succeeded.\n"); | |||
return (1); | |||
} | |||
static LibHalVolume *pusb_volume_probe(t_pusb_options *opts, | |||
LibHalContext *ctx) | |||
{ | |||
LibHalVolume *volume = NULL; | |||
int maxtries = 0; | |||
int i; | |||
if (!*(opts->device.volume_uuid)) | |||
{ | |||
log_debug("No UUID configured for device\n"); | |||
return (NULL); | |||
} | |||
log_debug("Searching for volume with uuid %s\n", opts->device.volume_uuid); | |||
maxtries = ((opts->probe_timeout * 1000000) / 250000); | |||
for (i = 0; i < maxtries; ++i) | |||
{ | |||
char *udi = NULL; | |||
if (i == 1) | |||
log_info("Probing volume (this could take a while)...\n"); | |||
udi = pusb_hal_find_item(ctx, | |||
"volume.uuid", opts->device.volume_uuid, | |||
NULL); | |||
if (!udi) | |||
{ | |||
usleep(250000); | |||
continue; | |||
} | |||
volume = libhal_volume_from_udi(ctx, udi); | |||
libhal_free_string(udi); | |||
if (!libhal_volume_should_ignore(volume)) | |||
return (volume); | |||
libhal_volume_free(volume); | |||
usleep(250000); | |||
} | |||
return (NULL); | |||
} | |||
LibHalVolume *pusb_volume_get(t_pusb_options *opts, LibHalContext *ctx) | |||
{ | |||
LibHalVolume *volume; | |||
if (!(volume = pusb_volume_probe(opts, ctx))) | |||
return (NULL); | |||
log_debug("Found volume %s\n", opts->device.volume_uuid); | |||
if (libhal_volume_is_mounted(volume)) | |||
{ | |||
log_debug("Volume is already mounted.\n"); | |||
return (volume); | |||
} | |||
if (!pusb_volume_mount(opts, &volume, ctx)) | |||
{ | |||
libhal_volume_free(volume); | |||
return (NULL); | |||
} | |||
return (volume); | |||
} | |||
void pusb_volume_destroy(LibHalVolume *volume) | |||
{ | |||
const char *mntpoint; | |||
mntpoint = libhal_volume_get_mount_point(volume); | |||
if (mntpoint && strstr(mntpoint, "pam_usb")) | |||
{ | |||
char command[1024]; | |||
log_debug("Attempting to umount %s\n", | |||
mntpoint); | |||
snprintf(command, sizeof(command), "pumount %s", mntpoint); | |||
log_debug("Executing \"%s\"\n", command); | |||
if (!system(command)) | |||
log_debug("Umount succeeded.\n"); | |||
else | |||
log_error("Unable to umount %s\n", mntpoint); | |||
} | |||
libhal_volume_free(volume); | |||
} |
@ -0,0 +1,24 @@ | |||
/* | |||
* Copyright (c) 2003-2007 Andrea Luzzardi <scox@sig11.org> | |||
* | |||
* This file is part of the pam_usb project. pam_usb is free software; | |||
* you can redistribute it and/or modify it under the terms of the GNU General | |||
* Public License version 2, as published by the Free Software Foundation. | |||
* | |||
* pam_usb is distributed in the hope that it will be useful, but WITHOUT ANY | |||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |||
* details. | |||
* | |||
* You should have received a copy of the GNU General Public License along with | |||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||
* Place, Suite 330, Boston, MA 02111-1307 USA | |||
*/ | |||
#ifndef VOLUME_H_ | |||
# define VOLUME_H_ | |||
LibHalVolume *pusb_volume_get(t_pusb_options *opts, LibHalContext *ctx); | |||
void pusb_volume_destroy(LibHalVolume *volume); | |||
#endif /* !VOLUME_H_ */ |
@ -0,0 +1,219 @@ | |||
/* | |||
* Copyright (c) 2003-2007 Andrea Luzzardi <scox@sig11.org> | |||
* | |||
* This file is part of the pam_usb project. pam_usb is free software; | |||
* you can redistribute it and/or modify it under the terms of the GNU General | |||
* Public License version 2, as published by the Free Software Foundation. | |||
* | |||
* pam_usb is distributed in the hope that it will be useful, but WITHOUT ANY | |||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |||
* details. | |||
* | |||
* You should have received a copy of the GNU General Public License along with | |||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||
* Place, Suite 330, Boston, MA 02111-1307 USA | |||
*/ | |||
#include <libxml/xpath.h> | |||
#include <ctype.h> | |||
#include <string.h> | |||
#include "xpath.h" | |||
#include "log.h" | |||
static xmlXPathObject *pusb_xpath_match(xmlDocPtr doc, const char *path) | |||
{ | |||
xmlXPathContext *context = NULL; | |||
xmlXPathObject *result = NULL; | |||
context = xmlXPathNewContext(doc); | |||
if (context == NULL) | |||
{ | |||
log_error("Unable to create XML context\n"); | |||
return (NULL); | |||
} | |||
result = xmlXPathEvalExpression((xmlChar *)path, context); | |||
xmlXPathFreeContext(context); | |||
if (result == NULL) | |||
{ | |||
log_error("Error in xmlXPathEvalExpression\n"); | |||
return (NULL); | |||
} | |||
if (xmlXPathNodeSetIsEmpty(result->nodesetval)) | |||
{ | |||
xmlXPathFreeObject(result); | |||
return (NULL); | |||
} | |||
return (result); | |||
} | |||
static int pusb_xpath_strip_string(char *dest, const char *src, | |||
size_t size) | |||
{ | |||
int first_char = -1; | |||
int last_char = -1; | |||
int i; | |||
for (i = 0; src[i]; ++i) | |||
{ | |||
if (isspace(src[i])) | |||
continue ; | |||
if (first_char == -1) | |||
first_char = i; | |||
last_char = i; | |||
} | |||
if (first_char == -1 || last_char == -1) | |||
return (0); | |||
if ((last_char - first_char) > (size - 1)) | |||
return (0); | |||
memset(dest, 0x0, size); | |||
strncpy(dest, &(src[first_char]), last_char - first_char + 1); | |||
return (1); | |||
} | |||
int pusb_xpath_get_string(xmlDocPtr doc, const char *path, | |||
char *value, size_t size) | |||
{ | |||
xmlXPathObject *result = NULL; | |||
xmlNode *node = NULL; | |||
xmlChar *result_string = NULL; | |||
if (!(result = pusb_xpath_match(doc, path))) | |||
return (0); | |||
if (result->nodesetval->nodeNr > 1) | |||
{ | |||
xmlXPathFreeObject(result); | |||
log_debug("Syntax error: %s: more than one record found\n", path); | |||
return (0); | |||
} | |||
node = result->nodesetval->nodeTab[0]->xmlChildrenNode; | |||
result_string = xmlNodeListGetString(doc, node, 1); | |||
if (!result_string) | |||
{ | |||
xmlXPathFreeObject(result); | |||
log_debug("Empty value for %s\n", path); | |||
return (0); | |||
} | |||
if (!pusb_xpath_strip_string(value, (const char *)result_string, size)) | |||
{ | |||
xmlFree(result_string); | |||
xmlXPathFreeObject(result); | |||
log_debug("Result for %s (%s) is too long (max: %d)\n", | |||
path, (const char *)result_string, size); | |||
return (0); | |||
} | |||
xmlFree(result_string); | |||
xmlXPathFreeObject(result); | |||
return (1); | |||
} | |||
int pusb_xpath_get_string_from(xmlDocPtr doc, | |||
const char *base, | |||
const char *path, | |||
char *value, size_t size) | |||
{ | |||
char *xpath = NULL; | |||
size_t xpath_size; | |||
int retval; | |||
xpath_size = strlen(base) + strlen(path) + 1; | |||
if (!(xpath = malloc(xpath_size))) | |||
{ | |||
log_error("malloc error !\n"); | |||
return (0); | |||
} | |||
memset(xpath, 0x00, xpath_size); | |||
snprintf(xpath, xpath_size, "%s%s", base, path); | |||
retval = pusb_xpath_get_string(doc, xpath, value, size); | |||
if (retval) | |||
log_debug("%s%s -> %s\n", base, path, value); | |||
free(xpath); | |||
return (retval); | |||
} | |||
int pusb_xpath_get_bool(xmlDocPtr doc, const char *path, int *value) | |||
{ | |||
char ret[6]; /* strlen("false") + 1 */ | |||
if (!pusb_xpath_get_string(doc, path, ret, sizeof(ret))) | |||
return (0); | |||
if (!strcmp(ret, "true")) | |||
{ | |||
*value = 1; | |||
return (1); | |||
} | |||
if (!strcmp(ret, "false")) | |||
{ | |||
*value = 0; | |||
return (1); | |||
} | |||
log_debug("Expecting a boolean, got %s\n", ret); | |||
return (0); | |||
} | |||
int pusb_xpath_get_bool_from(xmlDocPtr doc, | |||
const char *base, | |||
const char *path, | |||
int *value) | |||
{ | |||
char *xpath = NULL; | |||
size_t xpath_size; | |||
int retval; | |||
xpath_size = strlen(base) + strlen(path) + 1; | |||
if (!(xpath = malloc(xpath_size))) | |||
{ | |||
log_error("malloc error!\n"); | |||
return (0); | |||
} | |||
memset(xpath, 0x00, xpath_size); | |||
snprintf(xpath, xpath_size, "%s%s", base, path); | |||
retval = pusb_xpath_get_bool(doc, xpath, value); | |||
free(xpath); | |||
if (retval) | |||
log_debug("%s%s -> %s\n", base, path, *value ? "true" : "false"); | |||
return (retval); | |||
} | |||
int pusb_xpath_get_int(xmlDocPtr doc, const char *path, int *value) | |||
{ | |||
char ret[64]; /* strlen("false") + 1 */ | |||
if (!pusb_xpath_get_string(doc, path, ret, sizeof(ret))) | |||
return (0); | |||
*value = atoi(ret); | |||
return (1); | |||
} | |||
int pusb_xpath_get_int_from(xmlDocPtr doc, | |||
const char *base, | |||
const char *path, | |||
int *value) | |||
{ | |||
char *xpath = NULL; | |||
size_t xpath_size; | |||
int retval; | |||
xpath_size = strlen(base) + strlen(path) + 1; | |||
if (!(xpath = malloc(xpath_size))) | |||
{ | |||
log_error("malloc error!\n"); | |||
return (0); | |||
} | |||
memset(xpath, 0x00, xpath_size); | |||
snprintf(xpath, xpath_size, "%s%s", base, path); | |||
retval = pusb_xpath_get_int(doc, xpath, value); | |||
free(xpath); | |||
if (retval) | |||
log_debug("%s%s -> %d\n", base, path, *value); | |||
return (retval); | |||
} |
@ -0,0 +1,29 @@ | |||
/* | |||
* Copyright (c) 2003-2007 Andrea Luzzardi <scox@sig11.org> | |||
* | |||
* This file is part of the pam_usb project. pam_usb is free software; | |||
* you can redistribute it and/or modify it under the terms of the GNU General | |||
* Public License version 2, as published by the Free Software Foundation. | |||
* | |||
* pam_usb is distributed in the hope that it will be useful, but WITHOUT ANY | |||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |||
* details. | |||
* | |||
* You should have received a copy of the GNU General Public License along with | |||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||
* Place, Suite 330, Boston, MA 02111-1307 USA | |||
*/ | |||
#ifndef PUSB_XPATH_H_ | |||
# define PUSB_XPATH_H_ | |||
# include <libxml/parser.h> | |||
int pusb_xpath_get_string(xmlDocPtr doc, const char *path, char *value, size_t size); | |||
int pusb_xpath_get_bool(xmlDocPtr doc, const char *path, int *value); | |||
int pusb_xpath_get_string_from(xmlDocPtr doc, const char *base, const char *path, char *value, size_t size); | |||
int pusb_xpath_get_bool_from(xmlDocPtr doc, const char *base, const char *path, int *value); | |||
int pusb_xpath_get_int(xmlDocPtr doc, const char *path, int *value); | |||
int pusb_xpath_get_int_from(xmlDocPtr doc, const char *base, const char *path, int *value); | |||
#endif /* !PUSB_XPATH_H_ */ |
@ -0,0 +1,211 @@ | |||
#!/usr/bin/env python | |||
# | |||
# Copyright (c) 2003-2007 Andrea Luzzardi <scox@sig11.org> | |||
# | |||
# This file is part of the pam_usb project. pam_usb is free software; | |||
# you can redistribute it and/or modify it under the terms of the GNU General | |||
# Public License version 2, as published by the Free Software Foundation. | |||
# | |||
# pam_usb is distributed in the hope that it will be useful, but WITHOUT ANY | |||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |||
# details. | |||
# | |||
# You should have received a copy of the GNU General Public License along with | |||
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||
# Place, Suite 330, Boston, MA 02111-1307 USA | |||
import os | |||
import sys | |||
import pwd | |||
import getopt | |||
import syslog | |||
import gobject | |||
import dbus | |||
if getattr(dbus, 'version', (0,0,0)) >= (0,41,0): | |||
import dbus.glib | |||
try: | |||
import cElementTree as et | |||
except ImportError: | |||
import elementtree.ElementTree as et | |||
class HotPlugDevice: | |||
def __init__(self, serial): | |||
self.__udi = None | |||
self.__serial = serial | |||
self.__callbacks = [] | |||
self.__bus = dbus.SystemBus() | |||
self.__running = False | |||
def run(self): | |||
self.__scanDevices() | |||
self.__registerSignals() | |||
self.__running = True | |||
gobject.MainLoop().run() | |||
print 'signals registered' | |||
def addCallback(self, callback): | |||
self.__callbacks.append(callback) | |||
def __scanDevices(self): | |||
halService = self.__bus.get_object('org.freedesktop.Hal', | |||
'/org/freedesktop/Hal/Manager') | |||
halManager = dbus.Interface(halService, 'org.freedesktop.Hal.Manager') | |||
for udi in halManager.FindDeviceStringMatch('info.bus', 'usb_device'): | |||
self.__deviceAdded(udi) | |||
def __registerSignals(self): | |||
for signal, callback in (('DeviceAdded', self.__deviceAdded), | |||
('DeviceRemoved', self.__deviceRemoved)): | |||
self.__bus.add_signal_receiver(callback, | |||
signal, | |||
'org.freedesktop.Hal.Manager', | |||
'org.freedesktop.Hal', | |||
'/org/freedesktop/Hal/Manager') | |||
def __deviceAdded(self, udi): | |||
if self.__udi is not None: | |||
return | |||
deviceObj = self.__bus.get_object('org.freedesktop.Hal', | |||
udi) | |||
deviceProperties = deviceObj.GetAllProperties( | |||
dbus_interface = 'org.freedesktop.Hal.Device') | |||
if not deviceProperties.has_key('usb_device.serial'): | |||
return | |||
if deviceProperties['usb_device.serial'] != self.__serial: | |||
return | |||
self.__udi = udi | |||
if self.__running: | |||
[ cb('added') for cb in self.__callbacks ] | |||
def __deviceRemoved(self, udi): | |||
if self.__udi is None: | |||
return | |||
if self.__udi != udi: | |||
return | |||
self.__udi = None | |||
if self.__running: | |||
[ cb('removed') for cb in self.__callbacks ] | |||
class Log: | |||
def __init__(self): | |||
syslog.openlog('pamusb-agent', syslog.LOG_PID | syslog.LOG_PERROR, | |||
syslog.LOG_AUTH) | |||
def info(self, message): | |||
self.__logMessage(syslog.LOG_NOTICE, message) | |||
def error(self, message): | |||
self.__logMessage(syslog.LOG_ERR, message) | |||
def __logMessage(self, priority, message): | |||
syslog.syslog(priority, message) | |||
def usage(): | |||
print 'Usage: %s [--help] [--config=path] [--daemon] [--check=path]' % \ | |||
os.path.basename(__file__) | |||
sys.exit(1) | |||
import getopt | |||
try: | |||
opts, args = getopt.getopt(sys.argv[1:], "hc:dc:", | |||
["help", "config=", "daemon", "check="]) | |||
except getopt.GetoptError: | |||
usage() | |||
options = {'configFile' : '/etc/pamusb.conf', | |||
'daemon' : False, | |||
'check' : '/usr/bin/pamusb-check'} | |||
if len(args) != 0: | |||
usage() | |||
for o, a in opts: | |||
if o in ('-h', '--help'): | |||
usage() | |||
if o in ('-c', '--config'): | |||
options['configFile'] = a | |||
if o in ('-d', '--daemon'): | |||
options['daemon'] = True | |||
if o in ('-c', '--check'): | |||
options['check'] = a | |||
if not os.path.exists(options['check']): | |||
print '%s not found.' % options['check'] | |||
print "You might specify manually pamusb-check's location using --check." | |||
usage() | |||
username = pwd.getpwuid(os.getuid())[0] | |||
logger = Log() | |||
doc = et.parse(options['configFile']) | |||
users = doc.findall('users/user') | |||
for user in users: | |||
if user.get('id') == username: | |||
break | |||
else: | |||
logger.error('User %s not found in configuration file' % username) | |||
sys.exit(1) | |||
events = { | |||
'lock' : [], | |||
'unlock' : [] | |||
} | |||
for hotplug in user.findall('agent'): | |||
events[hotplug.get('event')].append(hotplug.text) | |||
deviceName = user.find('device').text.strip() | |||
devices = doc.findall("devices/device") | |||
for device in devices: | |||
if device.get('id') == deviceName: | |||
break | |||
else: | |||
logger.error('Device %s not found in configurtion file' % deviceName) | |||
sys.exit(1) | |||
serial = device.find('serial').text.strip() | |||
def authChangeCallback(event): | |||
if event == 'removed': | |||
logger.info('Device "%s" has been removed, ' \ | |||
'locking down user "%s"...' % (deviceName, username)) | |||
for cmd in events['lock']: | |||
logger.info('Running "%s"' % cmd) | |||
os.system(cmd) | |||
logger.info('Locked.') | |||
return | |||
logger.info('Device "%s" has been inserted. ' \ | |||
'Performing verification...' % deviceName) | |||
cmdLine = "%s --quiet --config=%s --service=pamusb-agent %s" % ( | |||
options['check'], options['configFile'], username) | |||
logger.info('Executing "%s"' % cmdLine) | |||
if not os.system(cmdLine): | |||
logger.info('Authentication succeeded. ' \ | |||
'Unlocking user "%s"...' % username) | |||
for cmd in events['unlock']: | |||
logger.info('Running "%s"' % cmd) | |||
os.system(cmd) | |||
logger.info('Unlocked.') | |||
else: | |||
logger.info('Authentication failed for device %s. ' \ | |||
'Keeping user "%s" locked down.' % (deviceName, username)) | |||
hpDev = HotPlugDevice(serial) | |||
hpDev.addCallback(authChangeCallback) | |||
if options['daemon'] and os.fork(): | |||
sys.exit(0) | |||
logger.info('pamusb-agent up and running.') | |||
logger.info('Watching device "%s" for user "%s"' % (deviceName, username)) | |||
try: | |||
hpDev.run() | |||
except KeyboardInterrupt: | |||
logger.error('Caught keyboard interruption, exiting...') |
@ -0,0 +1,271 @@ | |||
#!/usr/bin/env python | |||
# | |||
# Copyright (c) 2003-2007 Andrea Luzzardi <scox@sig11.org> | |||
# | |||
# This file is part of the pam_usb project. pam_usb is free software; | |||
# you can redistribute it and/or modify it under the terms of the GNU General | |||
# Public License version 2, as published by the Free Software Foundation. | |||
# | |||
# pam_usb is distributed in the hope that it will be useful, but WITHOUT ANY | |||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | |||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |||
# details. | |||
# | |||
# You should have received a copy of the GNU General Public License along with | |||
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |||
# Place, Suite 330, Boston, MA 02111-1307 USA | |||
import dbus | |||
import sys | |||
import os | |||
from xml.dom import minidom | |||
class Device: | |||
def __init__(self, udi): | |||
self.__udi = udi | |||
self.__findStorageDevice() | |||
deviceObj = bus.get_object('org.freedesktop.Hal', | |||
udi) | |||
deviceProperties = deviceObj.GetAllProperties( | |||
dbus_interface = 'org.freedesktop.Hal.Device') | |||
self.vendor = deviceProperties['usb_device.vendor'] | |||
self.product = deviceProperties['info.product'] | |||
self.serialNumber = deviceProperties['usb_device.serial'] | |||
if len(self.volumes()) < 1: | |||
raise Exception, '%s does not contain any volume' % self.__udi | |||
def __isChildOfDevice(self, udi): | |||
obj = bus.get_object('org.freedesktop.Hal', udi) | |||
properties = obj.GetAllProperties( | |||
dbus_interface = 'org.freedesktop.Hal.Device') | |||
if not properties.has_key('info.parent'): | |||
return False | |||
if properties.has_key('info.bus') and properties['info.bus'] == 'usb_device': | |||
return False | |||
if properties['info.parent'] == self.__udi: | |||
return True | |||
return self.__isChildOfDevice(properties['info.parent']) | |||
def __findStorageDevice(self): | |||
for child in halManager.FindDeviceByCapability('storage'): | |||
if self.__isChildOfDevice(child): | |||
self.__storageUdi = child | |||
return | |||
raise Exception, '%s is not a storage device.' % self.__udi | |||
def __repr__(self): | |||
return "%s %s (%s)" % (self.vendor, self.product, self.serialNumber) | |||
def volumes(self): | |||
vols = [] | |||
for volume in halManager.FindDeviceByCapability('volume'): | |||
deviceObj = bus.get_object('org.freedesktop.Hal', | |||
volume) | |||
deviceProperties = deviceObj.GetAllProperties( | |||
dbus_interface = 'org.freedesktop.Hal.Device') | |||
if deviceProperties['block.storage_device'] != self.__storageUdi: | |||
continue | |||
vols.append({'uuid' : deviceProperties['volume.uuid'], | |||
'device' : deviceProperties['block.device']}) | |||
return vols | |||
def listOptions(question, options, autodetect = True): | |||
if autodetect == True and len(options) == 1: | |||
print question | |||
print "* Using \"%s\" (only option)" % options[0] | |||
return 0 | |||
while True: | |||
try: | |||
print question | |||
for i in range(len(options)): | |||
print "%d) %s" % (i, options[i]) | |||
sys.stdout.write('[%s-%s]: ' % (0, len(options) - 1)) | |||
optionId = int(sys.stdin.readline()) | |||
if optionId not in range(len(options)): | |||
raise Exception | |||
return optionId | |||
except KeyboardInterrupt: sys.exit() | |||
except Exception: pass | |||
else: break | |||
def writeConf(options, doc): | |||
try: | |||
f = open(options['configFile'], 'w') | |||
doc.writexml(f) | |||
f.close() | |||
except Exception, err: | |||
print 'Unable to save %s: %s' % (options['configFile'], err) | |||
sys.exit(1) | |||
else: | |||
print 'Done.' | |||
def shouldSave(options, items): | |||
print "\n".join(["%s\t\t: %s" % item for item in items]) | |||
print 'Save to %s ?' % options['configFile'] | |||
sys.stdout.write('[Y/n] ') | |||
response = sys.stdin.readline().strip() | |||
if len(response) > 0 and response.lower() != 'y': | |||
sys.exit(1) | |||
def prettifyElement(element): | |||
tmp = minidom.parseString(element.toprettyxml()) | |||
return tmp.lastChild | |||
def addUser(options): | |||
try: | |||
doc = minidom.parse(options['configFile']) | |||
except Exception, err: | |||
print 'Unable to read %s: %s' % (options['configFile'], err) | |||
sys.exit(1) | |||
devSection = doc.getElementsByTagName('devices') | |||
if len(devSection) == 0: | |||
print 'Malformed configuration file: No <devices> section found.' | |||
sys.exit(1) | |||
devicesObj = devSection[0].getElementsByTagName('device') | |||
if len(devicesObj) == 0: | |||
print 'No devices found.' | |||
print 'You must add a device (--add-device) before adding users' | |||
sys.exit(1) | |||
devices = [] | |||
for device in devicesObj: | |||
devices.append(device.getAttribute('id')) | |||
device = devices[listOptions("Which device would you like to use for authentication ?", | |||
devices)] | |||
shouldSave(options, [ | |||
('User', options['userName']), | |||
('Device', device) | |||
]) | |||
users = doc.getElementsByTagName('users') | |||
user = doc.createElement('user') | |||
user.attributes['id'] = options['userName'] | |||
e = doc.createElement('device') | |||
t = doc.createTextNode(device) | |||
e.appendChild(t) | |||
user.appendChild(e) | |||
users[0].appendChild(prettifyElement(user)) | |||
writeConf(options, doc) | |||
def addDevice(options): | |||
devices = [] | |||
for udi in halManager.FindDeviceStringMatch('info.bus', 'usb_device'): | |||
try: | |||
devices.append(Device(udi)) | |||
except Exception, ex: | |||
pass | |||
if len(devices) == 0: | |||
print 'No devices detected.' | |||
sys.exit() | |||
device = devices[listOptions("Please select the device you wish to add.", devices)] | |||
volumes = device.volumes() | |||
volume = volumes[listOptions("Which volume would you like to use for " \ | |||
"storing data ?", | |||
["%s (UUID: %s)" % (volume['device'], | |||
volume['uuid'] or "<UNDEFINED>") | |||
for volume in volumes] | |||
)] | |||
if volume['uuid'] == '': | |||
print 'WARNING: No UUID detected for device %s. One time pads will be disabled.' % volume['device'] | |||
shouldSave(options,[ | |||
('Name', options['deviceName']), | |||
('Vendor', device.vendor), | |||
('Model', device.product), | |||
('Serial', device.serialNumber), | |||
('UUID', volume['uuid'] or "<UNDEFINED>") | |||
]) | |||
try: | |||
doc = minidom.parse(options['configFile']) | |||
except Exception, err: | |||
print 'Unable to read %s: %s' % (options['configFile'], err) | |||
sys.exit(1) | |||
devs = doc.getElementsByTagName('devices') | |||
dev = doc.createElement('device') | |||
dev.attributes['id'] = options['deviceName'] | |||
for name, value in (('vendor', device.vendor), | |||
('model', device.product), | |||
('serial', device.serialNumber), | |||
('volume_uuid', volume['uuid'])): | |||
if value == '': | |||
continue | |||
e = doc.createElement(name) | |||
t = doc.createTextNode(value) | |||
e.appendChild(t) | |||
dev.appendChild(e) | |||
# Disable one time pads if there's no device UUID | |||
if volume['uuid'] == '': | |||
e = doc.createElement('option') | |||
e.setAttribute('name', 'one_time_pad') | |||
e.appendChild(doc.createTextNode('false')) | |||
dev.appendChild(e) | |||
devs[0].appendChild(prettifyElement(dev)) | |||
writeConf(options, doc) | |||
def usage(): | |||
print 'Usage: %s [--help] [--config=path] [--add-user=name | --add-device=name]' % os.path.basename(__file__) | |||
sys.exit(1) | |||
import getopt | |||
try: | |||
opts, args = getopt.getopt(sys.argv[1:], "hd:nu:c:", | |||
["help", "add-device=", "add-user=", "config="]) | |||
except getopt.GetoptError: | |||
usage() | |||
if len(args) != 0: | |||
usage() | |||
options = { 'deviceName' : None, 'userName' : None, | |||
'configFile' : '/etc/pamusb.conf' } | |||
for o, a in opts: | |||
if o in ("-h", "--help"): | |||
usage() | |||
if o in ("-d", "--add-device"): | |||
options['deviceName'] = a | |||
if o in ("-u", "--add-user"): | |||
options['userName'] = a | |||
if o in ("-c", "--config"): | |||
options['configFile'] = a | |||
if options['deviceName'] is not None and options['userName'] is not None: | |||
print 'You cannot use both --add-user and --add-device' | |||
usage() | |||
if options['deviceName'] is None and options['userName'] is None: | |||
usage() | |||
if options['deviceName'] is not None: | |||
bus = dbus.SystemBus() | |||
halService = bus.get_object('org.freedesktop.Hal', | |||
'/org/freedesktop/Hal/Manager') | |||
halManager = dbus.Interface(halService, 'org.freedesktop.Hal.Manager') | |||
try: | |||
addDevice(options) | |||
except KeyboardInterrupt: | |||
sys.exit(1) | |||
if options['userName'] is not None: | |||
try: | |||
addUser(options) | |||
except KeyboardInterrupt: | |||
sys.exit(1) | |||