@ -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) | |||||