├── .gitignore ├── AUTHORS ├── COPYING ├── ChangeLog ├── INSTALL ├── Makefile.am ├── NEWS ├── README ├── TODO ├── acinclude.m4 ├── autogen.sh ├── configure.ac ├── data ├── Makefile.am ├── fprintd.conf ├── net.reactivated.Fprint.conf ├── net.reactivated.Fprint.service.in └── net.reactivated.fprint.device.policy.in ├── doc ├── Makefile.am ├── dbus │ ├── Makefile.am │ ├── dbus-introspect-docs.dtd │ └── spec-to-docbook.xsl ├── fprintd-docs.xml └── version.xml.in ├── pam ├── Makefile.am ├── README ├── fingerprint-strings.h └── pam_fprintd.c ├── po └── POTFILES.in ├── src ├── Makefile.am ├── device.c ├── device.xml ├── egg-dbus-monitor.c ├── egg-dbus-monitor.h ├── file_storage.c ├── file_storage.h ├── fprintd-marshal.list ├── fprintd.h ├── main.c ├── manager.c ├── manager.xml └── storage.h └── tests ├── Makefile.am ├── delete.c ├── enroll.c ├── list.c └── verify.c /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile.in 2 | Makefile 3 | aclocal.m4 4 | compile 5 | autom4te.cache 6 | configure 7 | depcomp 8 | install-sh 9 | missing 10 | config.log 11 | config.status 12 | .deps 13 | client-bindings.h 14 | *-dbus-glue.h 15 | verify 16 | enroll 17 | *.o 18 | fprintd 19 | *.swp 20 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Daniel Drake 2 | Bastien Nocera 3 | 4 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dsd/fprintd/4ea1c48f9fc8d851a765e8d4ccedf0a4378ac079/ChangeLog -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Installation Instructions 2 | ************************* 3 | 4 | Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, 5 | 2006, 2007 Free Software Foundation, Inc. 6 | 7 | This file is free documentation; the Free Software Foundation gives 8 | unlimited permission to copy, distribute and modify it. 9 | 10 | Basic Installation 11 | ================== 12 | 13 | Briefly, the shell commands `./configure; make; make install' should 14 | configure, build, and install this package. The following 15 | more-detailed instructions are generic; see the `README' file for 16 | instructions specific to this package. 17 | 18 | The `configure' shell script attempts to guess correct values for 19 | various system-dependent variables used during compilation. It uses 20 | those values to create a `Makefile' in each directory of the package. 21 | It may also create one or more `.h' files containing system-dependent 22 | definitions. Finally, it creates a shell script `config.status' that 23 | you can run in the future to recreate the current configuration, and a 24 | file `config.log' containing compiler output (useful mainly for 25 | debugging `configure'). 26 | 27 | It can also use an optional file (typically called `config.cache' 28 | and enabled with `--cache-file=config.cache' or simply `-C') that saves 29 | the results of its tests to speed up reconfiguring. Caching is 30 | disabled by default to prevent problems with accidental use of stale 31 | cache files. 32 | 33 | If you need to do unusual things to compile the package, please try 34 | to figure out how `configure' could check whether to do them, and mail 35 | diffs or instructions to the address given in the `README' so they can 36 | be considered for the next release. If you are using the cache, and at 37 | some point `config.cache' contains results you don't want to keep, you 38 | may remove or edit it. 39 | 40 | The file `configure.ac' (or `configure.in') is used to create 41 | `configure' by a program called `autoconf'. You need `configure.ac' if 42 | you want to change it or regenerate `configure' using a newer version 43 | of `autoconf'. 44 | 45 | The simplest way to compile this package is: 46 | 47 | 1. `cd' to the directory containing the package's source code and type 48 | `./configure' to configure the package for your system. 49 | 50 | Running `configure' might take a while. While running, it prints 51 | some messages telling which features it is checking for. 52 | 53 | 2. Type `make' to compile the package. 54 | 55 | 3. Optionally, type `make check' to run any self-tests that come with 56 | the package. 57 | 58 | 4. Type `make install' to install the programs and any data files and 59 | documentation. 60 | 61 | 5. You can remove the program binaries and object files from the 62 | source code directory by typing `make clean'. To also remove the 63 | files that `configure' created (so you can compile the package for 64 | a different kind of computer), type `make distclean'. There is 65 | also a `make maintainer-clean' target, but that is intended mainly 66 | for the package's developers. If you use it, you may have to get 67 | all sorts of other programs in order to regenerate files that came 68 | with the distribution. 69 | 70 | 6. Often, you can also type `make uninstall' to remove the installed 71 | files again. 72 | 73 | Compilers and Options 74 | ===================== 75 | 76 | Some systems require unusual options for compilation or linking that the 77 | `configure' script does not know about. Run `./configure --help' for 78 | details on some of the pertinent environment variables. 79 | 80 | You can give `configure' initial values for configuration parameters 81 | by setting variables in the command line or in the environment. Here 82 | is an example: 83 | 84 | ./configure CC=c99 CFLAGS=-g LIBS=-lposix 85 | 86 | *Note Defining Variables::, for more details. 87 | 88 | Compiling For Multiple Architectures 89 | ==================================== 90 | 91 | You can compile the package for more than one kind of computer at the 92 | same time, by placing the object files for each architecture in their 93 | own directory. To do this, you can use GNU `make'. `cd' to the 94 | directory where you want the object files and executables to go and run 95 | the `configure' script. `configure' automatically checks for the 96 | source code in the directory that `configure' is in and in `..'. 97 | 98 | With a non-GNU `make', it is safer to compile the package for one 99 | architecture at a time in the source code directory. After you have 100 | installed the package for one architecture, use `make distclean' before 101 | reconfiguring for another architecture. 102 | 103 | Installation Names 104 | ================== 105 | 106 | By default, `make install' installs the package's commands under 107 | `/usr/local/bin', include files under `/usr/local/include', etc. You 108 | can specify an installation prefix other than `/usr/local' by giving 109 | `configure' the option `--prefix=PREFIX'. 110 | 111 | You can specify separate installation prefixes for 112 | architecture-specific files and architecture-independent files. If you 113 | pass the option `--exec-prefix=PREFIX' to `configure', the package uses 114 | PREFIX as the prefix for installing programs and libraries. 115 | Documentation and other data files still use the regular prefix. 116 | 117 | In addition, if you use an unusual directory layout you can give 118 | options like `--bindir=DIR' to specify different values for particular 119 | kinds of files. Run `configure --help' for a list of the directories 120 | you can set and what kinds of files go in them. 121 | 122 | If the package supports it, you can cause programs to be installed 123 | with an extra prefix or suffix on their names by giving `configure' the 124 | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. 125 | 126 | Optional Features 127 | ================= 128 | 129 | Some packages pay attention to `--enable-FEATURE' options to 130 | `configure', where FEATURE indicates an optional part of the package. 131 | They may also pay attention to `--with-PACKAGE' options, where PACKAGE 132 | is something like `gnu-as' or `x' (for the X Window System). The 133 | `README' should mention any `--enable-' and `--with-' options that the 134 | package recognizes. 135 | 136 | For packages that use the X Window System, `configure' can usually 137 | find the X include and library files automatically, but if it doesn't, 138 | you can use the `configure' options `--x-includes=DIR' and 139 | `--x-libraries=DIR' to specify their locations. 140 | 141 | Specifying the System Type 142 | ========================== 143 | 144 | There may be some features `configure' cannot figure out automatically, 145 | but needs to determine by the type of machine the package will run on. 146 | Usually, assuming the package is built to be run on the _same_ 147 | architectures, `configure' can figure that out, but if it prints a 148 | message saying it cannot guess the machine type, give it the 149 | `--build=TYPE' option. TYPE can either be a short name for the system 150 | type, such as `sun4', or a canonical name which has the form: 151 | 152 | CPU-COMPANY-SYSTEM 153 | 154 | where SYSTEM can have one of these forms: 155 | 156 | OS KERNEL-OS 157 | 158 | See the file `config.sub' for the possible values of each field. If 159 | `config.sub' isn't included in this package, then this package doesn't 160 | need to know the machine type. 161 | 162 | If you are _building_ compiler tools for cross-compiling, you should 163 | use the option `--target=TYPE' to select the type of system they will 164 | produce code for. 165 | 166 | If you want to _use_ a cross compiler, that generates code for a 167 | platform different from the build platform, you should specify the 168 | "host" platform (i.e., that on which the generated programs will 169 | eventually be run) with `--host=TYPE'. 170 | 171 | Sharing Defaults 172 | ================ 173 | 174 | If you want to set default values for `configure' scripts to share, you 175 | can create a site shell script called `config.site' that gives default 176 | values for variables like `CC', `cache_file', and `prefix'. 177 | `configure' looks for `PREFIX/share/config.site' if it exists, then 178 | `PREFIX/etc/config.site' if it exists. Or, you can set the 179 | `CONFIG_SITE' environment variable to the location of the site script. 180 | A warning: not all `configure' scripts look for a site script. 181 | 182 | Defining Variables 183 | ================== 184 | 185 | Variables not defined in a site shell script can be set in the 186 | environment passed to `configure'. However, some packages may run 187 | configure again during the build, and the customized values of these 188 | variables may be lost. In order to avoid this problem, you should set 189 | them in the `configure' command line, using `VAR=value'. For example: 190 | 191 | ./configure CC=/usr/local2/bin/gcc 192 | 193 | causes the specified `gcc' to be used as the C compiler (unless it is 194 | overridden in the site shell script). 195 | 196 | Unfortunately, this technique does not work for `CONFIG_SHELL' due to 197 | an Autoconf bug. Until the bug is fixed you can use this workaround: 198 | 199 | CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash 200 | 201 | `configure' Invocation 202 | ====================== 203 | 204 | `configure' recognizes the following options to control how it operates. 205 | 206 | `--help' 207 | `-h' 208 | Print a summary of the options to `configure', and exit. 209 | 210 | `--version' 211 | `-V' 212 | Print the version of Autoconf used to generate the `configure' 213 | script, and exit. 214 | 215 | `--cache-file=FILE' 216 | Enable the cache: use and save the results of the tests in FILE, 217 | traditionally `config.cache'. FILE defaults to `/dev/null' to 218 | disable caching. 219 | 220 | `--config-cache' 221 | `-C' 222 | Alias for `--cache-file=config.cache'. 223 | 224 | `--quiet' 225 | `--silent' 226 | `-q' 227 | Do not print messages saying which checks are being made. To 228 | suppress all normal output, redirect it to `/dev/null' (any error 229 | messages will still be shown). 230 | 231 | `--srcdir=DIR' 232 | Look for the package's source code in directory DIR. Usually 233 | `configure' can determine that directory automatically. 234 | 235 | `configure' also accepts some other, not widely useful, options. Run 236 | `configure --help' for more details. 237 | 238 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | AUTOMAKE_OPTIONS = dist-bzip2 2 | SUBDIRS = src data tests pam doc po 3 | EXTRA_DIST = TODO intltool-extract.in intltool-merge.in intltool-update.in 4 | 5 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | This file lists notable changes in each release. For the full history of all 2 | changes, see ChangeLog. 3 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | fprintd 2 | ======= 3 | 4 | http://www.reactivated.net/fprint/wiki/Fprintd 5 | 6 | Daemon to offer libfprint functionality over D-Bus 7 | Currently in early stages. Might eat your kangaroo. 8 | 9 | Written in C. Requires bleeding edge libfprint (libusb-1.0 port). 10 | 11 | Licensed under the GPL version 2 (see COPYING). 12 | 13 | An experimental PAM login module is included in the 'pam' directory. 14 | This will be moved to a separate package once the system has matured. 15 | 16 | API use cases 17 | ============= 18 | 19 | - User wants to use the fingerprint reader, and enroll 20 | his fingerprints, or remove some fingerprints from the database 21 | 22 | - Administrator wants to enroll fingerprints for a particular user, 23 | or remove fingerprints for a particular user 24 | 25 | - Laptop/desktop authentication: 26 | * Check for fingerprint devices 27 | * Check whether a particular user has any fingerprints enrolled 28 | * Verify a fingerprint for a particular user, or, if the device 29 | supports it, verify that the fingerprint matches against 30 | any of the fingerprints enrolled 31 | 32 | - Point Of Sale authentication (in a bar, the fingerprint reader is 33 | used to see who accesses a particular point of sale/till, in place 34 | of PIN code authentication and/or tokens) 35 | * Given a list of users, verify which one has scanned their finger 36 | 37 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | Identification 2 | Image transfer 3 | 4 | Verify PAM messages fit with GDM/gnome-screensaver 5 | 6 | Register fprintd' po file with Transifex, Rosetta or the Translation Project 7 | 8 | Support insertion/removal of devices 9 | 10 | Add some hardware protection by making sure devices aren't opened and 11 | reading for more than a certain amount of time. 12 | 13 | Add POS use case 14 | 15 | Automatically show the fingerprint registration when logged in and 16 | not having any registered prints? 17 | http://uk.youtube.com/watch?v=F_x_vwCltbc 18 | 19 | -------------------------------------------------------------------------------- /acinclude.m4: -------------------------------------------------------------------------------- 1 | dnl AS_AC_EXPAND(VAR, CONFIGURE_VAR) 2 | dnl 3 | dnl example 4 | dnl AS_AC_EXPAND(SYSCONFDIR, $sysconfdir) 5 | dnl will set SYSCONFDIR to /usr/local/etc if prefix=/usr/local 6 | 7 | AC_DEFUN([AS_AC_EXPAND], 8 | [ 9 | EXP_VAR=[$1] 10 | FROM_VAR=[$2] 11 | 12 | dnl first expand prefix and exec_prefix if necessary 13 | prefix_save=$prefix 14 | exec_prefix_save=$exec_prefix 15 | 16 | dnl if no prefix given, then use /usr/local, the default prefix 17 | if test "x$prefix" = "xNONE"; then 18 | prefix=$ac_default_prefix 19 | fi 20 | dnl if no exec_prefix given, then use prefix 21 | if test "x$exec_prefix" = "xNONE"; then 22 | exec_prefix=$prefix 23 | fi 24 | 25 | full_var="$FROM_VAR" 26 | dnl loop until it doesn't change anymore 27 | while true; do 28 | new_full_var="`eval echo $full_var`" 29 | if test "x$new_full_var"="x$full_var"; then break; fi 30 | full_var=$new_full_var 31 | done 32 | 33 | dnl clean up 34 | full_var=$new_full_var 35 | AC_SUBST([$1], "$full_var") 36 | 37 | dnl restore prefix and exec_prefix 38 | prefix=$prefix_save 39 | exec_prefix=$exec_prefix_save 40 | ]) 41 | 42 | dnl GNOME_COMPILE_WARNINGS 43 | dnl Turn on many useful compiler warnings 44 | dnl For now, only works on GCC 45 | AC_DEFUN([GNOME_COMPILE_WARNINGS],[ 46 | dnl ****************************** 47 | dnl More compiler warnings 48 | dnl ****************************** 49 | 50 | AC_ARG_ENABLE(compile-warnings, 51 | AC_HELP_STRING([--enable-compile-warnings=@<:@no/minimum/yes/maximum/error@:>@], 52 | [Turn on compiler warnings]),, 53 | [enable_compile_warnings="m4_default([$1],[yes])"]) 54 | 55 | warnCFLAGS= 56 | if test "x$GCC" != xyes; then 57 | enable_compile_warnings=no 58 | fi 59 | 60 | warning_flags= 61 | realsave_CFLAGS="$CFLAGS" 62 | 63 | case "$enable_compile_warnings" in 64 | no) 65 | warning_flags= 66 | ;; 67 | minimum) 68 | warning_flags="-Wall" 69 | ;; 70 | yes) 71 | warning_flags="-Wall -Wmissing-prototypes" 72 | ;; 73 | maximum|error) 74 | warning_flags="-Wall -Wmissing-prototypes -Wnested-externs -Wpointer-arith" 75 | CFLAGS="$warning_flags $CFLAGS" 76 | for option in -Wno-sign-compare; do 77 | SAVE_CFLAGS="$CFLAGS" 78 | CFLAGS="$CFLAGS $option" 79 | AC_MSG_CHECKING([whether gcc understands $option]) 80 | AC_TRY_COMPILE([], [], 81 | has_option=yes, 82 | has_option=no,) 83 | CFLAGS="$SAVE_CFLAGS" 84 | AC_MSG_RESULT($has_option) 85 | if test $has_option = yes; then 86 | warning_flags="$warning_flags $option" 87 | fi 88 | unset has_option 89 | unset SAVE_CFLAGS 90 | done 91 | unset option 92 | if test "$enable_compile_warnings" = "error" ; then 93 | warning_flags="$warning_flags -Werror" 94 | fi 95 | ;; 96 | *) 97 | AC_MSG_ERROR(Unknown argument '$enable_compile_warnings' to --enable-compile-warnings) 98 | ;; 99 | esac 100 | CFLAGS="$realsave_CFLAGS" 101 | AC_MSG_CHECKING(what warning flags to pass to the C compiler) 102 | AC_MSG_RESULT($warning_flags) 103 | 104 | AC_ARG_ENABLE(iso-c, 105 | AC_HELP_STRING([--enable-iso-c], 106 | [Try to warn if code is not ISO C ]),, 107 | [enable_iso_c=no]) 108 | 109 | AC_MSG_CHECKING(what language compliance flags to pass to the C compiler) 110 | complCFLAGS= 111 | if test "x$enable_iso_c" != "xno"; then 112 | if test "x$GCC" = "xyes"; then 113 | case " $CFLAGS " in 114 | *[\ \ ]-ansi[\ \ ]*) ;; 115 | *) complCFLAGS="$complCFLAGS -ansi" ;; 116 | esac 117 | case " $CFLAGS " in 118 | *[\ \ ]-pedantic[\ \ ]*) ;; 119 | *) complCFLAGS="$complCFLAGS -pedantic" ;; 120 | esac 121 | fi 122 | fi 123 | AC_MSG_RESULT($complCFLAGS) 124 | 125 | WARN_CFLAGS="$warning_flags $complCFLAGS" 126 | AC_SUBST(WARN_CFLAGS) 127 | ]) 128 | 129 | dnl For C++, do basically the same thing. 130 | 131 | AC_DEFUN([GNOME_CXX_WARNINGS],[ 132 | AC_ARG_ENABLE(cxx-warnings, 133 | AC_HELP_STRING([--enable-cxx-warnings=@<:@no/minimum/yes@:>@] 134 | [Turn on compiler warnings.]),, 135 | [enable_cxx_warnings="m4_default([$1],[minimum])"]) 136 | 137 | AC_MSG_CHECKING(what warning flags to pass to the C++ compiler) 138 | warnCXXFLAGS= 139 | if test "x$GXX" != xyes; then 140 | enable_cxx_warnings=no 141 | fi 142 | if test "x$enable_cxx_warnings" != "xno"; then 143 | if test "x$GXX" = "xyes"; then 144 | case " $CXXFLAGS " in 145 | *[\ \ ]-Wall[\ \ ]*) ;; 146 | *) warnCXXFLAGS="-Wall -Wno-unused" ;; 147 | esac 148 | 149 | ## -W is not all that useful. And it cannot be controlled 150 | ## with individual -Wno-xxx flags, unlike -Wall 151 | if test "x$enable_cxx_warnings" = "xyes"; then 152 | warnCXXFLAGS="$warnCXXFLAGS -Wshadow -Woverloaded-virtual" 153 | fi 154 | fi 155 | fi 156 | AC_MSG_RESULT($warnCXXFLAGS) 157 | 158 | AC_ARG_ENABLE(iso-cxx, 159 | AC_HELP_STRING([--enable-iso-cxx], 160 | [Try to warn if code is not ISO C++ ]),, 161 | [enable_iso_cxx=no]) 162 | 163 | AC_MSG_CHECKING(what language compliance flags to pass to the C++ compiler) 164 | complCXXFLAGS= 165 | if test "x$enable_iso_cxx" != "xno"; then 166 | if test "x$GXX" = "xyes"; then 167 | case " $CXXFLAGS " in 168 | *[\ \ ]-ansi[\ \ ]*) ;; 169 | *) complCXXFLAGS="$complCXXFLAGS -ansi" ;; 170 | esac 171 | 172 | case " $CXXFLAGS " in 173 | *[\ \ ]-pedantic[\ \ ]*) ;; 174 | *) complCXXFLAGS="$complCXXFLAGS -pedantic" ;; 175 | esac 176 | fi 177 | fi 178 | AC_MSG_RESULT($complCXXFLAGS) 179 | 180 | WARN_CXXFLAGS="$CXXFLAGS $warnCXXFLAGS $complCXXFLAGS" 181 | AC_SUBST(WARN_CXXFLAGS) 182 | ]) 183 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | aclocal || exit 1 3 | autoheader || exit 1 4 | glib-gettextize -f -c || exit 1 5 | gtkdocize --copy || exit 1 6 | intltoolize -c -f || exit 1 7 | libtoolize -c || exit 1 8 | autoconf || exit 1 9 | automake -a -c || exit 1 10 | ./configure $* 11 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([fprintd], [0.1]) 2 | AM_INIT_AUTOMAKE 3 | AC_CONFIG_SRCDIR([src/main.c]) 4 | AC_CONFIG_HEADERS([config.h]) 5 | 6 | AC_PREREQ([2.50]) 7 | AC_PROG_LIBTOOL 8 | AC_PROG_CC 9 | AM_PROG_CC_C_O 10 | 11 | GETTEXT_PACKAGE=fprintd 12 | AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, ["$GETTEXT_PACKAGE"], [Define to the Gettext package name]) 13 | AC_SUBST(GETTEXT_PACKAGE) 14 | AM_GLIB_GNU_GETTEXT 15 | IT_PROG_INTLTOOL([0.35.0]) 16 | 17 | PKG_CHECK_MODULES(FPRINT, [libfprint > 0.1.0]) 18 | AC_SUBST(FPRINT_LIBS) 19 | AC_SUBST(FPRINT_CFLAGS) 20 | 21 | PKG_CHECK_MODULES(GLIB, glib-2.0 dbus-glib-1) 22 | AC_SUBST(GLIB_CFLAGS) 23 | AC_SUBST(GLIB_LIBS) 24 | 25 | PKG_CHECK_MODULES(DAEMON, glib-2.0 dbus-glib-1 gmodule-2.0 polkit >= 0.8 polkit-dbus) 26 | AC_SUBST(DAEMON_LIBS) 27 | AC_SUBST(DAEMON_CFLAGS) 28 | 29 | AC_ARG_ENABLE(pam, AC_HELP_STRING([--enable-pam],[Build the fprintd PAM module]), enable_pam="$enableval", enable_pam=yes) 30 | has_pam=no 31 | if test x$enable_pam = xyes; then 32 | has_pam=yes 33 | AC_CHECK_HEADER([security/pam_modules.h], [has_pam=yes] , [has_pam=no]) 34 | if test x$has_pam = xyes; then 35 | has_pam=no 36 | AC_CHECK_LIB(pam, pam_start, [PAM_LIBS="-lpam" 37 | has_pam=yes], 38 | has_pam=no) 39 | fi 40 | AC_SUBST(PAM_LIBS) 41 | fi 42 | AM_CONDITIONAL(HAVE_PAM, test "x$has_pam" = "xyes") 43 | 44 | AC_MSG_CHECKING(for PAM headers and library) 45 | AC_MSG_RESULT([$has_pam]) 46 | 47 | 48 | AC_CHECK_PROG([POLKIT_POLICY_FILE_VALIDATE], 49 | [polkit-policy-file-validate], [polkit-policy-file-validate]) 50 | 51 | AC_PATH_PROG([XSLTPROC], [xsltproc]) 52 | GTK_DOC_CHECK([1.3]) 53 | 54 | AS_AC_EXPAND(DATADIR, $datadir) 55 | 56 | DBUS_SERVICES_DIR="$DATADIR/dbus-1/services" 57 | AC_SUBST(DBUS_SERVICES_DIR) 58 | AC_DEFINE_UNQUOTED(DBUS_SERVICES_DIR, "$DBUS_SERVICES_DIR", [Where services dir for DBUS is]) 59 | 60 | AC_DEFINE_UNQUOTED(SYSCONFDIR, "$sysconfdir", [Where the configuration file will be located]) 61 | 62 | GNOME_COMPILE_WARNINGS 63 | 64 | AC_OUTPUT([ 65 | Makefile 66 | src/Makefile 67 | data/Makefile 68 | tests/Makefile 69 | pam/Makefile 70 | doc/Makefile 71 | doc/version.xml 72 | doc/dbus/Makefile 73 | po/Makefile.in 74 | ]) 75 | -------------------------------------------------------------------------------- /data/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | dbus_servicesdir = $(datadir)/dbus-1/system-services 3 | dbus_services_in_files = net.reactivated.Fprint.service.in 4 | dbus_services_DATA = $(dbus_services_in_files:.service.in=.service) 5 | 6 | $(dbus_services_DATA): $(dbus_services_in_files) 7 | sed -e "s|\@LIBEXECDIR\@|$(libexecdir)|" $< > $@ 8 | 9 | dbus_confdir = $(sysconfdir)/dbus-1/system.d 10 | dbus_conf_DATA = net.reactivated.Fprint.conf 11 | 12 | polkitdir = $(datadir)/PolicyKit/policy 13 | polkit_in_files = net.reactivated.fprint.device.policy.in 14 | 15 | @INTLTOOL_POLICY_RULE@ 16 | polkit_DATA = $(polkit_in_files:.policy.in=.policy) 17 | 18 | confdir = $(sysconfdir)/ 19 | conf_DATA = fprintd.conf 20 | 21 | EXTRA_DIST = $(dbus_services_in_files) $(dbus_conf_DATA) $(polkit_in_files) $(conf_DATA) 22 | CLEANFILES = $(polkit_DATA) $(dbus_services_DATA) 23 | 24 | check: 25 | $(POLKIT_POLICY_FILE_VALIDATE) $(polkit_DATA) 26 | 27 | 28 | -------------------------------------------------------------------------------- /data/fprintd.conf: -------------------------------------------------------------------------------- 1 | [storage] 2 | type=file 3 | -------------------------------------------------------------------------------- /data/net.reactivated.Fprint.conf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /data/net.reactivated.Fprint.service.in: -------------------------------------------------------------------------------- 1 | [D-BUS Service] 2 | Name=net.reactivated.Fprint 3 | Exec=@LIBEXECDIR@/fprintd 4 | User=root 5 | -------------------------------------------------------------------------------- /data/net.reactivated.fprint.device.policy.in: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | The FPrint Project 9 | http://reactivated.net/fprint/ 10 | fprint 11 | 12 | 13 | <_description>Verify a fingerprint 14 | <_message>Privileges are required to verify fingerprints. 15 | 16 | no 17 | no 18 | yes 19 | 20 | 21 | 22 | 23 | <_description>Enroll new fingerprints 24 | <_message>Privileges are required to enroll new fingerprints. 25 | 26 | no 27 | no 28 | yes 29 | 30 | 31 | 32 | 33 | <_description>Select a user to enroll 34 | <_message>Privileges are required to enroll new fingerprints for other users. 35 | 36 | no 37 | no 38 | auth_admin_keep_always 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | SUBDIRS = dbus 3 | 4 | NULL = 5 | 6 | AUTOMAKE_OPTIONS = 1.7 7 | 8 | # The name of the module. 9 | DOC_MODULE=fprintd 10 | 11 | # The top-level SGML file. 12 | DOC_MAIN_SGML_FILE=fprintd-docs.xml 13 | 14 | # Extra options to supply to gtkdoc-scan 15 | SCAN_OPTIONS=--ignore-headers=config.h 16 | 17 | # The directory containing the source code. Relative to $(srcdir) 18 | DOC_SOURCE_DIR=../src 19 | 20 | # Used for dependencies 21 | HFILE_GLOB= 22 | #$(top_srcdir)/policy/*.h 23 | CFILE_GLOB= 24 | #$(top_srcdir)/policy/*.c 25 | 26 | # Headers to ignore 27 | IGNORE_HFILES= \ 28 | $(NULL) 29 | 30 | # CFLAGS and LDFLAGS for compiling scan program. Only needed 31 | # if $(DOC_MODULE).types is non-empty. 32 | INCLUDES = \ 33 | $(GLIB_CFLAGS) \ 34 | -I$(top_srcdir)/src \ 35 | $(NULL) 36 | 37 | GTKDOC_LIBS = \ 38 | $(GLIB_LIBS) \ 39 | $(top_builddir)/src/libfprintd.la \ 40 | $(NULL) 41 | 42 | # Extra options to supply to gtkdoc-mkdb 43 | MKDB_OPTIONS=--sgml-mode --output-format=xml 44 | 45 | # Extra options to supply to gtkdoc-mktmpl 46 | MKTMPL_OPTIONS= 47 | 48 | # Non-autogenerated SGML files to be included in $(DOC_MAIN_SGML_FILE) 49 | content_files = \ 50 | version.xml \ 51 | dbus/net.reactivated.Fprint.Manager.ref.xml \ 52 | dbus/net.reactivated.Fprint.Device.ref.xml \ 53 | $(NULL) 54 | 55 | # Images to copy into HTML directory 56 | HTML_IMAGES = \ 57 | $(NULL) 58 | 59 | # Extra options to supply to gtkdoc-fixref 60 | FIXXREF_OPTIONS= 61 | 62 | MAINTAINERCLEANFILES = \ 63 | *~ \ 64 | Makefile.in \ 65 | fprintd.types \ 66 | fprintd-*.txt \ 67 | $(NULL) 68 | 69 | if ENABLE_GTK_DOC 70 | include $(top_srcdir)/gtk-doc.make 71 | else 72 | EXTRA_DIST = fprintd-docs.xml 73 | endif 74 | 75 | # Version information for marking the documentation 76 | EXTRA_DIST += version.xml.in 77 | 78 | -------------------------------------------------------------------------------- /doc/dbus/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | all : net.reactivated.Fprint.Manager.ref.xml net.reactivated.Fprint.Device.ref.xml 3 | 4 | net.reactivated.Fprint.Manager.ref.xml : $(top_srcdir)/src/manager.xml $(top_srcdir)/doc/dbus/spec-to-docbook.xsl 5 | echo """" > $@ 6 | $(XSLTPROC) $(top_srcdir)/doc/dbus/spec-to-docbook.xsl $< | tail -n +2 >> $@ 7 | 8 | net.reactivated.Fprint.Device.ref.xml : $(top_srcdir)/src/device.xml $(top_srcdir)/doc/dbus/spec-to-docbook.xsl 9 | echo """" > $@ 10 | $(XSLTPROC) $(top_srcdir)/doc/dbus/spec-to-docbook.xsl $< | tail -n +2 >> $@ 11 | 12 | EXTRA_DIST = spec-to-docbook.xsl dbus-introspect-docs.dtd 13 | 14 | clean-local : 15 | rm -f *~ *.ref.xml 16 | -------------------------------------------------------------------------------- /doc/dbus/dbus-introspect-docs.dtd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /doc/dbus/spec-to-docbook.xsl: -------------------------------------------------------------------------------- 1 | 2 | 5 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | interface 29 | 30 | 31 | 32 | Methods 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | Signals 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | Implemented Interfaces 55 | 56 | Objects implementing also implements 57 | org.freedesktop.DBus.Introspectable, 58 | org.freedesktop.DBus.Properties 59 | 60 | 61 | 62 | 63 | 64 | 65 | Properties 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | Description 77 | 78 | 79 | 80 | 81 | 82 | 83 | Details 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | Signal Details 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | Property Details 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | : 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | <anchor role="function"><xsl:attribute name="id"><xsl:value-of select="$basename"/>:<xsl:value-of select="@name"/></xsl:attribute></anchor>The "<xsl:value-of select="@name"/>" property 143 | 144 | '' 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | : 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | <anchor role="function"><xsl:attribute name="id"><xsl:value-of select="$basename"/>::<xsl:value-of select="@name"/></xsl:attribute></anchor>The <xsl:value-of select="@name"/> signal 180 | 181 | () 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | : 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | <anchor role="description"><xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute></anchor><xsl:value-of select="."/> 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | Since 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | /> 289 | 290 | 291 | 292 | 293 | 294 | 295 | is deprecated since version and should not be used in newly-written code. Use 296 | 297 | 298 | 299 | 300 | : 301 | 302 | 303 | :: 304 | 305 | 306 | . 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | instead. 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | See also: 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | : 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | Errors 396 | 397 | 398 | 399 | : 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | Permissions 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | <anchor role="function"><xsl:attribute name="id"><xsl:value-of select="$basename"/>.<xsl:value-of select="@name"/></xsl:attribute></anchor><xsl:value-of select="@name"/> () 430 | 431 | () 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | :'' 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | ::() 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | .() 475 | 476 | 477 | 478 | 479 | 480 | '' 481 | , 482 | 483 | 484 | 485 | 486 | 487 | '' 488 | , 489 | 490 | 491 | 492 | 493 | 494 | 495 | '' 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | -------------------------------------------------------------------------------- /doc/fprintd-docs.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | ]> 6 | 7 | 8 | fprintd Reference Manual 9 | Version &version; 10 | 11 | 12 | Bastien 13 | Nocera 14 | 15 |
16 | hadess@hadess.net 17 |
18 |
19 |
20 |
21 | 22 | 23 | 2008 24 | The fprintd Authors 25 | 26 | 27 | 28 | 29 | Permission is granted to copy, distribute and/or modify this 30 | document under the terms of the GNU Free 31 | Documentation License, Version 1.1 or any later 32 | version published by the Free Software Foundation with no 33 | Invariant Sections, no Front-Cover Texts, and no Back-Cover 34 | Texts. You may obtain a copy of the GNU Free 35 | Documentation License from the Free Software 36 | Foundation by visiting their Web site or by writing 38 | to: 39 | 40 |
41 | The Free Software Foundation, Inc., 42 | 59 Temple Place - Suite 330, 43 | Boston, MA 02111-1307, 44 | USA 45 |
46 |
47 | 48 | 49 | Many of the names used by companies to distinguish their 50 | products and services are claimed as trademarks. Where those 51 | names appear in any GNOME documentation, and those trademarks 52 | are made aware to the members of the GNOME Documentation 53 | Project, the names have been printed in caps or initial caps. 54 | 55 |
56 |
57 | 58 | 59 | D-Bus API Reference 60 | 61 | 62 | This part documents the D-Bus interface used to access the 63 | fprintd daemon. 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | Index 72 | 73 | 74 | 75 | 76 | 77 | License 78 | 79 | FIXME: MISSING XINCLUDE CONTENT 80 | 81 | 82 |
83 | -------------------------------------------------------------------------------- /doc/version.xml.in: -------------------------------------------------------------------------------- 1 | @VERSION@ 2 | -------------------------------------------------------------------------------- /pam/Makefile.am: -------------------------------------------------------------------------------- 1 | if HAVE_PAM 2 | 3 | pammod_PROGRAMS = pam_fprintd.so 4 | pammoddir=$(libdir)/security 5 | 6 | pam_fprintd_so_SOURCES = pam_fprintd.c $(MARSHALFILES) 7 | pam_fprintd_so_CFLAGS = -fPIC $(WARN_CFLAGS) $(GLIB_CFLAGS) 8 | pam_fprintd_so_LDFLAGS = -shared 9 | pam_fprintd_so_LDADD = $(PAM_LIBS) $(GLIB_LIBS) 10 | 11 | MARSHALFILES = marshal.c marshal.h 12 | GLIB_GENMARSHAL=`pkg-config --variable=glib_genmarshal glib-2.0` 13 | BUILT_SOURCES = $(MARSHALFILES) 14 | 15 | marshal.h: $(top_srcdir)/src/fprintd-marshal.list 16 | ( $(GLIB_GENMARSHAL) --prefix=fprintd_marshal $(top_srcdir)/src/fprintd-marshal.list --header > marshal.h ) 17 | marshal.c: marshal.h 18 | ( $(GLIB_GENMARSHAL) --prefix=fprintd_marshal $(top_srcdir)/src/fprintd-marshal.list --body --header > marshal.c ) 19 | 20 | endif 21 | 22 | EXTRA_DIST = pam_fprintd.c fingerprint-strings.h 23 | -------------------------------------------------------------------------------- /pam/README: -------------------------------------------------------------------------------- 1 | PAM module for fingerprint authentication 2 | ----------------------------------------- 3 | 4 | Using: 5 | * Modify the appropriate PAM configuration file 6 | (/etc/pam.d/system-auth-ac on Fedora systems), and add the line: 7 | auth sufficient pam_fprintd.so 8 | before the line: 9 | auth sufficient pam_unix.so ... 10 | * You can now enroll fingerprints using fprintd-enroll. The first available 11 | fingerprint available will be used to log you in. 12 | 13 | Options: 14 | * You can add the "debug" option on the pam configuration file line above, 15 | this will log more information from PAM to the file specified in your 16 | syslog configuration (/var/log/secure by default on Fedora) 17 | 18 | Known issues: 19 | * pam_fprintd does not support identifying the user itself as 20 | that would mean having the fingerprint reader on for all the time 21 | the user selection is displayed, and could damage the hardware. 22 | It could be fixed by having gdm/login only start the PAM conversation 23 | when there is activity 24 | * pam_fprintd doesn't support entering either the password or a fingerprint, 25 | as pam_thinkfinger does, because it's a gross hack, and could be fixed 26 | by having the login managers run 2 separate PAM stacks 27 | -------------------------------------------------------------------------------- /pam/fingerprint-strings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Helper functions to translate statuses and actions to strings 3 | * Copyright (C) 2008 Bastien Nocera 4 | * 5 | * Experimental code. This will be moved out of fprintd into it's own 6 | * package once the system has matured. 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License along 19 | * with this program; if not, write to the Free Software Foundation, Inc., 20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | struct { 24 | const char *dbus_name; 25 | const char *place_str; 26 | const char *swipe_str; 27 | } fingers[11] = { 28 | { "left-thumb", N_("Place your left thumb on %s"), N_("Swipe your left thumb on %s") }, 29 | { "left-index-finger", N_("Place your left index finger on %s"), N_("Swipe your left index finger on %s") }, 30 | { "left-middle-finger", N_("Place your left middle finger on %s"), N_("Swipe your left middle finger on %s") }, 31 | { "left-ring-finger", N_("Place your left ring finger on %s"), N_("Swipe your left ring finger on %s") }, 32 | { "left-little-finger", N_("Place your left little finger on %s"), N_("Swipe your left little finger on %s") }, 33 | { "right-thumb", N_("Place your right thumb on %s"), N_("Swipe your right thumb on %s") }, 34 | { "right-index-finger", N_("Place your right index finger on %s"), N_("Swipe your right index finger on %s") }, 35 | { "right-middle-finger", N_("Place your right middle finger on %s"), N_("Swipe your right middle finger on %s") }, 36 | { "right-ring-finger", N_("Place your right ring finger on %s"), N_("Swipe your right ring finger on %s") }, 37 | { "right-little-finger", N_("Place your right little finger on %s"), N_("Swipe your right little finger on %s") }, 38 | { NULL, NULL, NULL } 39 | }; 40 | 41 | static const char *finger_str_to_msg(const char *finger_name, gboolean is_swipe) 42 | { 43 | int i; 44 | 45 | if (finger_name == NULL) 46 | return NULL; 47 | 48 | for (i = 0; fingers[i].dbus_name != NULL; i++) { 49 | if (g_str_equal (fingers[i].dbus_name, finger_name)) { 50 | if (is_swipe == FALSE) 51 | return fingers[i].place_str; 52 | else 53 | return fingers[i].swipe_str; 54 | } 55 | } 56 | 57 | return NULL; 58 | } 59 | 60 | /* Cases not handled: 61 | * verify-no-match 62 | * verify-match 63 | * verify-unknown-error 64 | */ 65 | static const char *verify_result_str_to_msg(const char *result, gboolean is_swipe) 66 | { 67 | if (result == NULL) 68 | return NULL; 69 | 70 | if (strcmp (result, "verify-retry-scan") == 0) { 71 | if (is_swipe == FALSE) 72 | return N_("Place your finger on the reader again"); 73 | else 74 | return N_("Swipe your finger again"); 75 | } 76 | if (strcmp (result, "verify-swipe-too-short") == 0) 77 | return N_("Swipe was too short, try again"); 78 | if (strcmp (result, "verify-finger-not-centered") == 0) 79 | return N_("Your finger was not centered, try swiping your finger again"); 80 | if (strcmp (result, "verify-remove-and-retry") == 0) 81 | return N_("Remove your finger, and try swiping your finger again"); 82 | 83 | return NULL; 84 | } 85 | 86 | /* Cases not handled: 87 | * enroll-completed 88 | * enroll-failed 89 | * enroll-unknown-error 90 | */ 91 | static const char *enroll_result_str_to_msg(const char *result, gboolean is_swipe) 92 | { 93 | if (result == NULL) 94 | return NULL; 95 | 96 | if (strcmp (result, "enroll-retry-scan") == 0 || strcmp (result, "enroll-stage-passed") == 0) { 97 | if (is_swipe == FALSE) 98 | return N_("Place your finger on the reader again"); 99 | else 100 | return N_("Swipe your finger again"); 101 | } 102 | if (strcmp (result, "enroll-swipe-too-short") == 0) 103 | return N_("Swipe was too short, try again"); 104 | if (strcmp (result, "enroll-finger-not-centered") == 0) 105 | return N_("Your finger was not centered, try swiping your finger again"); 106 | if (strcmp (result, "enroll-remove-and-retry") == 0) 107 | return N_("Remove your finger, and try swiping your finger again"); 108 | 109 | return NULL; 110 | } 111 | 112 | -------------------------------------------------------------------------------- /pam/pam_fprintd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pam_fprint: PAM module for fingerprint authentication through fprintd 3 | * Copyright (C) 2007 Daniel Drake 4 | * Copyright (C) 2008 Bastien Nocera 5 | * 6 | * Experimental code. This will be moved out of fprintd into it's own 7 | * package once the system has matured. 8 | * 9 | * This program is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License along 20 | * with this program; if not, write to the Free Software Foundation, Inc., 21 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | 33 | #define PAM_SM_AUTH 34 | #include 35 | 36 | #include "marshal.h" 37 | 38 | #define N_(x) x 39 | #include "fingerprint-strings.h" 40 | 41 | #define MAX_TRIES 3 42 | #define TIMEOUT 30 43 | 44 | #define D(pamh, ...) { \ 45 | if (debug) { \ 46 | char *s; \ 47 | s = g_strdup_printf (__VA_ARGS__); \ 48 | send_debug_msg (pamh, s); \ 49 | g_free (s); \ 50 | } \ 51 | } 52 | 53 | 54 | static gboolean debug = FALSE; 55 | 56 | static gboolean send_info_msg(pam_handle_t *pamh, const char *msg) 57 | { 58 | const struct pam_message mymsg = { 59 | .msg_style = PAM_TEXT_INFO, 60 | .msg = msg, 61 | }; 62 | const struct pam_message *msgp = &mymsg; 63 | const struct pam_conv *pc; 64 | struct pam_response *resp; 65 | int r; 66 | 67 | r = pam_get_item(pamh, PAM_CONV, (const void **) &pc); 68 | if (r != PAM_SUCCESS) 69 | return FALSE; 70 | 71 | if (!pc || !pc->conv) 72 | return FALSE; 73 | 74 | return (pc->conv(1, &msgp, &resp, pc->appdata_ptr) == PAM_SUCCESS); 75 | } 76 | 77 | static gboolean send_err_msg(pam_handle_t *pamh, const char *msg) 78 | { 79 | const struct pam_message mymsg = { 80 | .msg_style = PAM_ERROR_MSG, 81 | .msg = msg, 82 | }; 83 | const struct pam_message *msgp = &mymsg; 84 | const struct pam_conv *pc; 85 | struct pam_response *resp; 86 | int r; 87 | 88 | r = pam_get_item(pamh, PAM_CONV, (const void **) &pc); 89 | if (r != PAM_SUCCESS) 90 | return FALSE; 91 | 92 | if (!pc || !pc->conv) 93 | return FALSE; 94 | 95 | return (pc->conv(1, &msgp, &resp, pc->appdata_ptr) == PAM_SUCCESS); 96 | } 97 | 98 | static void send_debug_msg(pam_handle_t *pamh, const char *msg) 99 | { 100 | gconstpointer item; 101 | const char *service; 102 | 103 | if (pam_get_item(pamh, PAM_SERVICE, &item) != PAM_SUCCESS || !item) 104 | service = ""; 105 | else 106 | service = item; 107 | 108 | openlog (service, LOG_CONS | LOG_PID, LOG_AUTHPRIV); 109 | 110 | syslog (LOG_AUTHPRIV|LOG_WARNING, "%s(%s): %s", "pam_fprintd", service, msg); 111 | 112 | closelog (); 113 | 114 | } 115 | 116 | static DBusGProxy *create_manager (pam_handle_t *pamh, DBusGConnection **ret_conn, GMainLoop **ret_loop) 117 | { 118 | DBusGConnection *connection; 119 | DBusConnection *conn; 120 | DBusGProxy *manager; 121 | DBusError error; 122 | GMainLoop *loop; 123 | GMainContext *ctx; 124 | 125 | /* Otherwise dbus-glib doesn't setup it value types */ 126 | connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL); 127 | 128 | if (connection != NULL) 129 | dbus_g_connection_unref (connection); 130 | 131 | /* And set us up a private D-Bus connection */ 132 | dbus_error_init (&error); 133 | conn = dbus_bus_get_private (DBUS_BUS_SYSTEM, &error); 134 | if (conn == NULL) { 135 | D(pamh, "Error with getting the bus: %s", error.message); 136 | dbus_error_free (&error); 137 | return NULL; 138 | } 139 | 140 | /* Set up our own main loop context */ 141 | ctx = g_main_context_new (); 142 | loop = g_main_loop_new (ctx, FALSE); 143 | dbus_connection_setup_with_g_main (conn, ctx); 144 | 145 | connection = dbus_connection_get_g_connection (conn); 146 | 147 | manager = dbus_g_proxy_new_for_name(connection, 148 | "net.reactivated.Fprint", 149 | "/net/reactivated/Fprint/Manager", 150 | "net.reactivated.Fprint.Manager"); 151 | *ret_conn = connection; 152 | *ret_loop = loop; 153 | 154 | return manager; 155 | } 156 | 157 | static void close_and_unref (DBusGConnection *connection) 158 | { 159 | DBusConnection *conn; 160 | 161 | conn = dbus_g_connection_get_connection (connection); 162 | dbus_connection_close (conn); 163 | dbus_g_connection_unref (connection); 164 | } 165 | 166 | static DBusGProxy *open_device(pam_handle_t *pamh, DBusGConnection *connection, DBusGProxy *manager, const char *username) 167 | { 168 | GError *error = NULL; 169 | gchar *path; 170 | DBusGProxy *dev; 171 | 172 | if (!dbus_g_proxy_call (manager, "GetDefaultDevice", &error, 173 | G_TYPE_INVALID, DBUS_TYPE_G_OBJECT_PATH, 174 | &path, G_TYPE_INVALID)) { 175 | D(pamh, "get_default_devices failed: %s", error->message); 176 | g_error_free (error); 177 | return NULL; 178 | } 179 | 180 | if (path == NULL) { 181 | D(pamh, "No devices found\n"); 182 | return NULL; 183 | } 184 | 185 | D(pamh, "Using device %s\n", path); 186 | 187 | dev = dbus_g_proxy_new_for_name(connection, 188 | "net.reactivated.Fprint", 189 | path, 190 | "net.reactivated.Fprint.Device"); 191 | 192 | g_free (path); 193 | 194 | if (!dbus_g_proxy_call (dev, "Claim", &error, G_TYPE_STRING, username, G_TYPE_INVALID, G_TYPE_INVALID)) { 195 | D(pamh, "failed to claim device: %s\n", error->message); 196 | g_error_free (error); 197 | g_object_unref (dev); 198 | return NULL; 199 | } 200 | return dev; 201 | } 202 | 203 | typedef struct { 204 | guint max_tries; 205 | char *result; 206 | gboolean timed_out; 207 | gboolean is_swipe; 208 | pam_handle_t *pamh; 209 | GMainLoop *loop; 210 | 211 | char *driver; 212 | } verify_data; 213 | 214 | static void verify_result(GObject *object, const char *result, gboolean done, gpointer user_data) 215 | { 216 | verify_data *data = user_data; 217 | const char *msg; 218 | 219 | D(data->pamh, "Verify result: %s\n", result); 220 | if (done != FALSE) { 221 | data->result = g_strdup (result); 222 | g_main_loop_quit (data->loop); 223 | return; 224 | } 225 | 226 | msg = verify_result_str_to_msg (result, data->is_swipe); 227 | send_err_msg (data->pamh, msg); 228 | } 229 | 230 | static void verify_finger_selected(GObject *object, const char *finger_name, gpointer user_data) 231 | { 232 | verify_data *data = user_data; 233 | char *msg; 234 | 235 | if (g_str_equal (finger_name, "any")) { 236 | if (data->is_swipe == FALSE) 237 | msg = g_strdup_printf ("Place your finger on %s", data->driver); 238 | else 239 | msg = g_strdup_printf ("Swipe your finger on %s", data->driver); 240 | } else { 241 | msg = g_strdup_printf (finger_str_to_msg(finger_name, data->is_swipe), data->driver); 242 | } 243 | D(data->pamh, "verify_finger_selected %s", msg); 244 | send_info_msg (data->pamh, msg); 245 | g_free (msg); 246 | } 247 | 248 | static gboolean verify_timeout_cb (gpointer user_data) 249 | { 250 | verify_data *data = user_data; 251 | 252 | data->timed_out = TRUE; 253 | send_info_msg (data->pamh, "Verification timed out"); 254 | g_main_loop_quit (data->loop); 255 | 256 | return FALSE; 257 | } 258 | 259 | static int do_verify(GMainLoop *loop, pam_handle_t *pamh, DBusGProxy *dev) 260 | { 261 | GError *error = NULL; 262 | GHashTable *props; 263 | DBusGProxy *p; 264 | verify_data *data; 265 | int ret; 266 | 267 | data = g_new0 (verify_data, 1); 268 | data->max_tries = MAX_TRIES; 269 | data->pamh = pamh; 270 | data->loop = loop; 271 | 272 | /* Get some properties for the device */ 273 | p = dbus_g_proxy_new_from_proxy (dev, "org.freedesktop.DBus.Properties", NULL); 274 | 275 | if (dbus_g_proxy_call (p, "GetAll", NULL, G_TYPE_STRING, "net.reactivated.Fprint.Device", G_TYPE_INVALID, 276 | dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), &props, G_TYPE_INVALID)) { 277 | const char *scan_type; 278 | data->driver = g_value_dup_string (g_hash_table_lookup (props, "name")); 279 | scan_type = g_value_dup_string (g_hash_table_lookup (props, "scan-type")); 280 | if (g_str_equal (scan_type, "swipe")) 281 | data->is_swipe = TRUE; 282 | g_hash_table_destroy (props); 283 | } 284 | 285 | g_object_unref (p); 286 | 287 | if (!data->driver) 288 | data->driver = g_strdup ("Fingerprint reader"); 289 | 290 | dbus_g_proxy_add_signal(dev, "VerifyStatus", G_TYPE_STRING, G_TYPE_BOOLEAN, NULL); 291 | dbus_g_proxy_add_signal(dev, "VerifyFingerSelected", G_TYPE_STRING, NULL); 292 | dbus_g_proxy_connect_signal(dev, "VerifyStatus", G_CALLBACK(verify_result), 293 | data, NULL); 294 | dbus_g_proxy_connect_signal(dev, "VerifyFingerSelected", G_CALLBACK(verify_finger_selected), 295 | data, NULL); 296 | 297 | ret = PAM_AUTH_ERR; 298 | 299 | while (ret == PAM_AUTH_ERR && data->max_tries > 0) { 300 | GSource *source; 301 | guint timeout_id; 302 | 303 | /* Set up the timeout on our non-default context */ 304 | source = g_timeout_source_new_seconds (TIMEOUT); 305 | timeout_id = g_source_attach (source, g_main_loop_get_context (loop)); 306 | g_source_set_callback (source, verify_timeout_cb, data, NULL); 307 | 308 | data->timed_out = FALSE; 309 | 310 | if (!dbus_g_proxy_call (dev, "VerifyStart", &error, G_TYPE_STRING, "any", G_TYPE_INVALID, G_TYPE_INVALID)) { 311 | D(pamh, "VerifyStart failed: %s", error->message); 312 | g_error_free (error); 313 | 314 | g_source_remove (timeout_id); 315 | g_source_unref (source); 316 | break; 317 | } 318 | 319 | g_main_loop_run (loop); 320 | 321 | g_source_remove (timeout_id); 322 | g_source_unref (source); 323 | 324 | /* Ignore errors from VerifyStop */ 325 | dbus_g_proxy_call (dev, "VerifyStop", NULL, G_TYPE_INVALID, G_TYPE_INVALID); 326 | 327 | if (data->timed_out) { 328 | ret = PAM_AUTHINFO_UNAVAIL; 329 | break; 330 | } else { 331 | if (g_str_equal (data->result, "verify-no-match")) { 332 | send_err_msg (data->pamh, "Failed to match fingerprint"); 333 | ret = PAM_AUTH_ERR; 334 | } else if (g_str_equal (data->result, "verify-match")) 335 | ret = PAM_SUCCESS; 336 | else if (g_str_equal (data->result, "verify-unknown-error")) 337 | ret = PAM_AUTHINFO_UNAVAIL; 338 | else if (g_str_equal (data->result, "verify-disconnected")) { 339 | ret = PAM_AUTHINFO_UNAVAIL; 340 | g_free (data->result); 341 | break; 342 | } else { 343 | send_info_msg (data->pamh, "An unknown error occured"); 344 | ret = PAM_AUTH_ERR; 345 | g_free (data->result); 346 | break; 347 | } 348 | g_free (data->result); 349 | data->result = NULL; 350 | } 351 | data->max_tries--; 352 | } 353 | 354 | dbus_g_proxy_disconnect_signal(dev, "VerifyStatus", G_CALLBACK(verify_result), data); 355 | dbus_g_proxy_disconnect_signal(dev, "VerifyFingerSelected", G_CALLBACK(verify_finger_selected), data); 356 | 357 | g_free (data->driver); 358 | g_free (data); 359 | 360 | return ret; 361 | } 362 | 363 | static void release_device(pam_handle_t *pamh, DBusGProxy *dev) 364 | { 365 | GError *error = NULL; 366 | if (!dbus_g_proxy_call (dev, "Release", &error, G_TYPE_INVALID, G_TYPE_INVALID)) { 367 | D(pamh, "ReleaseDevice failed: %s\n", error->message); 368 | g_error_free (error); 369 | } 370 | } 371 | 372 | static int do_auth(pam_handle_t *pamh, const char *username) 373 | { 374 | DBusGProxy *manager; 375 | DBusGConnection *connection; 376 | DBusGProxy *dev; 377 | GMainLoop *loop; 378 | int ret; 379 | 380 | manager = create_manager (pamh, &connection, &loop); 381 | if (manager == NULL) 382 | return PAM_AUTHINFO_UNAVAIL; 383 | 384 | dev = open_device(pamh, connection, manager, username); 385 | g_object_unref (manager); 386 | if (!dev) { 387 | g_main_loop_unref (loop); 388 | close_and_unref (connection); 389 | return PAM_AUTHINFO_UNAVAIL; 390 | } 391 | ret = do_verify(loop, pamh, dev); 392 | 393 | g_main_loop_unref (loop); 394 | release_device(pamh, dev); 395 | g_object_unref (dev); 396 | close_and_unref (connection); 397 | 398 | return ret; 399 | } 400 | 401 | PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, 402 | const char **argv) 403 | { 404 | const char *rhost = NULL; 405 | const char *username; 406 | guint i; 407 | int r; 408 | 409 | g_type_init (); 410 | 411 | dbus_g_object_register_marshaller (fprintd_marshal_VOID__STRING_BOOLEAN, 412 | G_TYPE_NONE, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_INVALID); 413 | 414 | pam_get_item(pamh, PAM_RHOST, (const void **)(const void*) &rhost); 415 | if (rhost != NULL && strlen(rhost) > 0) { 416 | /* remote login (e.g. over SSH) */ 417 | return PAM_AUTHINFO_UNAVAIL; 418 | } 419 | 420 | r = pam_get_user(pamh, &username, NULL); 421 | if (r != PAM_SUCCESS) 422 | return PAM_AUTHINFO_UNAVAIL; 423 | 424 | for (i = 0; i < argc; i++) { 425 | if (argv[i] != NULL && g_str_equal (argv[i], "debug")) { 426 | g_message ("debug on"); 427 | debug = TRUE; 428 | } 429 | } 430 | 431 | r = do_auth(pamh, username); 432 | 433 | return r; 434 | } 435 | 436 | PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, 437 | const char **argv) 438 | { 439 | return PAM_SUCCESS; 440 | } 441 | 442 | PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, 443 | const char **argv) 444 | { 445 | return PAM_SUCCESS; 446 | } 447 | 448 | -------------------------------------------------------------------------------- /po/POTFILES.in: -------------------------------------------------------------------------------- 1 | data/net.reactivated.fprint.device.policy.in 2 | src/main.c 3 | src/manager.c 4 | src/device.c 5 | pam/fingerprint-strings.h 6 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | BUILT_SOURCES = manager-dbus-glue.h device-dbus-glue.h $(MARSHALFILES) $(interfaces_DATA) 2 | noinst_HEADERS = $(BUILT_SOURCES) 3 | 4 | CLEANFILES = $(BUILT_SOURCES) 5 | EXTRA_DIST = manager.xml device.xml fprintd-marshal.list 6 | 7 | libexec_PROGRAMS = fprintd 8 | noinst_LTLIBRARIES = libfprintd.la 9 | 10 | AM_CFLAGS = $(WARN_CFLAGS) $(FPRINT_CFLAGS) $(DAEMON_CFLAGS) -DLOCALEDIR=\""$(datadir)/locale"\" -DPLUGINDIR=\""$(libdir)/fprintd/modules"\" 11 | 12 | libfprintd_la_SOURCES = \ 13 | manager.c device.c \ 14 | egg-dbus-monitor.c egg-dbus-monitor.h \ 15 | $(MARSHALFILES) \ 16 | fprintd.h 17 | libfprintd_la_LIBADD = $(FPRINT_LIBS) $(DAEMON_LIBS) 18 | libfprintd_la_LDFLAGS = -no-undefined 19 | 20 | fprintd_SOURCES = \ 21 | main.c \ 22 | file_storage.c file_storage.h storage.h 23 | fprintd_LDADD = libfprintd.la 24 | 25 | interfaces_DATA = net.reactivated.Fprint.Manager.xml net.reactivated.Fprint.Device.xml 26 | net.reactivated.Fprint.Manager.xml: manager.xml 27 | cat $< > $@ 28 | net.reactivated.Fprint.Device.xml: device.xml 29 | cat $< > $@ 30 | interfacesdir = $(datadir)/dbus-1/interfaces/ 31 | 32 | manager-dbus-glue.h: manager.xml 33 | dbus-binding-tool --prefix=fprint_manager --mode=glib-server $< --output=$@ 34 | 35 | device-dbus-glue.h: device.xml 36 | dbus-binding-tool --prefix=fprint_device --mode=glib-server $< --output=$@ 37 | 38 | MARSHALFILES = fprintd-marshal.c fprintd-marshal.h 39 | GLIB_GENMARSHAL=`pkg-config --variable=glib_genmarshal glib-2.0` 40 | 41 | fprintd-marshal.h: fprintd-marshal.list 42 | ( $(GLIB_GENMARSHAL) --prefix=fprintd_marshal $(srcdir)/fprintd-marshal.list --header > fprintd-marshal.h ) 43 | fprintd-marshal.c: fprintd-marshal.h 44 | ( $(GLIB_GENMARSHAL) --prefix=fprintd_marshal $(srcdir)/fprintd-marshal.list --body --header > fprintd-marshal.c ) 45 | 46 | -------------------------------------------------------------------------------- /src/device.c: -------------------------------------------------------------------------------- 1 | /* 2 | * /net/reactivated/Fprint/Device/foo object implementation 3 | * Copyright (C) 2008 Daniel Drake 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "config.h" 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #include "fprintd-marshal.h" 34 | #include "fprintd.h" 35 | #include "storage.h" 36 | #include "egg-dbus-monitor.h" 37 | 38 | static char *fingers[] = { 39 | "left-thumb", 40 | "left-index-finger", 41 | "left-middle-finger", 42 | "left-ring-finger", 43 | "left-little-finger", 44 | "right-thumb", 45 | "right-index-finger", 46 | "right-middle-finger", 47 | "right-ring-finger", 48 | "right-little-finger" 49 | }; 50 | 51 | extern DBusGConnection *fprintd_dbus_conn; 52 | 53 | static void fprint_device_claim(FprintDevice *rdev, 54 | const char *username, 55 | DBusGMethodInvocation *context); 56 | static void fprint_device_release(FprintDevice *rdev, 57 | DBusGMethodInvocation *context); 58 | static void fprint_device_verify_start(FprintDevice *rdev, 59 | const char *finger_name, DBusGMethodInvocation *context); 60 | static void fprint_device_verify_stop(FprintDevice *rdev, 61 | DBusGMethodInvocation *context); 62 | static void fprint_device_enroll_start(FprintDevice *rdev, 63 | const char *finger_name, DBusGMethodInvocation *context); 64 | static void fprint_device_enroll_stop(FprintDevice *rdev, 65 | DBusGMethodInvocation *context); 66 | static void fprint_device_list_enrolled_fingers(FprintDevice *rdev, 67 | const char *username, 68 | DBusGMethodInvocation *context); 69 | static void fprint_device_delete_enrolled_fingers(FprintDevice *rdev, 70 | const char *username, 71 | DBusGMethodInvocation *context); 72 | 73 | #include "device-dbus-glue.h" 74 | 75 | typedef enum { 76 | ACTION_NONE = 0, 77 | ACTION_IDENTIFY, 78 | ACTION_VERIFY, 79 | ACTION_ENROLL 80 | } FprintDeviceAction; 81 | 82 | struct session_data { 83 | /* finger being enrolled */ 84 | int enroll_finger; 85 | 86 | /* method invocation for async ClaimDevice() */ 87 | DBusGMethodInvocation *context_claim_device; 88 | 89 | /* method invocation for async ReleaseDevice() */ 90 | DBusGMethodInvocation *context_release_device; 91 | }; 92 | 93 | struct FprintDevicePrivate { 94 | guint32 id; 95 | struct fp_dscv_dev *ddev; 96 | struct fp_dev *dev; 97 | struct session_data *session; 98 | 99 | PolKitContext *pol_ctx; 100 | 101 | /* The current user of the device, if claimed */ 102 | char *sender; 103 | 104 | /* The current user of the device, or if allowed, 105 | * what was passed as a username argument */ 106 | char *username; 107 | 108 | /* type of storage */ 109 | int storage_type; 110 | 111 | /* Hashtable of connected clients */ 112 | GHashTable *clients; 113 | 114 | /* The data passed to fp_async_verify_start or 115 | * fp_async_identify_start */ 116 | struct fp_print_data *verify_data; 117 | struct fp_print_data **identify_data; 118 | 119 | /* whether we're running an identify, or a verify */ 120 | FprintDeviceAction current_action; 121 | /* Whether we should ignore new signals on the device */ 122 | gboolean action_done; 123 | /* Whether the device was disconnected */ 124 | gboolean disconnected; 125 | }; 126 | 127 | typedef struct FprintDevicePrivate FprintDevicePrivate; 128 | 129 | #define DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), FPRINT_TYPE_DEVICE, FprintDevicePrivate)) 130 | 131 | enum fprint_device_properties { 132 | FPRINT_DEVICE_CONSTRUCT_DDEV = 1, 133 | FPRINT_DEVICE_IN_USE, 134 | FPRINT_DEVICE_NAME, 135 | FPRINT_DEVICE_NUM_ENROLL, 136 | FPRINT_DEVICE_SCAN_TYPE 137 | }; 138 | 139 | enum fprint_device_signals { 140 | SIGNAL_VERIFY_STATUS, 141 | SIGNAL_VERIFY_FINGER_SELECTED, 142 | SIGNAL_ENROLL_STATUS, 143 | NUM_SIGNALS, 144 | }; 145 | 146 | static GObjectClass *parent_class = NULL; 147 | static guint32 last_id = ~0; 148 | static guint signals[NUM_SIGNALS] = { 0, }; 149 | 150 | static void fprint_device_finalize(GObject *object) 151 | { 152 | FprintDevice *self = (FprintDevice *) object; 153 | FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(self); 154 | 155 | g_hash_table_destroy (priv->clients); 156 | /* FIXME close and stuff */ 157 | } 158 | 159 | static void fprint_device_set_property(GObject *object, guint property_id, 160 | const GValue *value, GParamSpec *pspec) 161 | { 162 | FprintDevice *self = (FprintDevice *) object; 163 | FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(self); 164 | 165 | switch (property_id) { 166 | case FPRINT_DEVICE_CONSTRUCT_DDEV: 167 | priv->ddev = g_value_get_pointer(value); 168 | break; 169 | default: 170 | G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); 171 | break; 172 | } 173 | } 174 | 175 | static void fprint_device_get_property(GObject *object, guint property_id, 176 | GValue *value, GParamSpec *pspec) 177 | { 178 | FprintDevice *self = (FprintDevice *) object; 179 | FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(self); 180 | 181 | switch (property_id) { 182 | case FPRINT_DEVICE_IN_USE: 183 | g_value_set_boolean(value, g_hash_table_size (priv->clients) != 0); 184 | break; 185 | case FPRINT_DEVICE_NAME: 186 | g_value_set_static_string (value, fp_driver_get_full_name (fp_dscv_dev_get_driver (priv->ddev))); 187 | break; 188 | case FPRINT_DEVICE_NUM_ENROLL: 189 | if (priv->dev) 190 | g_value_set_int (value, fp_dev_get_nr_enroll_stages (priv->dev)); 191 | else 192 | g_value_set_int (value, -1); 193 | break; 194 | case FPRINT_DEVICE_SCAN_TYPE: { 195 | const char *type; 196 | 197 | if (fp_driver_get_scan_type (fp_dscv_dev_get_driver (priv->ddev)) == FP_SCAN_TYPE_PRESS) 198 | type = "press"; 199 | else 200 | type = "swipe"; 201 | 202 | g_value_set_static_string (value, type); 203 | break; 204 | } 205 | default: 206 | G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); 207 | break; 208 | } 209 | } 210 | 211 | static void fprint_device_class_init(FprintDeviceClass *klass) 212 | { 213 | GObjectClass *gobject_class = G_OBJECT_CLASS(klass); 214 | GParamSpec *pspec; 215 | 216 | dbus_g_object_type_install_info(FPRINT_TYPE_DEVICE, 217 | &dbus_glib_fprint_device_object_info); 218 | parent_class = g_type_class_peek_parent(klass); 219 | 220 | gobject_class->finalize = fprint_device_finalize; 221 | gobject_class->set_property = fprint_device_set_property; 222 | gobject_class->get_property = fprint_device_get_property; 223 | g_type_class_add_private(klass, sizeof(FprintDevicePrivate)); 224 | 225 | pspec = g_param_spec_pointer("discovered-dev", "Discovered device", 226 | "Set discovered device construction property", 227 | G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE); 228 | g_object_class_install_property(gobject_class, 229 | FPRINT_DEVICE_CONSTRUCT_DDEV, pspec); 230 | 231 | pspec = g_param_spec_boolean("in-use", "In use", 232 | "Whether the device is currently in use", FALSE, 233 | G_PARAM_READABLE); 234 | g_object_class_install_property(gobject_class, 235 | FPRINT_DEVICE_IN_USE, pspec); 236 | 237 | pspec = g_param_spec_string("name", "Name", 238 | "The product name of the device", NULL, 239 | G_PARAM_READABLE); 240 | g_object_class_install_property(gobject_class, 241 | FPRINT_DEVICE_NAME, pspec); 242 | 243 | pspec = g_param_spec_string("scan-type", "Scan Type", 244 | "The scan type of the device", "press", 245 | G_PARAM_READABLE); 246 | g_object_class_install_property(gobject_class, 247 | FPRINT_DEVICE_SCAN_TYPE, pspec); 248 | 249 | pspec = g_param_spec_int("num-enroll-stages", "Number of enrollments stages", 250 | "Number of enrollment stages for the device.", 251 | -1, G_MAXINT, -1, G_PARAM_READABLE); 252 | g_object_class_install_property(gobject_class, 253 | FPRINT_DEVICE_NUM_ENROLL, pspec); 254 | 255 | signals[SIGNAL_VERIFY_STATUS] = g_signal_new("verify-status", 256 | G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, 257 | fprintd_marshal_VOID__STRING_BOOLEAN, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_BOOLEAN); 258 | signals[SIGNAL_ENROLL_STATUS] = g_signal_new("enroll-status", 259 | G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, 260 | fprintd_marshal_VOID__STRING_BOOLEAN, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_BOOLEAN); 261 | signals[SIGNAL_VERIFY_FINGER_SELECTED] = g_signal_new("verify-finger-selected", 262 | G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, 263 | g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); 264 | } 265 | 266 | static gboolean 267 | pk_io_watch_have_data (GIOChannel *channel, GIOCondition condition, gpointer user_data) 268 | { 269 | int fd; 270 | PolKitContext *pk_context = user_data; 271 | fd = g_io_channel_unix_get_fd (channel); 272 | polkit_context_io_func (pk_context, fd); 273 | return TRUE; 274 | } 275 | 276 | static int 277 | pk_io_add_watch (PolKitContext *pk_context, int fd) 278 | { 279 | guint id = 0; 280 | GIOChannel *channel; 281 | channel = g_io_channel_unix_new (fd); 282 | if (channel == NULL) 283 | goto out; 284 | id = g_io_add_watch (channel, G_IO_IN, pk_io_watch_have_data, pk_context); 285 | if (id == 0) { 286 | g_io_channel_unref (channel); 287 | goto out; 288 | } 289 | g_io_channel_unref (channel); 290 | out: 291 | return id; 292 | } 293 | 294 | static void 295 | pk_io_remove_watch (PolKitContext *pk_context, int watch_id) 296 | { 297 | g_source_remove (watch_id); 298 | } 299 | 300 | static void fprint_device_init(FprintDevice *device) 301 | { 302 | FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(device); 303 | priv->id = ++last_id; 304 | 305 | /* Setup PolicyKit */ 306 | priv->pol_ctx = polkit_context_new (); 307 | polkit_context_set_io_watch_functions (priv->pol_ctx, pk_io_add_watch, pk_io_remove_watch); 308 | if (!polkit_context_init (priv->pol_ctx, NULL)) { 309 | g_critical ("cannot initialize libpolkit"); 310 | polkit_context_unref (priv->pol_ctx); 311 | priv->pol_ctx = NULL; 312 | } 313 | priv->clients = g_hash_table_new_full (g_str_hash, 314 | g_str_equal, 315 | g_free, 316 | g_object_unref); 317 | } 318 | 319 | G_DEFINE_TYPE(FprintDevice, fprint_device, G_TYPE_OBJECT); 320 | 321 | FprintDevice *fprint_device_new(struct fp_dscv_dev *ddev) 322 | { 323 | return g_object_new(FPRINT_TYPE_DEVICE, "discovered-dev", ddev, NULL); 324 | } 325 | 326 | guint32 _fprint_device_get_id(FprintDevice *rdev) 327 | { 328 | return DEVICE_GET_PRIVATE(rdev)->id; 329 | } 330 | 331 | static const char * 332 | finger_num_to_name (int finger_num) 333 | { 334 | if (finger_num == -1) 335 | return "any"; 336 | if (finger_num < LEFT_THUMB || finger_num > RIGHT_LITTLE) 337 | return NULL; 338 | return fingers[finger_num - 1]; 339 | } 340 | 341 | static int 342 | finger_name_to_num (const char *finger_name) 343 | { 344 | guint i; 345 | 346 | if (finger_name == NULL || *finger_name == '\0' || g_str_equal (finger_name, "any")) 347 | return -1; 348 | 349 | for (i = 0; i < G_N_ELEMENTS (fingers); i++) { 350 | if (g_str_equal (finger_name, fingers[i])) 351 | return i + 1; 352 | } 353 | 354 | /* Invalid, let's try that */ 355 | return -1; 356 | } 357 | 358 | static const char * 359 | verify_result_to_name (int result) 360 | { 361 | switch (result) { 362 | case FP_VERIFY_NO_MATCH: 363 | return "verify-no-match"; 364 | case FP_VERIFY_MATCH: 365 | return "verify-match"; 366 | case FP_VERIFY_RETRY: 367 | return "verify-retry-scan"; 368 | case FP_VERIFY_RETRY_TOO_SHORT: 369 | return "verify-swipe-too-short"; 370 | case FP_VERIFY_RETRY_CENTER_FINGER: 371 | return "verify-finger-not-centered"; 372 | case FP_VERIFY_RETRY_REMOVE_FINGER: 373 | return "verify-remove-and-retry"; 374 | case -EPROTO: 375 | return "verify-disconnected"; 376 | default: 377 | return "verify-unknown-error"; 378 | } 379 | } 380 | 381 | static const char * 382 | enroll_result_to_name (int result) 383 | { 384 | switch (result) { 385 | case FP_ENROLL_COMPLETE: 386 | return "enroll-completed"; 387 | case FP_ENROLL_FAIL: 388 | return "enroll-failed"; 389 | case FP_ENROLL_PASS: 390 | return "enroll-stage-passed"; 391 | case FP_ENROLL_RETRY: 392 | return "enroll-retry-scan"; 393 | case FP_ENROLL_RETRY_TOO_SHORT: 394 | return "enroll-swipe-too-short"; 395 | case FP_ENROLL_RETRY_CENTER_FINGER: 396 | return "enroll-finger-not-centered"; 397 | case FP_ENROLL_RETRY_REMOVE_FINGER: 398 | return "enroll-remove-and-retry"; 399 | case -EPROTO: 400 | return "enroll-disconnected"; 401 | default: 402 | return "enroll-unknown-error"; 403 | } 404 | } 405 | 406 | static void 407 | set_disconnected (FprintDevicePrivate *priv, const char *res) 408 | { 409 | if (g_str_equal (res, "enroll-disconnected") || 410 | g_str_equal (res, "verify-disconnected")) 411 | priv->disconnected = TRUE; 412 | } 413 | 414 | static gboolean 415 | _fprint_device_check_claimed (FprintDevice *rdev, 416 | DBusGMethodInvocation *context, 417 | GError **error) 418 | { 419 | FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); 420 | DBusConnection *conn; 421 | char *sender; 422 | gboolean retval; 423 | 424 | /* The device wasn't claimed, exit */ 425 | if (priv->sender == NULL) { 426 | g_set_error (error, FPRINT_ERROR, FPRINT_ERROR_CLAIM_DEVICE, 427 | _("Device was not claimed before use")); 428 | return FALSE; 429 | } 430 | 431 | conn = dbus_g_connection_get_connection (fprintd_dbus_conn); 432 | sender = dbus_g_method_get_sender (context); 433 | retval = g_str_equal (sender, priv->sender); 434 | g_free (sender); 435 | 436 | if (retval == FALSE) { 437 | g_set_error (error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE, 438 | _("Device already in use by another user")); 439 | } 440 | 441 | return retval; 442 | } 443 | 444 | static gboolean 445 | _fprint_device_check_polkit_for_action (FprintDevice *rdev, DBusGMethodInvocation *context, const char *action, GError **error) 446 | { 447 | FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); 448 | const char *sender; 449 | DBusError dbus_error; 450 | PolKitCaller *pk_caller; 451 | PolKitAction *pk_action; 452 | PolKitResult pk_result; 453 | uid_t uid; 454 | 455 | /* Check that caller is privileged */ 456 | sender = dbus_g_method_get_sender (context); 457 | dbus_error_init (&dbus_error); 458 | pk_caller = polkit_caller_new_from_dbus_name ( 459 | dbus_g_connection_get_connection (fprintd_dbus_conn), 460 | sender, 461 | &dbus_error); 462 | if (pk_caller == NULL) { 463 | g_set_error (error, FPRINT_ERROR, 464 | FPRINT_ERROR_INTERNAL, 465 | "Error getting information about caller: %s: %s", 466 | dbus_error.name, dbus_error.message); 467 | dbus_error_free (&dbus_error); 468 | return FALSE; 469 | } 470 | 471 | /* XXX Hack? 472 | * We'd like to allow root to set the username by default, so 473 | * it can authenticate users through PAM 474 | * https://bugzilla.redhat.com/show_bug.cgi?id=447266 */ 475 | if ((polkit_caller_get_uid (pk_caller, &uid) && uid == 0) && 476 | (g_str_equal (action, "net.reactivated.fprint.device.setusername") || 477 | g_str_equal (action, "net.reactivated.fprint.device.verify"))) { 478 | polkit_caller_unref (pk_caller); 479 | return TRUE; 480 | } 481 | 482 | pk_action = polkit_action_new (); 483 | polkit_action_set_action_id (pk_action, action); 484 | pk_result = polkit_context_is_caller_authorized (priv->pol_ctx, pk_action, pk_caller, 485 | TRUE, NULL); 486 | polkit_caller_unref (pk_caller); 487 | polkit_action_unref (pk_action); 488 | 489 | if (pk_result != POLKIT_RESULT_YES) { 490 | g_set_error (error, FPRINT_ERROR, 491 | FPRINT_ERROR_PERMISSION_DENIED, 492 | "%s %s <-- (action, result)", 493 | action, 494 | polkit_result_to_string_representation (pk_result)); 495 | dbus_error_free (&dbus_error); 496 | return FALSE; 497 | } 498 | 499 | return TRUE; 500 | } 501 | 502 | static gboolean 503 | _fprint_device_check_polkit_for_actions (FprintDevice *rdev, 504 | DBusGMethodInvocation *context, 505 | const char *action1, 506 | const char *action2, 507 | GError **error) 508 | { 509 | if (_fprint_device_check_polkit_for_action (rdev, context, action1, error) != FALSE) 510 | return TRUE; 511 | 512 | g_error_free (*error); 513 | *error = NULL; 514 | 515 | return _fprint_device_check_polkit_for_action (rdev, context, action2, error); 516 | } 517 | 518 | static char * 519 | _fprint_device_check_for_username (FprintDevice *rdev, 520 | DBusGMethodInvocation *context, 521 | const char *username, 522 | char **ret_sender, 523 | GError **error) 524 | { 525 | DBusConnection *conn; 526 | DBusError dbus_error; 527 | char *sender; 528 | unsigned long uid; 529 | struct passwd *user; 530 | char *client_username; 531 | 532 | /* Get details about the current sender, and username/uid */ 533 | conn = dbus_g_connection_get_connection (fprintd_dbus_conn); 534 | sender = dbus_g_method_get_sender (context); 535 | dbus_error_init (&dbus_error); 536 | uid = dbus_bus_get_unix_user (conn, sender, &dbus_error); 537 | 538 | if (dbus_error_is_set(&dbus_error)) { 539 | g_free (sender); 540 | dbus_set_g_error (error, &dbus_error); 541 | return NULL; 542 | } 543 | 544 | user = getpwuid (uid); 545 | if (user == NULL) { 546 | g_free (sender); 547 | g_set_error(error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL, 548 | "Failed to get information about user UID %lu", uid); 549 | return NULL; 550 | } 551 | client_username = g_strdup (user->pw_name); 552 | 553 | /* The current user is usually allowed to access their 554 | * own data, this should be followed by PolicyKit checks 555 | * anyway */ 556 | if (username == NULL || *username == '\0' || g_str_equal (username, client_username)) { 557 | if (ret_sender != NULL) 558 | *ret_sender = sender; 559 | else 560 | g_free (sender); 561 | return client_username; 562 | } 563 | 564 | /* If we're not allowed to set a different username, 565 | * then fail */ 566 | if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.setusername", error) == FALSE) { 567 | g_free (sender); 568 | return NULL; 569 | } 570 | 571 | if (ret_sender != NULL) 572 | *ret_sender = sender; 573 | else 574 | g_free (sender); 575 | 576 | return g_strdup (username); 577 | } 578 | 579 | static void action_stop_cb(struct fp_dev *dev, void *user_data) 580 | { 581 | gboolean *done = (gboolean *) user_data; 582 | *done = TRUE; 583 | } 584 | 585 | static void 586 | _fprint_device_client_disconnected (EggDbusMonitor *monitor, gboolean connected, FprintDevice *rdev) 587 | { 588 | FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); 589 | 590 | if (connected == FALSE) { 591 | const char *sender; 592 | sender = egg_dbus_monitor_get_service (monitor); 593 | 594 | /* Was that the client that claimed the device? */ 595 | if (priv->sender != NULL) { 596 | gboolean done = FALSE; 597 | switch (priv->current_action) { 598 | case ACTION_NONE: 599 | break; 600 | case ACTION_IDENTIFY: 601 | fp_async_identify_stop(priv->dev, action_stop_cb, &done); 602 | while (done == FALSE) 603 | g_main_context_iteration (NULL, TRUE); 604 | break; 605 | case ACTION_VERIFY: 606 | fp_async_verify_stop(priv->dev, action_stop_cb, &done); 607 | while (done == FALSE) 608 | g_main_context_iteration (NULL, TRUE); 609 | break; 610 | case ACTION_ENROLL: 611 | fp_async_enroll_stop(priv->dev, action_stop_cb, &done); 612 | while (done == FALSE) 613 | g_main_context_iteration (NULL, TRUE); 614 | break; 615 | } 616 | priv->current_action = ACTION_NONE; 617 | done = FALSE; 618 | 619 | /* Close the claimed device as well */ 620 | fp_async_dev_close (priv->dev, action_stop_cb, &done); 621 | while (done == FALSE) 622 | g_main_context_iteration (NULL, TRUE); 623 | 624 | g_free (priv->sender); 625 | priv->sender = NULL; 626 | g_free (priv->username); 627 | priv->username = NULL; 628 | } 629 | g_hash_table_remove (priv->clients, sender); 630 | } 631 | 632 | if (g_hash_table_size (priv->clients) == 0) { 633 | g_object_notify (G_OBJECT (rdev), "in-use"); 634 | } 635 | } 636 | 637 | static void 638 | _fprint_device_add_client (FprintDevice *rdev, const char *sender) 639 | { 640 | EggDbusMonitor *monitor; 641 | FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); 642 | 643 | monitor = g_hash_table_lookup (priv->clients, sender); 644 | if (monitor == NULL) { 645 | monitor = egg_dbus_monitor_new (); 646 | egg_dbus_monitor_assign (monitor, fprintd_dbus_conn, sender); 647 | //FIXME handle replaced 648 | g_signal_connect (G_OBJECT (monitor), "connection-changed", 649 | G_CALLBACK (_fprint_device_client_disconnected), rdev); 650 | g_hash_table_insert (priv->clients, g_strdup (sender), monitor); 651 | g_object_notify (G_OBJECT (rdev), "in-use"); 652 | } 653 | } 654 | 655 | static void dev_open_cb(struct fp_dev *dev, int status, void *user_data) 656 | { 657 | FprintDevice *rdev = user_data; 658 | FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); 659 | struct session_data *session = priv->session; 660 | 661 | g_message("device %d claim status %d", priv->id, status); 662 | 663 | if (status != 0) { 664 | GError *error; 665 | 666 | g_free (priv->sender); 667 | priv->sender = NULL; 668 | 669 | g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL, 670 | "Open failed with error %d", status); 671 | dbus_g_method_return_error(session->context_claim_device, error); 672 | return; 673 | } 674 | 675 | priv->dev = dev; 676 | dbus_g_method_return(session->context_claim_device); 677 | } 678 | 679 | static void fprint_device_claim(FprintDevice *rdev, 680 | const char *username, 681 | DBusGMethodInvocation *context) 682 | { 683 | FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); 684 | GError *error = NULL; 685 | char *sender, *user; 686 | int r; 687 | 688 | /* Is it already claimed? */ 689 | if (priv->sender != NULL) { 690 | g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE, 691 | "Device was already claimed"); 692 | dbus_g_method_return_error(context, error); 693 | return; 694 | } 695 | 696 | g_assert (priv->username == NULL); 697 | g_assert (priv->sender == NULL); 698 | 699 | sender = NULL; 700 | user = _fprint_device_check_for_username (rdev, 701 | context, 702 | username, 703 | &sender, 704 | &error); 705 | if (user == NULL) { 706 | g_free (sender); 707 | dbus_g_method_return_error (context, error); 708 | g_error_free (error); 709 | return; 710 | } 711 | 712 | if (_fprint_device_check_polkit_for_actions (rdev, context, 713 | "net.reactivated.fprint.device.verify", 714 | "net.reactivated.fprint.device.enroll", 715 | &error) == FALSE) { 716 | g_free (sender); 717 | g_free (user); 718 | dbus_g_method_return_error (context, error); 719 | return; 720 | } 721 | 722 | _fprint_device_add_client (rdev, sender); 723 | 724 | priv->username = user; 725 | priv->sender = sender; 726 | 727 | g_message ("user '%s' claiming the device: %d", priv->username, priv->id); 728 | 729 | priv->session = g_slice_new0(struct session_data); 730 | priv->session->context_claim_device = context; 731 | 732 | r = fp_async_dev_open(priv->ddev, dev_open_cb, rdev); 733 | if (r < 0) { 734 | g_slice_free(struct session_data, priv->session); 735 | priv->session = NULL; 736 | 737 | g_free (priv->username); 738 | priv->username = NULL; 739 | g_free (priv->sender); 740 | priv->sender = NULL; 741 | 742 | g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL, 743 | "Could not attempt device open, error %d", r); 744 | dbus_g_method_return_error(context, error); 745 | } 746 | } 747 | 748 | static void dev_close_cb(struct fp_dev *dev, void *user_data) 749 | { 750 | FprintDevice *rdev = user_data; 751 | FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); 752 | struct session_data *session = priv->session; 753 | DBusGMethodInvocation *context = session->context_release_device; 754 | 755 | priv->dev = NULL; 756 | g_slice_free(struct session_data, session); 757 | priv->session = NULL; 758 | 759 | g_free (priv->sender); 760 | priv->sender = NULL; 761 | 762 | g_free (priv->username); 763 | priv->username = NULL; 764 | 765 | g_message("released device %d", priv->id); 766 | dbus_g_method_return(context); 767 | } 768 | 769 | static void fprint_device_release(FprintDevice *rdev, 770 | DBusGMethodInvocation *context) 771 | { 772 | FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); 773 | struct session_data *session = priv->session; 774 | GError *error = NULL; 775 | 776 | if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) { 777 | dbus_g_method_return_error (context, error); 778 | return; 779 | } 780 | 781 | /* People that can claim can also release */ 782 | if (_fprint_device_check_polkit_for_actions (rdev, context, 783 | "net.reactivated.fprint.device.verify", 784 | "net.reactivated.fprint.device.enroll", 785 | &error) == FALSE) { 786 | dbus_g_method_return_error (context, error); 787 | return; 788 | } 789 | 790 | session->context_release_device = context; 791 | fp_async_dev_close(priv->dev, dev_close_cb, rdev); 792 | } 793 | 794 | static void verify_cb(struct fp_dev *dev, int r, struct fp_img *img, 795 | void *user_data) 796 | { 797 | struct FprintDevice *rdev = user_data; 798 | FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); 799 | const char *name = verify_result_to_name (r); 800 | 801 | if (priv->action_done != FALSE) 802 | return; 803 | 804 | g_message("verify_cb: result %s (%d)", name, r); 805 | 806 | if (r == FP_VERIFY_NO_MATCH || r == FP_VERIFY_MATCH || r < 0) 807 | priv->action_done = TRUE; 808 | set_disconnected (priv, name); 809 | g_signal_emit(rdev, signals[SIGNAL_VERIFY_STATUS], 0, name, priv->action_done); 810 | fp_img_free(img); 811 | 812 | if (priv->action_done && priv->verify_data) { 813 | fp_print_data_free (priv->verify_data); 814 | priv->verify_data = NULL; 815 | } 816 | } 817 | 818 | static void identify_cb(struct fp_dev *dev, int r, 819 | size_t match_offset, struct fp_img *img, void *user_data) 820 | { 821 | struct FprintDevice *rdev = user_data; 822 | FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); 823 | const char *name = verify_result_to_name (r); 824 | 825 | if (priv->action_done != FALSE) 826 | return; 827 | 828 | g_message("identify_cb: result %s (%d)", name, r); 829 | 830 | if (r == FP_VERIFY_NO_MATCH || r == FP_VERIFY_MATCH || r < 0) 831 | priv->action_done = TRUE; 832 | set_disconnected (priv, name); 833 | g_signal_emit(rdev, signals[SIGNAL_VERIFY_STATUS], 0, name, priv->action_done); 834 | fp_img_free(img); 835 | 836 | if (priv->action_done && priv->identify_data != NULL) { 837 | guint i; 838 | for (i = 0; priv->identify_data[i] != NULL; i++) 839 | fp_print_data_free(priv->identify_data[i]); 840 | g_free (priv->identify_data); 841 | priv->identify_data = NULL; 842 | } 843 | } 844 | 845 | static void fprint_device_verify_start(FprintDevice *rdev, 846 | const char *finger_name, DBusGMethodInvocation *context) 847 | { 848 | FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); 849 | struct fp_print_data **gallery = NULL; 850 | struct fp_print_data *data = NULL; 851 | GError *error = NULL; 852 | guint finger_num = finger_name_to_num (finger_name); 853 | int r; 854 | 855 | if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) { 856 | dbus_g_method_return_error (context, error); 857 | g_error_free (error); 858 | return; 859 | } 860 | 861 | if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.verify", &error) == FALSE) { 862 | dbus_g_method_return_error (context, error); 863 | g_error_free (error); 864 | return; 865 | } 866 | 867 | if (priv->current_action != ACTION_NONE) { 868 | if (priv->current_action == ACTION_ENROLL) { 869 | g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE, 870 | "Enrollment in progress"); 871 | } else { 872 | g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE, 873 | "Verification already in progress"); 874 | } 875 | dbus_g_method_return_error(context, error); 876 | g_error_free (error); 877 | return; 878 | } 879 | priv->action_done = FALSE; 880 | 881 | if (finger_num == -1) { 882 | GSList *prints; 883 | 884 | prints = store.discover_prints(priv->ddev, priv->username); 885 | if (prints == NULL) { 886 | g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ENROLLED_PRINTS, 887 | "No fingerprints enrolled"); 888 | dbus_g_method_return_error(context, error); 889 | return; 890 | } 891 | if (fp_dev_supports_identification(priv->dev)) { 892 | GSList *l; 893 | GPtrArray *array; 894 | 895 | array = g_ptr_array_new (); 896 | 897 | for (l = prints; l != NULL; l = l->next) { 898 | g_message ("adding finger %d to the gallery", GPOINTER_TO_INT (l->data)); 899 | r = store.print_data_load(priv->dev, GPOINTER_TO_INT (l->data), 900 | &data, priv->username); 901 | if (r == 0) 902 | g_ptr_array_add (array, data); 903 | } 904 | data = NULL; 905 | 906 | if (array->len > 0) { 907 | g_ptr_array_add (array, NULL); 908 | gallery = (struct fp_print_data **) g_ptr_array_free (array, FALSE); 909 | } else { 910 | gallery = NULL; 911 | } 912 | } else { 913 | finger_num = GPOINTER_TO_INT (prints->data); 914 | } 915 | g_slist_free(prints); 916 | } 917 | 918 | if (fp_dev_supports_identification(priv->dev) && finger_num == -1) { 919 | if (gallery == NULL) { 920 | g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ENROLLED_PRINTS, 921 | "No fingerprints on that device"); 922 | dbus_g_method_return_error(context, error); 923 | g_error_free (error); 924 | return; 925 | } 926 | priv->current_action = ACTION_IDENTIFY; 927 | 928 | g_message ("start identification device %d", priv->id); 929 | r = fp_async_identify_start (priv->dev, gallery, identify_cb, rdev); 930 | } else { 931 | priv->current_action = ACTION_VERIFY; 932 | 933 | g_message("start verification device %d finger %d", priv->id, finger_num); 934 | 935 | r = store.print_data_load(priv->dev, (enum fp_finger)finger_num, 936 | &data, priv->username); 937 | 938 | if (r < 0 || !data) { 939 | g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL, 940 | "No such print %d", finger_num); 941 | dbus_g_method_return_error(context, error); 942 | return; 943 | } 944 | 945 | r = fp_async_verify_start(priv->dev, data, verify_cb, rdev); 946 | } 947 | 948 | /* Emit VerifyFingerSelected telling the front-end which finger 949 | * we selected for auth */ 950 | g_signal_emit(rdev, signals[SIGNAL_VERIFY_FINGER_SELECTED], 951 | 0, finger_num_to_name (finger_num)); 952 | 953 | 954 | if (r < 0) { 955 | if (data != NULL) { 956 | fp_print_data_free (data); 957 | } else if (gallery != NULL) { 958 | guint i; 959 | for (i = 0; gallery[i] != NULL; i++) 960 | fp_print_data_free(gallery[i]); 961 | g_free (gallery); 962 | } 963 | g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL, 964 | "Verify start failed with error %d", r); 965 | dbus_g_method_return_error(context, error); 966 | return; 967 | } 968 | priv->verify_data = data; 969 | priv->identify_data = gallery; 970 | 971 | dbus_g_method_return(context); 972 | } 973 | 974 | static void verify_stop_cb(struct fp_dev *dev, void *user_data) 975 | { 976 | dbus_g_method_return((DBusGMethodInvocation *) user_data); 977 | } 978 | 979 | static void identify_stop_cb(struct fp_dev *dev, void *user_data) 980 | { 981 | dbus_g_method_return((DBusGMethodInvocation *) user_data); 982 | } 983 | 984 | static void fprint_device_verify_stop(FprintDevice *rdev, 985 | DBusGMethodInvocation *context) 986 | { 987 | FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); 988 | GError *error = NULL; 989 | int r; 990 | 991 | if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) { 992 | dbus_g_method_return_error (context, error); 993 | return; 994 | } 995 | 996 | if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.verify", &error) == FALSE) { 997 | dbus_g_method_return_error (context, error); 998 | return; 999 | } 1000 | 1001 | if (priv->current_action == ACTION_VERIFY) { 1002 | if (priv->verify_data) { 1003 | fp_print_data_free (priv->verify_data); 1004 | priv->verify_data = NULL; 1005 | } 1006 | if (!priv->disconnected) 1007 | r = fp_async_verify_stop(priv->dev, verify_stop_cb, context); 1008 | else 1009 | r = 0; 1010 | } else if (priv->current_action == ACTION_IDENTIFY) { 1011 | if (priv->identify_data != NULL) { 1012 | guint i; 1013 | for (i = 0; priv->identify_data[i] != NULL; i++) 1014 | fp_print_data_free(priv->identify_data[i]); 1015 | g_free (priv->identify_data); 1016 | priv->identify_data = NULL; 1017 | } 1018 | if (!priv->disconnected) 1019 | r = fp_async_identify_stop(priv->dev, identify_stop_cb, context); 1020 | else 1021 | r = 0; 1022 | } else { 1023 | g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ACTION_IN_PROGRESS, 1024 | "No verification in progress"); 1025 | dbus_g_method_return_error(context, error); 1026 | g_error_free (error); 1027 | return; 1028 | } 1029 | 1030 | if (r < 0) { 1031 | g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL, 1032 | "Verify stop failed with error %d", r); 1033 | dbus_g_method_return_error(context, error); 1034 | g_error_free (error); 1035 | } 1036 | if (priv->disconnected) 1037 | dbus_g_method_return(context); 1038 | 1039 | priv->current_action = ACTION_NONE; 1040 | } 1041 | 1042 | static void enroll_stage_cb(struct fp_dev *dev, int result, 1043 | struct fp_print_data *print, struct fp_img *img, void *user_data) 1044 | { 1045 | struct FprintDevice *rdev = user_data; 1046 | FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); 1047 | struct session_data *session = priv->session; 1048 | const char *name = enroll_result_to_name (result); 1049 | int r; 1050 | 1051 | /* We're done, ignore new events for the action */ 1052 | if (priv->action_done != FALSE) 1053 | return; 1054 | 1055 | g_message("enroll_stage_cb: result %d", result); 1056 | if (result == FP_ENROLL_COMPLETE) { 1057 | r = store.print_data_save(print, session->enroll_finger, priv->username); 1058 | if (r < 0) 1059 | result = FP_ENROLL_FAIL; 1060 | } 1061 | 1062 | if (result == FP_ENROLL_COMPLETE || result == FP_ENROLL_FAIL || result < 0) 1063 | priv->action_done = TRUE; 1064 | set_disconnected (priv, name); 1065 | 1066 | g_signal_emit(rdev, signals[SIGNAL_ENROLL_STATUS], 0, name, priv->action_done); 1067 | 1068 | fp_img_free(img); 1069 | fp_print_data_free(print); 1070 | } 1071 | 1072 | static void fprint_device_enroll_start(FprintDevice *rdev, 1073 | const char *finger_name, DBusGMethodInvocation *context) 1074 | { 1075 | FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); 1076 | struct session_data *session = priv->session; 1077 | int finger_num = finger_name_to_num (finger_name); 1078 | GError *error = NULL; 1079 | int r; 1080 | 1081 | if (finger_num == -1) { 1082 | g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INVALID_FINGERNAME, 1083 | "Invalid print name"); 1084 | dbus_g_method_return_error(context, error); 1085 | g_error_free (error); 1086 | return; 1087 | } 1088 | 1089 | if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) { 1090 | dbus_g_method_return_error (context, error); 1091 | return; 1092 | } 1093 | 1094 | if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.enroll", &error) == FALSE) { 1095 | dbus_g_method_return_error (context, error); 1096 | return; 1097 | } 1098 | 1099 | if (priv->current_action != ACTION_NONE) { 1100 | if (priv->current_action == ACTION_ENROLL) { 1101 | g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE, 1102 | "Enrollment already in progress"); 1103 | } else { 1104 | g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE, 1105 | "Verification in progress"); 1106 | } 1107 | dbus_g_method_return_error(context, error); 1108 | g_error_free (error); 1109 | return; 1110 | } 1111 | 1112 | g_message("start enrollment device %d finger %d", priv->id, finger_num); 1113 | session->enroll_finger = finger_num; 1114 | priv->action_done = FALSE; 1115 | 1116 | r = fp_async_enroll_start(priv->dev, enroll_stage_cb, rdev); 1117 | if (r < 0) { 1118 | g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL, 1119 | "Enroll start failed with error %d", r); 1120 | dbus_g_method_return_error(context, error); 1121 | return; 1122 | } 1123 | 1124 | priv->current_action = ACTION_ENROLL; 1125 | 1126 | dbus_g_method_return(context); 1127 | } 1128 | 1129 | static void enroll_stop_cb(struct fp_dev *dev, void *user_data) 1130 | { 1131 | dbus_g_method_return((DBusGMethodInvocation *) user_data); 1132 | } 1133 | 1134 | static void fprint_device_enroll_stop(FprintDevice *rdev, 1135 | DBusGMethodInvocation *context) 1136 | { 1137 | FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); 1138 | GError *error = NULL; 1139 | int r; 1140 | 1141 | if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) { 1142 | dbus_g_method_return_error (context, error); 1143 | return; 1144 | } 1145 | 1146 | if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.enroll", &error) == FALSE) { 1147 | dbus_g_method_return_error (context, error); 1148 | return; 1149 | } 1150 | 1151 | if (priv->current_action != ACTION_ENROLL) { 1152 | g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ACTION_IN_PROGRESS, 1153 | "No enrollment in progress"); 1154 | dbus_g_method_return_error(context, error); 1155 | g_error_free (error); 1156 | return; 1157 | } 1158 | 1159 | if (!priv->disconnected) 1160 | r = fp_async_enroll_stop(priv->dev, enroll_stop_cb, context); 1161 | else 1162 | r = 0; 1163 | if (r < 0) { 1164 | g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL, 1165 | "Enroll stop failed with error %d", r); 1166 | dbus_g_method_return_error(context, error); 1167 | g_error_free (error); 1168 | } 1169 | if (priv->disconnected) 1170 | dbus_g_method_return(context); 1171 | 1172 | priv->current_action = ACTION_NONE; 1173 | } 1174 | 1175 | static void fprint_device_list_enrolled_fingers(FprintDevice *rdev, 1176 | const char *username, 1177 | DBusGMethodInvocation *context) 1178 | { 1179 | FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); 1180 | GError *error = NULL; 1181 | GSList *prints; 1182 | GSList *item; 1183 | GPtrArray *ret; 1184 | char *user, *sender; 1185 | 1186 | user = _fprint_device_check_for_username (rdev, 1187 | context, 1188 | username, 1189 | NULL, 1190 | &error); 1191 | if (user == NULL) { 1192 | dbus_g_method_return_error (context, error); 1193 | g_error_free (error); 1194 | return; 1195 | } 1196 | 1197 | if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.verify", &error) == FALSE) { 1198 | g_free (user); 1199 | dbus_g_method_return_error (context, error); 1200 | return; 1201 | } 1202 | 1203 | sender = dbus_g_method_get_sender (context); 1204 | _fprint_device_add_client (rdev, sender); 1205 | g_free (sender); 1206 | 1207 | prints = store.discover_prints(priv->ddev, user); 1208 | g_free (user); 1209 | if (!prints) { 1210 | g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ENROLLED_PRINTS, 1211 | "Failed to discover prints"); 1212 | dbus_g_method_return_error(context, error); 1213 | return; 1214 | } 1215 | 1216 | ret = g_ptr_array_new (); 1217 | for (item = prints; item; item = item->next) { 1218 | int finger_num = GPOINTER_TO_INT (item->data); 1219 | g_ptr_array_add (ret, g_strdup (finger_num_to_name (finger_num))); 1220 | } 1221 | g_ptr_array_add (ret, NULL); 1222 | 1223 | g_slist_free(prints); 1224 | 1225 | dbus_g_method_return(context, g_ptr_array_free (ret, FALSE)); 1226 | } 1227 | 1228 | static void fprint_device_delete_enrolled_fingers(FprintDevice *rdev, 1229 | const char *username, 1230 | DBusGMethodInvocation *context) 1231 | { 1232 | FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev); 1233 | GError *error = NULL; 1234 | guint i; 1235 | char *user, *sender; 1236 | 1237 | user = _fprint_device_check_for_username (rdev, 1238 | context, 1239 | username, 1240 | NULL, 1241 | &error); 1242 | if (user == NULL) { 1243 | dbus_g_method_return_error (context, error); 1244 | g_error_free (error); 1245 | return; 1246 | } 1247 | 1248 | if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.enroll", &error) == FALSE) { 1249 | g_free (user); 1250 | dbus_g_method_return_error (context, error); 1251 | return; 1252 | } 1253 | 1254 | sender = dbus_g_method_get_sender (context); 1255 | _fprint_device_add_client (rdev, sender); 1256 | g_free (sender); 1257 | 1258 | for (i = LEFT_THUMB; i <= RIGHT_LITTLE; i++) { 1259 | store.print_data_delete(priv->ddev, i, user); 1260 | } 1261 | g_free (user); 1262 | 1263 | dbus_g_method_return(context); 1264 | } 1265 | 1266 | -------------------------------------------------------------------------------- /src/device.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | ]> 12 | 13 | 14 | 15 | 17 | 18 | 19 | 20 | PolicyKit integration 21 | 22 | 23 | fprintd uses PolicyKit to check whether users are allowed to access fingerprint data, or the 24 | fingerprint readers itself. 25 | 26 | 27 | net.reactivated.fprint.device.verify 28 | 29 | Whether the user is allowed to verify fingers against saved fingerprints. 30 | 31 | 32 | 33 | net.reactivated.fprint.device.enroll 34 | 35 | Whether the user is allowed to enroll new fingerprints. 36 | 37 | 38 | 39 | net.reactivated.fprint.device.setusername 40 | 41 | Whether the user is allowed to query, verify, or enroll fingerprints for users other than itself. 42 | 43 | 44 | 45 | 46 | 47 | 48 | Usernames 49 | 50 | 51 | When a username argument is used for a method, a PolicyKit check is done on the 52 | net.reactivated.fprint.device.setusername PolicyKit 53 | action to see whether the user the client is running as is allowed to access data from other users. 54 | 55 | 56 | By default, only root is allowed to access fingerprint data for users other than itself. For a normal user, 57 | it is recommended that you use an empty string for the username, which will mean "the client the user is 58 | running as". 59 | 60 | 61 | See PolicyKit integration. 62 | 63 | 64 | 65 | Fingerprint names 66 | 67 | 68 | When a finger name argument is used for a method, it refers to either a single finger, or 69 | "any" finger. See the list of possible values below: 70 | 71 | 72 | left-thumb 73 | 74 | Left thumb 75 | 76 | 77 | 78 | left-index-finger 79 | 80 | Left index finger 81 | 82 | 83 | 84 | left-middle-finger 85 | 86 | Left middle finger 87 | 88 | 89 | 90 | left-ring-finger 91 | 92 | Left ring finger 93 | 94 | 95 | 96 | left-little-finger 97 | 98 | Left little finger 99 | 100 | 101 | 102 | right-thumb 103 | 104 | Right thumb 105 | 106 | 107 | 108 | right-index-finger 109 | 110 | Right index finger 111 | 112 | 113 | 114 | right-middle-finger 115 | 116 | Right middle finger 117 | 118 | 119 | 120 | right-ring-finger 121 | 122 | Right ring finger 123 | 124 | 125 | 126 | right-little-finger 127 | 128 | Right little finger 129 | 130 | 131 | 132 | any 133 | 134 | Any finger. This is only used for Device.VerifyStart 135 | (select the first finger with a fingerprint associated, or all the fingerprints available for the user when 136 | the device supports it) and Device::VerifyFingerSelected 137 | (any finger with an associated fingerprint can be used). 138 | 139 | 140 | 141 | 142 | 143 | 144 | Verify Statuses 145 | 146 | 147 | 148 | Possible values for the result passed through Device::VerifyResult are: 149 | 150 | verify-no-match 151 | 152 | The verification did not match, Device.VerifyStop should now be called. 153 | 154 | 155 | 156 | verify-match 157 | 158 | The verification succeeded, Device.VerifyStop should now be called. 159 | 160 | 161 | 162 | verify-retry-scan 163 | 164 | The user should retry scanning their finger, the verification is still ongoing. 165 | 166 | 167 | 168 | verify-swipe-too-short 169 | 170 | The user's swipe was too short. The user should retry scanning their finger, the verification is still ongoing. 171 | 172 | 173 | 174 | verify-finger-not-centered 175 | 176 | The user's finger was not centered on the reader. The user should retry scanning their finger, the verification is still ongoing. 177 | 178 | 179 | 180 | verify-remove-and-retry 181 | 182 | The user should remove their finger from the reader and retry scanning their finger, the verification is still ongoing. 183 | 184 | 185 | 186 | verify-disconnected 187 | 188 | The device was disconnected during the verification, no other actions should be taken, and you shouldn't use the device any more. 189 | 190 | 191 | 192 | verify-unknown-error 193 | 194 | An unknown error occurred (usually a driver problem), Device.VerifyStop should now be called. 195 | 196 | 197 | 198 | 199 | 200 | 201 | Enroll Statuses 202 | 203 | 204 | 205 | Possible values for the result passed through Device::EnrollResult are: 206 | 207 | enroll-completed 208 | 209 | The enrollment successfully completed, Device.EnrollStop should now be called. 210 | 211 | 212 | 213 | enroll-failed 214 | 215 | The enrollment failed, Device.EnrollStop should now be called. 216 | 217 | 218 | 219 | enroll-stage-passed 220 | 221 | One stage of the enrollment passed, the enrollment is still ongoing. 222 | 223 | 224 | 225 | enroll-retry-scan 226 | 227 | The user should retry scanning their finger, the enrollment is still ongoing. 228 | 229 | 230 | 231 | enroll-swipe-too-short 232 | 233 | The user's swipe was too short. The user should retry scanning their finger, the enrollment is still ongoing. 234 | 235 | 236 | 237 | enroll-finger-not-centered 238 | 239 | The user's finger was not centered on the reader. The user should retry scanning their finger, the enrollment is still ongoing. 240 | 241 | 242 | 243 | enroll-remove-and-retry 244 | 245 | The user should remove their finger from the reader and retry scanning their finger, the enrollment is still ongoing. 246 | 247 | 248 | 249 | enroll-disconnected 250 | 251 | The device was disconnected during the enrollment, no other actions should be taken, and you shouldn't use the device any more. 252 | 253 | 254 | 255 | 256 | enroll-unknown-error 257 | 258 | An unknown error occurred (usually a driver problem), Device.EnrollStop should now be called. 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | The username for whom to list the enrolled fingerprints. See Usernames. 271 | 272 | 273 | An array of strings representing the enrolled fingerprints. See Fingerprint names. 274 | 275 | 276 | 277 | 278 | 279 | 280 | List all the enrolled fingerprints for the chosen user. 281 | 282 | 283 | 284 | 285 | if the caller lacks the appropriate PolicyKit authorization 286 | if the chosen user doesn't have any fingerprints enrolled 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | The username for whom to delete the enrolled fingerprints. See Usernames. 296 | 297 | 298 | 299 | 300 | 301 | 302 | Delete all the enrolled fingerprints for the chosen user. 303 | 304 | 305 | 306 | 307 | if the caller lacks the appropriate PolicyKit authorization 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | The username for whom to claim the device. See Usernames. 317 | 318 | 319 | 320 | 321 | 322 | 323 | Claim the device for the chosen user. 324 | 325 | 326 | 327 | 328 | if the caller lacks the appropriate PolicyKit authorization 329 | if the device is already claimed 330 | if the device couldn't be claimed 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | Release a device claimed with Device.Claim. 344 | 345 | 346 | 347 | 348 | if the caller lacks the appropriate PolicyKit authorization 349 | if the device was not claimed 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | A string representing the finger to verify. See Fingerprint names. 359 | 360 | 361 | 362 | 363 | 364 | 365 | Check the chosen finger against a saved fingerprint. You need to have claimed the device using 366 | Device.Claim. The finger selected is sent to the front-end 367 | using Device::VerifyFingerSelected and 368 | verification status through Device::VerifyStatus. 369 | 370 | 371 | 372 | 373 | if the caller lacks the appropriate PolicyKit authorization 374 | if the device was not claimed 375 | if the device was already being used 376 | if there are no enrolled prints for the chosen user 377 | if there was an internal error 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | Stop an on-going fingerprint verification started with Device.VerifyStart. 391 | 392 | 393 | 394 | 395 | if the caller lacks the appropriate PolicyKit authorization 396 | if the device was not claimed 397 | if there was no ongoing verification 398 | if there was an internal error 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | A string representing the finger select to be verified. 411 | 412 | 413 | 414 | 415 | 416 | 417 | Fingerprint names. 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | A string representing the status of the verification. 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | Whether the verification finished and can be stopped. 437 | 438 | 439 | 440 | 441 | 442 | 443 | Verify Statuses and Device.VerifyStop. 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | A string representing the finger to enroll. See 453 | Fingerprint names. 454 | Note that "any" is not a valid finger name for this method. 455 | 456 | 457 | 458 | 459 | 460 | 461 | Start enrollemnt for the selected finger. You need to have claimed the device using 462 | Device.Claim before calling 463 | this method. Enrollment status is sent through Device::EnrollStatus. 464 | 465 | 466 | 467 | 468 | if the caller lacks the appropriate PolicyKit authorization 469 | if the device was not claimed 470 | if the device was already being used 471 | if there are no enrolled prints for the chosen user 472 | if there was an internal error 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | Stop an on-going fingerprint enrollment started with Device.EnrollStart. 487 | 488 | 489 | 490 | 491 | if the caller lacks the appropriate PolicyKit authorization 492 | if the device was not claimed 493 | if there was no ongoing verification 494 | if there was an internal error 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | A string representing the status of the enrollment. 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | Whether the enrollment finished and can be stopped. 514 | 515 | 516 | 517 | 518 | 519 | 520 | Enrollment Statuses and Device.EnrollStop. 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | The product name of the device. 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | The number of enrollment stages for the device. This is only available when the device has been claimed, otherwise it will be undefined (-1). 544 | 545 | 546 | Device.Claim and Device.EnrollStart. 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | The scan type of the device, either "press" if you place your finger on the device, or "swipe" if you have to swipe your finger. 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | -------------------------------------------------------------------------------- /src/egg-dbus-monitor.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- 2 | * 3 | * Copyright (C) 2006-2008 Richard Hughes 4 | * 5 | * Licensed under the GNU General Public License Version 2 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 20 | */ 21 | 22 | #include "config.h" 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "egg-dbus-monitor.h" 33 | 34 | static void egg_dbus_monitor_class_init (EggDbusMonitorClass *klass); 35 | static void egg_dbus_monitor_init (EggDbusMonitor *dbus_monitor); 36 | static void egg_dbus_monitor_finalize (GObject *object); 37 | 38 | #define EGG_DBUS_MONITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), EGG_TYPE_DBUS_MONITOR, EggDbusMonitorPrivate)) 39 | 40 | struct EggDbusMonitorPrivate 41 | { 42 | gchar *service; 43 | DBusGProxy *proxy; 44 | DBusGConnection *connection; 45 | const gchar *unique_name; 46 | }; 47 | 48 | enum { 49 | EGG_DBUS_MONITOR_CONNECTION_CHANGED, 50 | EGG_DBUS_MONITOR_CONNECTION_REPLACED, 51 | EGG_DBUS_MONITOR_LAST_SIGNAL 52 | }; 53 | 54 | static guint signals [EGG_DBUS_MONITOR_LAST_SIGNAL] = { 0 }; 55 | 56 | G_DEFINE_TYPE (EggDbusMonitor, egg_dbus_monitor, G_TYPE_OBJECT) 57 | 58 | /** 59 | * egg_dbus_monitor_name_owner_changed_cb: 60 | **/ 61 | static void 62 | egg_dbus_monitor_name_owner_changed_cb (DBusGProxy *proxy, const gchar *name, 63 | const gchar *prev, const gchar *new, 64 | EggDbusMonitor *monitor) 65 | { 66 | guint new_len; 67 | guint prev_len; 68 | 69 | g_return_if_fail (EGG_IS_DBUS_MONITOR (monitor)); 70 | if (monitor->priv->proxy == NULL) 71 | return; 72 | 73 | /* not us */ 74 | if (strcmp (name, monitor->priv->service) != 0) 75 | return; 76 | 77 | /* ITS4: ignore, not used for allocation */ 78 | new_len = strlen (new); 79 | /* ITS4: ignore, not used for allocation */ 80 | prev_len = strlen (prev); 81 | 82 | /* something --> nothing */ 83 | if (prev_len != 0 && new_len == 0) { 84 | g_signal_emit (monitor, signals [EGG_DBUS_MONITOR_CONNECTION_CHANGED], 0, FALSE); 85 | return; 86 | } 87 | 88 | /* nothing --> something */ 89 | if (prev_len == 0 && new_len != 0) { 90 | g_signal_emit (monitor, signals [EGG_DBUS_MONITOR_CONNECTION_CHANGED], 0, TRUE); 91 | return; 92 | } 93 | 94 | /* something --> something (we've replaced the old process) */ 95 | if (prev_len != 0 && new_len != 0) { 96 | /* only send this to the prev client */ 97 | if (strcmp (monitor->priv->unique_name, prev) == 0) 98 | g_signal_emit (monitor, signals [EGG_DBUS_MONITOR_CONNECTION_REPLACED], 0); 99 | return; 100 | } 101 | } 102 | 103 | /** 104 | * egg_dbus_monitor_assign: 105 | * @monitor: This class instance 106 | * @connection: The bus connection 107 | * @service: The EGG_DBUS_MONITOR service name 108 | * Return value: success 109 | * 110 | * Emits connection-changed(TRUE) if connection is alive - this means you 111 | * have to connect up the callback before this function is called. 112 | **/ 113 | gboolean 114 | egg_dbus_monitor_assign (EggDbusMonitor *monitor, DBusGConnection *connection, const gchar *service) 115 | { 116 | GError *error = NULL; 117 | gboolean connected; 118 | DBusConnection *conn; 119 | 120 | g_return_val_if_fail (EGG_IS_DBUS_MONITOR (monitor), FALSE); 121 | g_return_val_if_fail (service != NULL, FALSE); 122 | g_return_val_if_fail (connection != NULL, FALSE); 123 | 124 | if (monitor->priv->proxy != NULL) { 125 | g_warning ("already assigned!"); 126 | return FALSE; 127 | } 128 | 129 | monitor->priv->service = g_strdup (service); 130 | monitor->priv->connection = connection; 131 | monitor->priv->proxy = dbus_g_proxy_new_for_name_owner (monitor->priv->connection, 132 | DBUS_SERVICE_DBUS, 133 | DBUS_PATH_DBUS, 134 | DBUS_INTERFACE_DBUS, 135 | &error); 136 | if (error != NULL) { 137 | g_warning ("Cannot connect to DBUS: %s", error->message); 138 | g_error_free (error); 139 | return FALSE; 140 | } 141 | dbus_g_proxy_add_signal (monitor->priv->proxy, "NameOwnerChanged", 142 | G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID); 143 | dbus_g_proxy_connect_signal (monitor->priv->proxy, "NameOwnerChanged", 144 | G_CALLBACK (egg_dbus_monitor_name_owner_changed_cb), 145 | monitor, NULL); 146 | 147 | /* coldplug */ 148 | connected = egg_dbus_monitor_is_connected (monitor); 149 | if (connected) 150 | g_signal_emit (monitor, signals [EGG_DBUS_MONITOR_CONNECTION_CHANGED], 0, TRUE); 151 | 152 | /* save this for the replaced check */ 153 | conn = dbus_g_connection_get_connection (monitor->priv->connection); 154 | monitor->priv->unique_name = dbus_bus_get_unique_name (conn); 155 | return TRUE; 156 | } 157 | 158 | /** 159 | * egg_dbus_monitor_is_connected: 160 | * @monitor: This class instance 161 | * Return value: if we are connected to a valid watch 162 | **/ 163 | gboolean 164 | egg_dbus_monitor_is_connected (EggDbusMonitor *monitor) 165 | { 166 | DBusError error; 167 | DBusConnection *conn; 168 | gboolean ret; 169 | g_return_val_if_fail (EGG_IS_DBUS_MONITOR (monitor), FALSE); 170 | 171 | /* get raw connection */ 172 | conn = dbus_g_connection_get_connection (monitor->priv->connection); 173 | dbus_error_init (&error); 174 | ret = dbus_bus_name_has_owner (conn, monitor->priv->service, &error); 175 | if (dbus_error_is_set (&error)) { 176 | g_debug ("error: %s", error.message); 177 | dbus_error_free (&error); 178 | } 179 | 180 | return ret; 181 | } 182 | 183 | /** 184 | * egg_dbus_monitor_get_service: 185 | * @monitor: This class instance 186 | * Return value: the service name being monitored 187 | **/ 188 | const gchar * 189 | egg_dbus_monitor_get_service (EggDbusMonitor *monitor) 190 | { 191 | g_return_val_if_fail (EGG_IS_DBUS_MONITOR (monitor), FALSE); 192 | 193 | return monitor->priv->service; 194 | } 195 | 196 | /** 197 | * egg_dbus_monitor_class_init: 198 | * @klass: The EggDbusMonitorClass 199 | **/ 200 | static void 201 | egg_dbus_monitor_class_init (EggDbusMonitorClass *klass) 202 | { 203 | GObjectClass *object_class = G_OBJECT_CLASS (klass); 204 | object_class->finalize = egg_dbus_monitor_finalize; 205 | g_type_class_add_private (klass, sizeof (EggDbusMonitorPrivate)); 206 | signals [EGG_DBUS_MONITOR_CONNECTION_CHANGED] = 207 | g_signal_new ("connection-changed", 208 | G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, 209 | G_STRUCT_OFFSET (EggDbusMonitorClass, connection_changed), 210 | NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, 211 | G_TYPE_NONE, 1, G_TYPE_BOOLEAN); 212 | signals [EGG_DBUS_MONITOR_CONNECTION_REPLACED] = 213 | g_signal_new ("connection-replaced", 214 | G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, 215 | G_STRUCT_OFFSET (EggDbusMonitorClass, connection_replaced), 216 | NULL, NULL, g_cclosure_marshal_VOID__VOID, 217 | G_TYPE_NONE, 0); 218 | } 219 | 220 | /** 221 | * egg_dbus_monitor_init: 222 | * @monitor: This class instance 223 | **/ 224 | static void 225 | egg_dbus_monitor_init (EggDbusMonitor *monitor) 226 | { 227 | monitor->priv = EGG_DBUS_MONITOR_GET_PRIVATE (monitor); 228 | monitor->priv->service = NULL; 229 | monitor->priv->connection = NULL; 230 | monitor->priv->proxy = NULL; 231 | } 232 | 233 | /** 234 | * egg_dbus_monitor_finalize: 235 | * @object: The object to finalize 236 | **/ 237 | static void 238 | egg_dbus_monitor_finalize (GObject *object) 239 | { 240 | EggDbusMonitor *monitor; 241 | 242 | g_return_if_fail (EGG_IS_DBUS_MONITOR (object)); 243 | 244 | monitor = EGG_DBUS_MONITOR (object); 245 | 246 | g_return_if_fail (monitor->priv != NULL); 247 | if (monitor->priv->proxy != NULL) 248 | g_object_unref (monitor->priv->proxy); 249 | 250 | G_OBJECT_CLASS (egg_dbus_monitor_parent_class)->finalize (object); 251 | } 252 | 253 | /** 254 | * egg_dbus_monitor_new: 255 | * 256 | * Return value: a new EggDbusMonitor object. 257 | **/ 258 | EggDbusMonitor * 259 | egg_dbus_monitor_new (void) 260 | { 261 | EggDbusMonitor *monitor; 262 | monitor = g_object_new (EGG_TYPE_DBUS_MONITOR, NULL); 263 | return EGG_DBUS_MONITOR (monitor); 264 | } 265 | 266 | -------------------------------------------------------------------------------- /src/egg-dbus-monitor.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- 2 | * 3 | * Copyright (C) 2008 Richard Hughes 4 | * 5 | * Licensed under the GNU General Public License Version 2 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 20 | */ 21 | 22 | #ifndef __EGG_DBUS_MONITOR_H 23 | #define __EGG_DBUS_MONITOR_H 24 | 25 | #include 26 | #include 27 | 28 | G_BEGIN_DECLS 29 | 30 | #define EGG_TYPE_DBUS_MONITOR (egg_dbus_monitor_get_type ()) 31 | #define EGG_DBUS_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EGG_TYPE_DBUS_MONITOR, EggDbusMonitor)) 32 | #define EGG_DBUS_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EGG_TYPE_DBUS_MONITOR, EggDbusMonitorClass)) 33 | #define EGG_IS_DBUS_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EGG_TYPE_DBUS_MONITOR)) 34 | #define EGG_IS_DBUS_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EGG_TYPE_DBUS_MONITOR)) 35 | #define EGG_DBUS_MONITOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EGG_TYPE_DBUS_MONITOR, EggDbusMonitorClass)) 36 | #define EGG_DBUS_MONITOR_ERROR (egg_dbus_monitor_error_quark ()) 37 | #define EGG_DBUS_MONITOR_TYPE_ERROR (egg_dbus_monitor_error_get_type ()) 38 | 39 | typedef struct EggDbusMonitorPrivate EggDbusMonitorPrivate; 40 | 41 | typedef struct 42 | { 43 | GObject parent; 44 | EggDbusMonitorPrivate *priv; 45 | } EggDbusMonitor; 46 | 47 | typedef struct 48 | { 49 | GObjectClass parent_class; 50 | void (* connection_changed) (EggDbusMonitor *watch, 51 | gboolean connected); 52 | void (* connection_replaced) (EggDbusMonitor *watch); 53 | } EggDbusMonitorClass; 54 | 55 | GType egg_dbus_monitor_get_type (void) G_GNUC_CONST; 56 | EggDbusMonitor *egg_dbus_monitor_new (void); 57 | gboolean egg_dbus_monitor_assign (EggDbusMonitor *monitor, 58 | DBusGConnection *connection, 59 | const gchar *service); 60 | const gchar *egg_dbus_monitor_get_service (EggDbusMonitor *monitor); 61 | gboolean egg_dbus_monitor_is_connected (EggDbusMonitor *monitor); 62 | 63 | G_END_DECLS 64 | 65 | #endif /* __EGG_DBUS_MONITOR_H */ 66 | 67 | -------------------------------------------------------------------------------- /src/file_storage.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple file storage for fprintd 3 | * Copyright (C) 2007 Daniel Drake 4 | * Copyright (C) 2008 Vasily Khoruzhick 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License along 17 | * with this program; if not, write to the Free Software Foundation, Inc., 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | * 20 | */ 21 | 22 | 23 | /* FIXME: 24 | * This file almost duplicate data.c from libfprint 25 | * Maybe someday data.c will be upgraded to this one ;) 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | 38 | #include 39 | 40 | #include "file_storage.h" 41 | 42 | #define DIR_PERMS 0700 43 | 44 | #ifndef FILE_STORAGE_PATH 45 | #define FILE_STORAGE_PATH "/var/lib/fprint/" 46 | #endif 47 | 48 | #define FP_FINGER_IS_VALID(finger) \ 49 | ((finger) >= LEFT_THUMB && (finger) <= RIGHT_LITTLE) 50 | 51 | static char *get_path_to_storedir(uint16_t driver_id, uint32_t devtype, char *base_store) 52 | { 53 | char idstr[5]; 54 | char devtypestr[9]; 55 | 56 | g_snprintf(idstr, sizeof(idstr), "%04x", driver_id); 57 | g_snprintf(devtypestr, sizeof(devtypestr), "%08x", devtype); 58 | 59 | return g_build_filename(base_store, idstr, devtypestr, NULL); 60 | } 61 | 62 | static char *__get_path_to_print(uint16_t driver_id, uint32_t devtype, 63 | enum fp_finger finger, char *base_store) 64 | { 65 | char *dirpath; 66 | char *path; 67 | char fingername[2]; 68 | 69 | g_snprintf(fingername, 2, "%x", finger); 70 | 71 | dirpath = get_path_to_storedir(driver_id, devtype, base_store); 72 | path = g_build_filename(dirpath, fingername, NULL); 73 | g_free(dirpath); 74 | return path; 75 | } 76 | 77 | static char *get_path_to_print(struct fp_dev *dev, enum fp_finger finger, char *base_store) 78 | { 79 | return __get_path_to_print(fp_driver_get_driver_id(fp_dev_get_driver(dev)), 80 | fp_dev_get_devtype(dev), finger, base_store); 81 | } 82 | 83 | static char *get_path_to_print_dscv(struct fp_dscv_dev *dev, enum fp_finger finger, char *base_store) 84 | { 85 | return __get_path_to_print(fp_driver_get_driver_id(fp_dscv_dev_get_driver(dev)), 86 | fp_dscv_dev_get_devtype(dev), finger, base_store); 87 | } 88 | 89 | static int file_storage_get_basestore_for_username(const char *username, char **base_store) 90 | { 91 | char *dirpath = FILE_STORAGE_PATH; 92 | 93 | *base_store = g_build_filename(dirpath, username, NULL); 94 | return 0; 95 | } 96 | 97 | /* if username == NULL function will use current username */ 98 | int file_storage_print_data_save(struct fp_print_data *data, 99 | enum fp_finger finger, const char *username) 100 | { 101 | GError *err = NULL; 102 | char *path, *dirpath, *buf; 103 | size_t len; 104 | int r; 105 | char *base_store = NULL; 106 | 107 | r = file_storage_get_basestore_for_username(username, &base_store); 108 | 109 | if (r < 0) { 110 | return r; 111 | } 112 | 113 | len = fp_print_data_get_data(data, (guchar **) &buf); 114 | if (!len) { 115 | g_free(base_store); 116 | return -ENOMEM; 117 | } 118 | 119 | path = __get_path_to_print(fp_print_data_get_driver_id(data), fp_print_data_get_devtype(data), finger, base_store); 120 | dirpath = g_path_get_dirname(path); 121 | r = g_mkdir_with_parents(dirpath, DIR_PERMS); 122 | if (r < 0) { 123 | g_free(base_store); 124 | g_free(path); 125 | g_free(dirpath); 126 | return r; 127 | } 128 | 129 | //fp_dbg("saving to %s", path); 130 | g_file_set_contents(path, buf, len, &err); 131 | free(buf); 132 | g_free(dirpath); 133 | g_free(path); 134 | if (err) { 135 | r = err->code; 136 | //fp_err("save failed: %s", err->message); 137 | g_error_free(err); 138 | /* FIXME interpret error codes */ 139 | return r; 140 | } 141 | 142 | return 0; 143 | } 144 | 145 | static int load_from_file(char *path, struct fp_print_data **data) 146 | { 147 | gsize length; 148 | char *contents; 149 | GError *err = NULL; 150 | struct fp_print_data *fdata; 151 | 152 | //fp_dbg("from %s", path); 153 | g_file_get_contents(path, &contents, &length, &err); 154 | if (err) { 155 | int r = err->code; 156 | g_error_free(err); 157 | /* FIXME interpret more error codes */ 158 | if (r == G_FILE_ERROR_NOENT) 159 | return -ENOENT; 160 | else 161 | return r; 162 | } 163 | 164 | fdata = fp_print_data_from_data((guchar *) contents, length); 165 | g_free(contents); 166 | if (!fdata) 167 | return -EIO; 168 | *data = fdata; 169 | return 0; 170 | } 171 | 172 | int file_storage_print_data_load(struct fp_dev *dev, 173 | enum fp_finger finger, struct fp_print_data **data, const char *username) 174 | { 175 | gchar *path; 176 | struct fp_print_data *fdata = NULL; 177 | int r; 178 | char *base_store = NULL; 179 | 180 | r = file_storage_get_basestore_for_username(username, &base_store); 181 | 182 | if (r < 0) { 183 | return r; 184 | } 185 | 186 | path = get_path_to_print(dev, finger, base_store); 187 | r = load_from_file(path, &fdata); 188 | g_free(path); 189 | g_free(base_store); 190 | if (r) 191 | return r; 192 | 193 | if (!fp_dev_supports_print_data(dev, fdata)) { 194 | fp_print_data_free(fdata); 195 | return -EINVAL; 196 | } 197 | 198 | *data = fdata; 199 | return 0; 200 | } 201 | 202 | int file_storage_print_data_delete(struct fp_dscv_dev *dev, 203 | enum fp_finger finger, const char *username) 204 | { 205 | int r; 206 | char *base_store; 207 | 208 | r = file_storage_get_basestore_for_username(username, &base_store); 209 | 210 | if (r < 0) { 211 | return r; 212 | } 213 | 214 | gchar *path = get_path_to_print_dscv(dev, finger, base_store); 215 | 216 | r = g_unlink(path); 217 | g_free(path); 218 | g_free(base_store); 219 | 220 | /* FIXME: cleanup empty directory */ 221 | return r; 222 | } 223 | 224 | static GSList *scan_dev_storedir(char *devpath, uint16_t driver_id, 225 | uint32_t devtype, GSList *list) 226 | { 227 | GError *err = NULL; 228 | const gchar *ent; 229 | 230 | GDir *dir = g_dir_open(devpath, 0, &err); 231 | if (!dir) { 232 | //fp_err("opendir %s failed: %s", devpath, err->message); 233 | g_error_free(err); 234 | return list; 235 | } 236 | 237 | while ((ent = g_dir_read_name(dir))) { 238 | /* ent is an 1 hex character fp_finger code */ 239 | guint64 val; 240 | gchar *endptr; 241 | 242 | if (*ent == 0 || strlen(ent) != 1) 243 | continue; 244 | 245 | val = g_ascii_strtoull(ent, &endptr, 16); 246 | if (endptr == ent || !FP_FINGER_IS_VALID(val)) { 247 | //fp_dbg("skipping print file %s", ent); 248 | continue; 249 | } 250 | 251 | list = g_slist_prepend(list, GINT_TO_POINTER(val)); 252 | } 253 | 254 | g_dir_close(dir); 255 | return list; 256 | } 257 | 258 | GSList *file_storage_discover_prints(struct fp_dscv_dev *dev, const char *username) 259 | { 260 | GSList *list = NULL; 261 | char *base_store = NULL; 262 | char *storedir = NULL; 263 | int r; 264 | 265 | 266 | r = file_storage_get_basestore_for_username(username, &base_store); 267 | 268 | if (r < 0) { 269 | return NULL; 270 | } 271 | 272 | storedir = get_path_to_storedir(fp_driver_get_driver_id(fp_dscv_dev_get_driver(dev)), 273 | fp_dscv_dev_get_devtype(dev), base_store); 274 | 275 | list = scan_dev_storedir(storedir, fp_driver_get_driver_id(fp_dscv_dev_get_driver(dev)), 276 | fp_dscv_dev_get_devtype(dev), list); 277 | 278 | g_free(base_store); 279 | g_free(storedir); 280 | 281 | return list; 282 | } 283 | 284 | int file_storage_init(void) 285 | { 286 | /* Nothing to do */ 287 | return 0; 288 | } 289 | 290 | int file_storage_deinit(void) 291 | { 292 | /* Nothing to do */ 293 | return 0; 294 | } 295 | -------------------------------------------------------------------------------- /src/file_storage.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple file storage for fprintd 3 | * Copyright (C) 2008 Vasily Khoruzhick 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | */ 20 | 21 | #ifndef FILE_STORAGE_H 22 | 23 | #define FILE_STORAGE_H 24 | 25 | int file_storage_print_data_save(struct fp_print_data *data, 26 | enum fp_finger finger, const char *username); 27 | 28 | 29 | int file_storage_print_data_load(struct fp_dev *dev, 30 | enum fp_finger finger, struct fp_print_data **data, const char *username); 31 | 32 | int file_storage_print_data_delete(struct fp_dscv_dev *dev, 33 | enum fp_finger finger, const char *username); 34 | 35 | int file_storage_init(void); 36 | 37 | int file_storage_deinit(void); 38 | 39 | GSList *file_storage_discover_prints(struct fp_dscv_dev *dev, const char *username); 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/fprintd-marshal.list: -------------------------------------------------------------------------------- 1 | VOID:STRING,BOOLEAN 2 | -------------------------------------------------------------------------------- /src/fprintd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * fprintd header file 3 | * Copyright (C) 2008 Daniel Drake 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef __FPRINTD_H__ 21 | #define __FPRINTD_H__ 22 | 23 | #include 24 | #include 25 | 26 | /* General */ 27 | #define TIMEOUT 30 28 | #define FPRINT_SERVICE_NAME "net.reactivated.Fprint" 29 | extern DBusGConnection *fprintd_dbus_conn; 30 | 31 | /* Errors */ 32 | GQuark fprint_error_quark(void); 33 | GType fprint_error_get_type(void); 34 | 35 | #define FPRINT_ERROR fprint_error_quark() 36 | #define FPRINT_TYPE_ERROR fprint_error_get_type() 37 | #define FPRINT_ERROR_DBUS_INTERFACE "net.reactivated.Fprint.Error" 38 | typedef enum { 39 | FPRINT_ERROR_CLAIM_DEVICE, /* developer didn't claim the device */ 40 | FPRINT_ERROR_ALREADY_IN_USE, /* device is already claimed by somebody else */ 41 | FPRINT_ERROR_INTERNAL, /* internal error occured */ 42 | FPRINT_ERROR_PERMISSION_DENIED, /* PolicyKit refused the action */ 43 | FPRINT_ERROR_NO_ENROLLED_PRINTS, /* No prints are enrolled */ 44 | FPRINT_ERROR_NO_ACTION_IN_PROGRESS, /* No actions currently in progress */ 45 | FPRINT_ERROR_INVALID_FINGERNAME, /* the finger name passed was invalid */ 46 | FPRINT_ERROR_NO_SUCH_DEVICE, /* device does not exist */ 47 | } FprintError; 48 | 49 | /* Manager */ 50 | #define FPRINT_TYPE_MANAGER (fprint_manager_get_type()) 51 | #define FPRINT_MANAGER(object) (G_TYPE_CHECK_INSTANCE_CAST((object), FPRINT_TYPE_MANAGER, FprintManager)) 52 | #define FPRINT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), FPRINT_TYPE_MANAGER, FprintManagerClass)) 53 | #define FPRINT_IS_MANAGER(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), FPRINT_TYPE_MANAGER)) 54 | #define FPRINT_IS_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), FPRINT_TYPE_MANAGER)) 55 | #define FPRINT_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), FPRINT_TYPE_MANAGER, FprintManagerClass)) 56 | 57 | struct FprintManager { 58 | GObject parent; 59 | }; 60 | 61 | struct FprintManagerClass { 62 | GObjectClass parent; 63 | }; 64 | 65 | typedef struct FprintManager FprintManager; 66 | typedef struct FprintManagerClass FprintManagerClass; 67 | 68 | FprintManager *fprint_manager_new(gboolean no_timeout); 69 | GType fprint_manager_get_type(void); 70 | 71 | /* Device */ 72 | #define FPRINT_TYPE_DEVICE (fprint_device_get_type()) 73 | #define FPRINT_DEVICE(object) (G_TYPE_CHECK_INSTANCE_CAST((object), FPRINT_DEVICE_TYPE, FprintDevice)) 74 | #define FPRINT_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), FPRINT_DEVICE_TYPE, FprintDeviceClass)) 75 | #define FPRINT_IS_DEVICE(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), FPRINT_TYPE_DEVICE)) 76 | #define FPRINT_IS_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), FPRINT_TYPE_DEVICE)) 77 | #define FPRINT_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), FPRINT_TYPE_DEVICE, FprintDeviceClass)) 78 | 79 | struct FprintDevice { 80 | GObject parent; 81 | }; 82 | 83 | struct FprintDeviceClass { 84 | GObjectClass parent; 85 | }; 86 | 87 | typedef struct FprintDevice FprintDevice; 88 | typedef struct FprintDeviceClass FprintDeviceClass; 89 | 90 | FprintDevice *fprint_device_new(struct fp_dscv_dev *ddev); 91 | GType fprint_device_get_type(void); 92 | guint32 _fprint_device_get_id(FprintDevice *rdev); 93 | /* Print */ 94 | /* TODO */ 95 | 96 | /* Binding data included in main.c thorugh server-bindings.h which individual 97 | * class implementations need to access. 98 | */ 99 | extern const DBusGObjectInfo dbus_glib_fprint_manager_object_info; 100 | extern const DBusGObjectInfo dbus_glib_fprint_device_object_info; 101 | 102 | #endif 103 | 104 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * fprint D-Bus daemon 3 | * Copyright (C) 2008 Daniel Drake 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include "config.h" 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "fprintd.h" 33 | #include "storage.h" 34 | #include "file_storage.h" 35 | 36 | extern DBusGConnection *fprintd_dbus_conn; 37 | static gboolean no_timeout = FALSE; 38 | static gboolean g_fatal_warnings = FALSE; 39 | 40 | struct fdsource { 41 | GSource source; 42 | GSList *pollfds; 43 | }; 44 | 45 | static gboolean source_prepare(GSource *source, gint *timeout) 46 | { 47 | int r; 48 | struct timeval tv; 49 | 50 | r = fp_get_next_timeout(&tv); 51 | if (r == 0) { 52 | *timeout = -1; 53 | return FALSE; 54 | } 55 | 56 | if (!timerisset(&tv)) 57 | return TRUE; 58 | 59 | *timeout = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); 60 | return FALSE; 61 | } 62 | 63 | static gboolean source_check(GSource *source) 64 | { 65 | struct fdsource *_fdsource = (struct fdsource *) source; 66 | GSList *elem = _fdsource->pollfds; 67 | struct timeval tv; 68 | int r; 69 | 70 | if (!elem) 71 | return FALSE; 72 | 73 | do { 74 | GPollFD *pollfd = elem->data; 75 | if (pollfd->revents) 76 | return TRUE; 77 | } while ((elem = g_slist_next(elem))); 78 | 79 | r = fp_get_next_timeout(&tv); 80 | if (r == 1 && !timerisset(&tv)) 81 | return TRUE; 82 | 83 | return FALSE; 84 | } 85 | 86 | static gboolean source_dispatch(GSource *source, GSourceFunc callback, 87 | gpointer data) 88 | { 89 | struct timeval zerotimeout = { 90 | .tv_sec = 0, 91 | .tv_usec = 0, 92 | }; 93 | 94 | /* FIXME error handling */ 95 | fp_handle_events_timeout(&zerotimeout); 96 | 97 | /* FIXME whats the return value used for? */ 98 | return TRUE; 99 | } 100 | 101 | static void source_finalize(GSource *source) 102 | { 103 | struct fdsource *_fdsource = (struct fdsource *) source; 104 | GSList *elem = _fdsource->pollfds; 105 | 106 | if (elem) 107 | do { 108 | GPollFD *pollfd = elem->data; 109 | g_source_remove_poll((GSource *) _fdsource, pollfd); 110 | g_slice_free(GPollFD, pollfd); 111 | _fdsource->pollfds = g_slist_delete_link(_fdsource->pollfds, elem); 112 | } while ((elem = g_slist_next(elem))); 113 | 114 | g_slist_free(_fdsource->pollfds); 115 | } 116 | 117 | static GSourceFuncs sourcefuncs = { 118 | .prepare = source_prepare, 119 | .check = source_check, 120 | .dispatch = source_dispatch, 121 | .finalize = source_finalize, 122 | }; 123 | 124 | static struct fdsource *fdsource = NULL; 125 | 126 | static void pollfd_add(int fd, short events) 127 | { 128 | GPollFD *pollfd = g_slice_new(GPollFD); 129 | pollfd->fd = fd; 130 | pollfd->events = 0; 131 | pollfd->revents = 0; 132 | if (events & POLLIN) 133 | pollfd->events |= G_IO_IN; 134 | if (events & POLLOUT) 135 | pollfd->events |= G_IO_OUT; 136 | 137 | fdsource->pollfds = g_slist_prepend(fdsource->pollfds, pollfd); 138 | g_source_add_poll((GSource *) fdsource, pollfd); 139 | } 140 | 141 | static void pollfd_added_cb(int fd, short events) 142 | { 143 | g_message("now monitoring fd %d", fd); 144 | pollfd_add(fd, events); 145 | } 146 | 147 | static void pollfd_removed_cb(int fd) 148 | { 149 | GSList *elem = fdsource->pollfds; 150 | g_message("no longer monitoring fd %d", fd); 151 | 152 | if (!elem) { 153 | g_warning("cannot remove from list as list is empty?"); 154 | return; 155 | } 156 | 157 | do { 158 | GPollFD *pollfd = elem->data; 159 | if (pollfd->fd != fd) 160 | continue; 161 | 162 | g_source_remove_poll((GSource *) fdsource, pollfd); 163 | g_slice_free(GPollFD, pollfd); 164 | fdsource->pollfds = g_slist_delete_link(fdsource->pollfds, elem); 165 | return; 166 | } while ((elem = g_slist_next(elem))); 167 | 168 | g_error("couldn't find fd %d in list\n", fd); 169 | } 170 | 171 | static int setup_pollfds(void) 172 | { 173 | size_t numfds; 174 | size_t i; 175 | struct fp_pollfd *fpfds; 176 | GSource *gsource = g_source_new(&sourcefuncs, sizeof(struct fdsource)); 177 | 178 | fdsource = (struct fdsource *) gsource; 179 | fdsource->pollfds = NULL; 180 | 181 | numfds = fp_get_pollfds(&fpfds); 182 | if (numfds < 0) { 183 | if (fpfds) 184 | free(fpfds); 185 | return (int) numfds; 186 | } else if (numfds > 0) { 187 | for (i = 0; i < numfds; i++) { 188 | struct fp_pollfd *fpfd = &fpfds[i]; 189 | pollfd_add(fpfd->fd, fpfd->events); 190 | } 191 | } 192 | 193 | free(fpfds); 194 | fp_set_pollfd_notifiers(pollfd_added_cb, pollfd_removed_cb); 195 | g_source_attach(gsource, NULL); 196 | return 0; 197 | } 198 | 199 | static void 200 | set_storage_file (void) 201 | { 202 | store.init = &file_storage_init; 203 | store.deinit = &file_storage_deinit; 204 | store.print_data_save = &file_storage_print_data_save; 205 | store.print_data_load = &file_storage_print_data_load; 206 | store.print_data_delete = &file_storage_print_data_delete; 207 | store.discover_prints = &file_storage_discover_prints; 208 | } 209 | 210 | static gboolean 211 | load_storage_module (const char *module_name) 212 | { 213 | GModule *module; 214 | char *filename; 215 | 216 | filename = g_module_build_path (PLUGINDIR, module_name); 217 | module = g_module_open (filename, 0); 218 | g_free (filename); 219 | if (module == NULL) 220 | return FALSE; 221 | 222 | if (!g_module_symbol (module, "init", (gpointer *) &store.init) || 223 | !g_module_symbol (module, "deinit", (gpointer *) &store.deinit) || 224 | !g_module_symbol (module, "print_data_save", (gpointer *) &store.print_data_save) || 225 | !g_module_symbol (module, "print_data_load", (gpointer *) &store.print_data_load) || 226 | !g_module_symbol (module, "print_data_delete", (gpointer *) &store.print_data_delete) || 227 | !g_module_symbol (module, "discover_prints", (gpointer *) &store.discover_prints)) { 228 | g_module_close (module); 229 | return FALSE; 230 | } 231 | 232 | g_module_make_resident (module); 233 | 234 | return TRUE; 235 | } 236 | 237 | static gboolean 238 | load_conf (void) 239 | { 240 | GKeyFile *file; 241 | char *filename; 242 | char *module_name; 243 | GError *error = NULL; 244 | gboolean ret; 245 | 246 | filename = g_build_filename (SYSCONFDIR, "fprintd.conf", NULL); 247 | file = g_key_file_new (); 248 | if (!g_key_file_load_from_file (file, filename, G_KEY_FILE_NONE, &error)) { 249 | g_print ("Could not open fprintd.conf: %s\n", error->message); 250 | goto bail; 251 | } 252 | 253 | g_free (filename); 254 | filename = NULL; 255 | 256 | module_name = g_key_file_get_string (file, "storage", "type", &error); 257 | if (module_name == NULL) 258 | goto bail; 259 | 260 | g_key_file_free (file); 261 | 262 | if (g_str_equal (module_name, "file")) { 263 | g_free (module_name); 264 | set_storage_file (); 265 | return TRUE; 266 | } 267 | 268 | ret = load_storage_module (module_name); 269 | g_free (module_name); 270 | 271 | return ret; 272 | 273 | bail: 274 | g_key_file_free (file); 275 | g_free (filename); 276 | g_error_free (error); 277 | 278 | return FALSE; 279 | } 280 | 281 | static const GOptionEntry entries[] = { 282 | {"g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &g_fatal_warnings, "Make all warnings fatal", NULL}, 283 | {"no-timeout", 't', 0, G_OPTION_ARG_NONE, &no_timeout, "Do not exit after unused for a while", NULL}, 284 | { NULL } 285 | }; 286 | 287 | int main(int argc, char **argv) 288 | { 289 | GOptionContext *context; 290 | GMainLoop *loop; 291 | GError *error = NULL; 292 | FprintManager *manager; 293 | DBusGProxy *driver_proxy; 294 | guint32 request_name_ret; 295 | int r = 0; 296 | 297 | bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); 298 | bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); 299 | textdomain (GETTEXT_PACKAGE); 300 | 301 | context = g_option_context_new ("Fingerprint handler daemon"); 302 | g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); 303 | g_type_init(); 304 | 305 | if (g_option_context_parse (context, &argc, &argv, &error) == FALSE) { 306 | g_print ("couldn't parse command-line options: %s\n", error->message); 307 | g_error_free (error); 308 | return 1; 309 | } 310 | 311 | if (g_fatal_warnings) { 312 | GLogLevelFlags fatal_mask; 313 | 314 | fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK); 315 | fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL; 316 | g_log_set_always_fatal (fatal_mask); 317 | } 318 | 319 | /* Load the configuration file, 320 | * and the default storage plugin */ 321 | if (!load_conf()) 322 | set_storage_file (); 323 | store.init (); 324 | 325 | r = fp_init(); 326 | if (r < 0) { 327 | g_error("fprint init failed with error %d\n", r); 328 | return r; 329 | } 330 | 331 | loop = g_main_loop_new(NULL, FALSE); 332 | 333 | r = setup_pollfds(); 334 | if (r < 0) { 335 | g_print("pollfd setup failed\n"); 336 | goto err; 337 | } 338 | 339 | g_print("Launching FprintObject\n"); 340 | 341 | /* Obtain a connection to the session bus */ 342 | fprintd_dbus_conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error); 343 | if (fprintd_dbus_conn == NULL) 344 | g_error("Failed to open connection to bus: %s", error->message); 345 | 346 | /* create the one instance of the Manager object to be shared between 347 | * all fprintd users */ 348 | manager = fprint_manager_new(no_timeout); 349 | 350 | driver_proxy = dbus_g_proxy_new_for_name(fprintd_dbus_conn, 351 | DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); 352 | 353 | if (!org_freedesktop_DBus_request_name(driver_proxy, FPRINT_SERVICE_NAME, 354 | 0, &request_name_ret, &error)) 355 | g_error("Failed to get name: %s", error->message); 356 | 357 | if (request_name_ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { 358 | g_error ("Got result code %u from requesting name", request_name_ret); 359 | exit(1); 360 | } 361 | 362 | g_message("D-Bus service launched with name: %s", FPRINT_SERVICE_NAME); 363 | 364 | g_message("entering main loop"); 365 | g_main_loop_run(loop); 366 | g_message("main loop completed"); 367 | 368 | err: 369 | fp_exit(); 370 | return 0; 371 | } 372 | 373 | -------------------------------------------------------------------------------- /src/manager.c: -------------------------------------------------------------------------------- 1 | /* 2 | * /net/reactivated/Fprint/Manager object implementation 3 | * Copyright (C) 2008 Daniel Drake 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "fprintd.h" 29 | 30 | DBusGConnection *fprintd_dbus_conn; 31 | 32 | static gboolean fprint_manager_get_devices(FprintManager *manager, 33 | GPtrArray **devices, GError **error); 34 | static gboolean fprint_manager_get_default_device(FprintManager *manager, 35 | const char **device, GError **error); 36 | #include "manager-dbus-glue.h" 37 | 38 | static GObjectClass *parent_class = NULL; 39 | 40 | G_DEFINE_TYPE(FprintManager, fprint_manager, G_TYPE_OBJECT); 41 | 42 | typedef struct 43 | { 44 | GSList *dev_registry; 45 | gboolean no_timeout; 46 | guint timeout_id; 47 | } FprintManagerPrivate; 48 | 49 | #define FPRINT_MANAGER_GET_PRIVATE(o) \ 50 | (G_TYPE_INSTANCE_GET_PRIVATE ((o), FPRINT_TYPE_MANAGER, FprintManagerPrivate)) 51 | 52 | static void fprint_manager_finalize(GObject *object) 53 | { 54 | FprintManagerPrivate *priv = FPRINT_MANAGER_GET_PRIVATE (object); 55 | 56 | g_slist_free(priv->dev_registry); 57 | 58 | G_OBJECT_CLASS(parent_class)->finalize(object); 59 | } 60 | 61 | static void fprint_manager_class_init(FprintManagerClass *klass) 62 | { 63 | dbus_g_object_type_install_info(FPRINT_TYPE_MANAGER, 64 | &dbus_glib_fprint_manager_object_info); 65 | dbus_g_error_domain_register (FPRINT_ERROR, FPRINT_ERROR_DBUS_INTERFACE, FPRINT_TYPE_ERROR); 66 | 67 | g_type_class_add_private ((GObjectClass *) klass, sizeof (FprintManagerPrivate)); 68 | 69 | G_OBJECT_CLASS(klass)->finalize = fprint_manager_finalize; 70 | parent_class = g_type_class_peek_parent(klass); 71 | } 72 | 73 | static gchar *get_device_path(FprintDevice *rdev) 74 | { 75 | return g_strdup_printf("/net/reactivated/Fprint/Device/%d", 76 | _fprint_device_get_id(rdev)); 77 | } 78 | 79 | static gboolean 80 | fprint_manager_timeout_cb (FprintManager *manager) 81 | { 82 | g_message ("No devices in use, exit"); 83 | //FIXME kill all the devices 84 | exit(0); 85 | return FALSE; 86 | } 87 | 88 | static void 89 | fprint_manager_in_use_notified (FprintDevice *rdev, GParamSpec *spec, FprintManager *manager) 90 | { 91 | FprintManagerPrivate *priv = FPRINT_MANAGER_GET_PRIVATE (manager); 92 | guint num_devices_used = 0; 93 | GSList *l; 94 | gboolean in_use; 95 | 96 | if (priv->timeout_id > 0) { 97 | g_source_remove (priv->timeout_id); 98 | priv->timeout_id = 0; 99 | } 100 | if (priv->no_timeout) 101 | return; 102 | 103 | for (l = priv->dev_registry; l != NULL; l = l->next) { 104 | FprintDevice *dev = l->data; 105 | 106 | g_object_get (G_OBJECT(dev), "in-use", &in_use, NULL); 107 | if (in_use != FALSE) 108 | num_devices_used++; 109 | } 110 | 111 | if (num_devices_used == 0) 112 | priv->timeout_id = g_timeout_add_seconds (TIMEOUT, (GSourceFunc) fprint_manager_timeout_cb, manager); 113 | } 114 | 115 | static void 116 | fprint_manager_init (FprintManager *manager) 117 | { 118 | FprintManagerPrivate *priv = FPRINT_MANAGER_GET_PRIVATE (manager); 119 | struct fp_dscv_dev **discovered_devs = fp_discover_devs(); 120 | struct fp_dscv_dev *ddev; 121 | int i = 0; 122 | 123 | dbus_g_connection_register_g_object(fprintd_dbus_conn, 124 | "/net/reactivated/Fprint/Manager", G_OBJECT(manager)); 125 | 126 | if (discovered_devs == NULL) 127 | return; 128 | 129 | while ((ddev = discovered_devs[i++]) != NULL) { 130 | FprintDevice *rdev = fprint_device_new(ddev); 131 | gchar *path; 132 | 133 | g_signal_connect (G_OBJECT(rdev), "notify::in-use", 134 | G_CALLBACK (fprint_manager_in_use_notified), manager); 135 | 136 | priv->dev_registry = g_slist_prepend(priv->dev_registry, rdev); 137 | path = get_device_path(rdev); 138 | dbus_g_connection_register_g_object(fprintd_dbus_conn, path, 139 | G_OBJECT(rdev)); 140 | g_free(path); 141 | } 142 | } 143 | 144 | FprintManager *fprint_manager_new(gboolean no_timeout) 145 | { 146 | FprintManagerPrivate *priv; 147 | GObject *object; 148 | 149 | object = g_object_new(FPRINT_TYPE_MANAGER, NULL); 150 | priv = FPRINT_MANAGER_GET_PRIVATE (object); 151 | priv->no_timeout = no_timeout; 152 | 153 | if (!priv->no_timeout) 154 | priv->timeout_id = g_timeout_add_seconds (TIMEOUT, (GSourceFunc) fprint_manager_timeout_cb, object); 155 | 156 | return FPRINT_MANAGER (object); 157 | } 158 | 159 | static gboolean fprint_manager_get_devices(FprintManager *manager, 160 | GPtrArray **devices, GError **error) 161 | { 162 | FprintManagerPrivate *priv = FPRINT_MANAGER_GET_PRIVATE (manager); 163 | GSList *elem = priv->dev_registry; 164 | int num_open = g_slist_length(elem); 165 | GPtrArray *devs = g_ptr_array_sized_new(num_open); 166 | 167 | if (num_open > 0) 168 | do { 169 | FprintDevice *rdev = elem->data; 170 | g_ptr_array_add(devs, get_device_path(rdev)); 171 | } while ((elem = g_slist_next(elem)) != NULL); 172 | 173 | *devices = devs; 174 | return TRUE; 175 | } 176 | 177 | static gboolean fprint_manager_get_default_device(FprintManager *manager, 178 | const char **device, GError **error) 179 | { 180 | FprintManagerPrivate *priv = FPRINT_MANAGER_GET_PRIVATE (manager); 181 | GSList *elem = priv->dev_registry; 182 | int num_open = g_slist_length(elem); 183 | 184 | if (num_open > 0) { 185 | *device = get_device_path (elem->data); 186 | return TRUE; 187 | } else { 188 | g_set_error (error, FPRINT_ERROR, FPRINT_ERROR_NO_SUCH_DEVICE, 189 | "No devices available"); 190 | *device = NULL; 191 | return FALSE; 192 | } 193 | } 194 | 195 | GQuark fprint_error_quark(void) 196 | { 197 | static GQuark quark = 0; 198 | if (!quark) 199 | quark = g_quark_from_static_string("fprintd-error-quark"); 200 | return quark; 201 | } 202 | 203 | #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } 204 | GType 205 | fprint_error_get_type (void) 206 | { 207 | static GType etype = 0; 208 | 209 | if (etype == 0) { 210 | static const GEnumValue values[] = 211 | { 212 | ENUM_ENTRY (FPRINT_ERROR_CLAIM_DEVICE, "ClaimDevice"), 213 | ENUM_ENTRY (FPRINT_ERROR_ALREADY_IN_USE, "AlreadyInUse"), 214 | ENUM_ENTRY (FPRINT_ERROR_INTERNAL, "Internal"), 215 | ENUM_ENTRY (FPRINT_ERROR_PERMISSION_DENIED, "PermissionDenied"), 216 | ENUM_ENTRY (FPRINT_ERROR_NO_ENROLLED_PRINTS, "NoEnrolledPrints"), 217 | ENUM_ENTRY (FPRINT_ERROR_NO_ACTION_IN_PROGRESS, "NoActionInProgress"), 218 | ENUM_ENTRY (FPRINT_ERROR_INVALID_FINGERNAME, "InvalidFingername"), 219 | ENUM_ENTRY (FPRINT_ERROR_NO_SUCH_DEVICE, "NoSuchDevice"), 220 | { 0, 0, 0 } 221 | }; 222 | etype = g_enum_register_static ("FprintError", values); 223 | } 224 | return etype; 225 | } 226 | -------------------------------------------------------------------------------- /src/manager.xml: -------------------------------------------------------------------------------- 1 | 5 | ]> 6 | 7 | 8 | 10 | 11 | 12 | 13 | 14 | 15 | An array of object paths for devices. 16 | 17 | 18 | 19 | 20 | 21 | Enumerate all the fingerprint readers attached to the system. If there are 22 | no devices available, an empty array is returned. 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | The object path for the default device. 33 | 34 | 35 | 36 | 37 | 38 | Returns the default fingerprint reader device. 39 | 40 | 41 | 42 | 43 | if the device does not exist 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/storage.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Simple file storage for fprintd 3 | * Copyright (C) 2008 Vasily Khoruzhick 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | * 19 | */ 20 | 21 | #ifndef STORAGE_H 22 | 23 | #define STORAGE_H 24 | 25 | typedef int (*storage_print_data_save)(struct fp_print_data *data, 26 | enum fp_finger finger, const char *username); 27 | typedef int (*storage_print_data_load)(struct fp_dev *dev, 28 | enum fp_finger finger, struct fp_print_data **data, const char *username); 29 | typedef int (*storage_print_data_delete)(struct fp_dscv_dev *dev, 30 | enum fp_finger finger, const char *username); 31 | typedef GSList *(*storage_discover_prints)(struct fp_dscv_dev *dev, const char *username); 32 | typedef int (*storage_init)(void); 33 | typedef int (*storage_deinit)(void); 34 | 35 | struct storage { 36 | storage_init init; 37 | storage_deinit deinit; 38 | storage_print_data_save print_data_save; 39 | storage_print_data_load print_data_load; 40 | storage_print_data_delete print_data_delete; 41 | storage_discover_prints discover_prints; 42 | }; 43 | 44 | typedef struct storage fp_storage; 45 | 46 | /* The currently setup store */ 47 | fp_storage store; 48 | 49 | #endif 50 | 51 | -------------------------------------------------------------------------------- /tests/Makefile.am: -------------------------------------------------------------------------------- 1 | BUILT_SOURCES = manager-dbus-glue.h device-dbus-glue.h $(MARSHALFILES) 2 | noinst_HEADERS = $(BUILT_SOURCES) 3 | CLEANFILES = $(BUILT_SOURCES) 4 | 5 | bin_PROGRAMS = fprintd-verify fprintd-enroll fprintd-list fprintd-delete 6 | 7 | fprintd_verify_SOURCES = verify.c $(MARSHALFILES) 8 | fprintd_verify_CFLAGS = $(WARN_CFLAGS) $(GLIB_CFLAGS) 9 | fprintd_verify_LDADD = $(GLIB_LIBS) 10 | 11 | fprintd_enroll_SOURCES = enroll.c $(MARSHALFILES) 12 | fprintd_enroll_CFLAGS = $(WARN_CFLAGS) $(GLIB_CFLAGS) 13 | fprintd_enroll_LDADD = $(GLIB_LIBS) 14 | 15 | fprintd_list_SOURCES = list.c 16 | fprintd_list_CFLAGS = $(WARN_CFLAGS) $(GLIB_CFLAGS) 17 | fprintd_list_LDADD = $(GLIB_LIBS) 18 | 19 | fprintd_delete_SOURCES = delete.c 20 | fprintd_delete_CFLAGS = $(WARN_CFLAGS) $(GLIB_CFLAGS) 21 | fprintd_delete_LDADD = $(GLIB_LIBS) 22 | 23 | manager-dbus-glue.h: ../src/manager.xml 24 | dbus-binding-tool --prefix=fprint_manager --mode=glib-client $< --output=$@ 25 | 26 | device-dbus-glue.h: ../src/device.xml 27 | dbus-binding-tool --prefix=fprint_device --mode=glib-client $< --output=$@ 28 | 29 | MARSHALFILES = marshal.c marshal.h 30 | GLIB_GENMARSHAL=`pkg-config --variable=glib_genmarshal glib-2.0` 31 | 32 | marshal.h: $(top_srcdir)/src/fprintd-marshal.list 33 | ( $(GLIB_GENMARSHAL) --prefix=fprintd_marshal $(top_srcdir)/src/fprintd-marshal.list --header > marshal.h ) 34 | marshal.c: marshal.h 35 | ( $(GLIB_GENMARSHAL) --prefix=fprintd_marshal $(top_srcdir)/src/fprintd-marshal.list --body --header > marshal.c ) 36 | -------------------------------------------------------------------------------- /tests/delete.c: -------------------------------------------------------------------------------- 1 | /* 2 | * fprintd example to delete fingerprints 3 | * Copyright (C) 2008 Daniel Drake 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include "manager-dbus-glue.h" 24 | #include "device-dbus-glue.h" 25 | 26 | static DBusGProxy *manager = NULL; 27 | static DBusGConnection *connection = NULL; 28 | 29 | static void create_manager(void) 30 | { 31 | GError *error = NULL; 32 | 33 | connection = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error); 34 | if (connection == NULL) 35 | g_error("Failed to connect to session bus: %s", error->message); 36 | 37 | manager = dbus_g_proxy_new_for_name(connection, 38 | "net.reactivated.Fprint", "/net/reactivated/Fprint/Manager", 39 | "net.reactivated.Fprint.Manager"); 40 | } 41 | 42 | static void delete_fingerprints(DBusGProxy *dev, const char *username) 43 | { 44 | GError *error = NULL; 45 | GHashTable *props; 46 | DBusGProxy *p; 47 | 48 | p = dbus_g_proxy_new_from_proxy(dev, "org.freedesktop.DBus.Properties", NULL); 49 | if (!dbus_g_proxy_call (p, "GetAll", &error, G_TYPE_STRING, "net.reactivated.Fprint.Device", G_TYPE_INVALID, 50 | dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), &props, G_TYPE_INVALID)) 51 | g_error("GetAll on the Properties interface failed: %s", error->message); 52 | 53 | if (!net_reactivated_Fprint_Device_delete_enrolled_fingers(dev, username, &error)) { 54 | if (dbus_g_error_has_name (error, "net.reactivated.Fprint.Error.NoEnrolledPrints") == FALSE) 55 | g_error("ListEnrolledFingers failed: %s", error->message); 56 | else 57 | g_print ("No fingerprints to delete on %s\n", g_value_get_string (g_hash_table_lookup (props, "name"))); 58 | } else { 59 | g_print ("Fingerprints deleted on %s\n", g_value_get_string (g_hash_table_lookup (props, "name"))); 60 | } 61 | g_hash_table_destroy (props); 62 | g_object_unref (p); 63 | } 64 | 65 | static void process_devices(char **argv) 66 | { 67 | GError *error = NULL; 68 | GPtrArray *devices; 69 | char *path; 70 | guint i; 71 | 72 | if (!net_reactivated_Fprint_Manager_get_devices(manager, &devices, &error)) 73 | g_error("list_devices failed: %s", error->message); 74 | 75 | if (devices->len == 0) { 76 | g_print("No devices found\n"); 77 | exit(1); 78 | } 79 | 80 | g_print("found %d devices\n", devices->len); 81 | for (i = 0; i < devices->len; i++) { 82 | path = g_ptr_array_index(devices, i); 83 | g_print("Device at %s\n", path); 84 | } 85 | 86 | for (i = 0; i < devices->len; i++) { 87 | guint j; 88 | DBusGProxy *dev; 89 | 90 | path = g_ptr_array_index(devices, 0); 91 | g_print("Using device %s\n", path); 92 | 93 | /* FIXME use for_name_owner?? */ 94 | dev = dbus_g_proxy_new_for_name(connection, "net.reactivated.Fprint", 95 | path, "net.reactivated.Fprint.Device"); 96 | 97 | for (j = 1; argv[j] != NULL; j++) 98 | delete_fingerprints (dev, argv[j]); 99 | 100 | g_object_unref (dev); 101 | } 102 | 103 | g_ptr_array_foreach(devices, (GFunc) g_free, NULL); 104 | g_ptr_array_free(devices, TRUE); 105 | } 106 | 107 | int main(int argc, char **argv) 108 | { 109 | GMainLoop *loop; 110 | 111 | g_type_init(); 112 | loop = g_main_loop_new(NULL, FALSE); 113 | create_manager(); 114 | 115 | if (argc < 2) { 116 | g_print ("Usage: %s [usernames...]\n", argv[0]); 117 | return 1; 118 | } 119 | 120 | process_devices (argv); 121 | 122 | return 0; 123 | } 124 | 125 | -------------------------------------------------------------------------------- /tests/enroll.c: -------------------------------------------------------------------------------- 1 | /* 2 | * fprintd example to enroll right index finger 3 | * Copyright (C) 2008 Daniel Drake 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include 21 | #include 22 | #include "manager-dbus-glue.h" 23 | #include "device-dbus-glue.h" 24 | #include "marshal.h" 25 | 26 | static DBusGProxy *manager = NULL; 27 | static DBusGConnection *connection = NULL; 28 | 29 | static void create_manager(void) 30 | { 31 | GError *error = NULL; 32 | 33 | connection = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error); 34 | if (connection == NULL) 35 | g_error("Failed to connect to session bus: %s", error->message); 36 | 37 | manager = dbus_g_proxy_new_for_name(connection, 38 | "net.reactivated.Fprint", "/net/reactivated/Fprint/Manager", 39 | "net.reactivated.Fprint.Manager"); 40 | } 41 | 42 | static DBusGProxy *open_device(const char *username) 43 | { 44 | GError *error = NULL; 45 | gchar *path; 46 | DBusGProxy *dev; 47 | 48 | if (!net_reactivated_Fprint_Manager_get_default_device(manager, &path, &error)) 49 | g_error("list_devices failed: %s", error->message); 50 | 51 | if (path == NULL) { 52 | g_print("No devices found\n"); 53 | exit(1); 54 | } 55 | 56 | g_print("Using device %s\n", path); 57 | 58 | /* FIXME use for_name_owner?? */ 59 | dev = dbus_g_proxy_new_for_name(connection, "net.reactivated.Fprint", 60 | path, "net.reactivated.Fprint.Device"); 61 | 62 | g_free (path); 63 | 64 | if (!net_reactivated_Fprint_Device_claim(dev, username, &error)) 65 | g_error("failed to claim device: %s", error->message); 66 | return dev; 67 | } 68 | 69 | static void enroll_result(GObject *object, const char *result, gboolean done, void *user_data) 70 | { 71 | gboolean *enroll_completed = user_data; 72 | g_print("Enroll result: %s\n", result); 73 | if (done != FALSE) 74 | *enroll_completed = TRUE; 75 | } 76 | 77 | static void do_enroll(DBusGProxy *dev) 78 | { 79 | GError *error; 80 | gboolean enroll_completed = FALSE; 81 | 82 | dbus_g_proxy_add_signal(dev, "EnrollStatus", G_TYPE_STRING, G_TYPE_BOOLEAN, NULL); 83 | dbus_g_proxy_connect_signal(dev, "EnrollStatus", G_CALLBACK(enroll_result), 84 | &enroll_completed, NULL); 85 | 86 | g_print("Enrolling right index finger.\n"); 87 | if (!net_reactivated_Fprint_Device_enroll_start(dev, "right-index-finger", &error)) 88 | g_error("EnrollStart failed: %s", error->message); 89 | 90 | while (!enroll_completed) 91 | g_main_context_iteration(NULL, TRUE); 92 | 93 | dbus_g_proxy_disconnect_signal(dev, "EnrollStatus", 94 | G_CALLBACK(enroll_result), &enroll_completed); 95 | 96 | if (!net_reactivated_Fprint_Device_enroll_stop(dev, &error)) 97 | g_error("VerifyStop failed: %s", error->message); 98 | } 99 | 100 | static void release_device(DBusGProxy *dev) 101 | { 102 | GError *error = NULL; 103 | if (!net_reactivated_Fprint_Device_release(dev, &error)) 104 | g_error("ReleaseDevice failed: %s", error->message); 105 | } 106 | 107 | int main(int argc, char **argv) 108 | { 109 | GMainLoop *loop; 110 | DBusGProxy *dev; 111 | char *username; 112 | 113 | g_type_init(); 114 | 115 | dbus_g_object_register_marshaller (fprintd_marshal_VOID__STRING_BOOLEAN, 116 | G_TYPE_NONE, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_INVALID); 117 | 118 | loop = g_main_loop_new(NULL, FALSE); 119 | create_manager(); 120 | 121 | username = NULL; 122 | if (argc == 2) 123 | username = argv[1]; 124 | dev = open_device(username); 125 | do_enroll(dev); 126 | release_device(dev); 127 | return 0; 128 | } 129 | 130 | -------------------------------------------------------------------------------- /tests/list.c: -------------------------------------------------------------------------------- 1 | /* 2 | * fprintd example to list enrolled fingerprints 3 | * Copyright (C) 2008 Daniel Drake 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include "manager-dbus-glue.h" 24 | #include "device-dbus-glue.h" 25 | 26 | static DBusGProxy *manager = NULL; 27 | static DBusGConnection *connection = NULL; 28 | 29 | static void create_manager(void) 30 | { 31 | GError *error = NULL; 32 | 33 | connection = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error); 34 | if (connection == NULL) 35 | g_error("Failed to connect to session bus: %s", error->message); 36 | 37 | manager = dbus_g_proxy_new_for_name(connection, 38 | "net.reactivated.Fprint", "/net/reactivated/Fprint/Manager", 39 | "net.reactivated.Fprint.Manager"); 40 | } 41 | 42 | static void list_fingerprints(DBusGProxy *dev, const char *username) 43 | { 44 | GError *error = NULL; 45 | char **fingers; 46 | GHashTable *props; 47 | DBusGProxy *p; 48 | guint i; 49 | 50 | if (!net_reactivated_Fprint_Device_list_enrolled_fingers(dev, username, &fingers, &error)) { 51 | if (dbus_g_error_has_name (error, "net.reactivated.Fprint.Error.NoEnrolledPrints") == FALSE) 52 | g_error("ListEnrolledFingers failed: %s", error->message); 53 | else 54 | fingers = NULL; 55 | } 56 | 57 | p = dbus_g_proxy_new_from_proxy(dev, "org.freedesktop.DBus.Properties", NULL); 58 | if (!dbus_g_proxy_call (p, "GetAll", &error, G_TYPE_STRING, "net.reactivated.Fprint.Device", G_TYPE_INVALID, 59 | dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), &props, G_TYPE_INVALID)) 60 | g_error("GetAll on the Properties interface failed: %s", error->message); 61 | 62 | if (fingers == NULL || g_strv_length (fingers) == 0) { 63 | g_print("User %s has no fingers enrolled for %s.\n", username, g_value_get_string (g_hash_table_lookup (props, "name"))); 64 | return; 65 | } 66 | 67 | g_print("Fingerprints for user %s on %s (%s):\n", 68 | username, 69 | g_value_get_string (g_hash_table_lookup (props, "name")), 70 | g_value_get_string (g_hash_table_lookup (props, "scan-type"))); 71 | g_hash_table_destroy (props); 72 | g_object_unref (p); 73 | 74 | for (i = 0; fingers[i] != NULL; i++) { 75 | g_print(" - #%d: %s\n", i, fingers[i]); 76 | } 77 | 78 | g_strfreev (fingers); 79 | } 80 | 81 | static void process_devices(char **argv) 82 | { 83 | GError *error = NULL; 84 | GPtrArray *devices; 85 | char *path; 86 | guint i; 87 | 88 | if (!net_reactivated_Fprint_Manager_get_devices(manager, &devices, &error)) 89 | g_error("list_devices failed: %s", error->message); 90 | 91 | if (devices->len == 0) { 92 | g_print("No devices found\n"); 93 | exit(1); 94 | } 95 | 96 | g_print("found %d devices\n", devices->len); 97 | for (i = 0; i < devices->len; i++) { 98 | path = g_ptr_array_index(devices, i); 99 | g_print("Device at %s\n", path); 100 | } 101 | 102 | for (i = 0; i < devices->len; i++) { 103 | guint j; 104 | DBusGProxy *dev; 105 | 106 | path = g_ptr_array_index(devices, 0); 107 | g_print("Using device %s\n", path); 108 | 109 | /* FIXME use for_name_owner?? */ 110 | dev = dbus_g_proxy_new_for_name(connection, "net.reactivated.Fprint", 111 | path, "net.reactivated.Fprint.Device"); 112 | 113 | for (j = 1; argv[j] != NULL; j++) 114 | list_fingerprints (dev, argv[j]); 115 | 116 | g_object_unref (dev); 117 | } 118 | 119 | g_ptr_array_foreach(devices, (GFunc) g_free, NULL); 120 | g_ptr_array_free(devices, TRUE); 121 | } 122 | 123 | int main(int argc, char **argv) 124 | { 125 | GMainLoop *loop; 126 | 127 | g_type_init(); 128 | loop = g_main_loop_new(NULL, FALSE); 129 | create_manager(); 130 | 131 | if (argc < 2) { 132 | g_print ("Usage: %s [usernames...]\n", argv[0]); 133 | return 1; 134 | } 135 | 136 | process_devices (argv); 137 | 138 | return 0; 139 | } 140 | 141 | -------------------------------------------------------------------------------- /tests/verify.c: -------------------------------------------------------------------------------- 1 | /* 2 | * fprintd example to verify a fingerprint 3 | * Copyright (C) 2008 Daniel Drake 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along 16 | * with this program; if not, write to the Free Software Foundation, Inc., 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "manager-dbus-glue.h" 25 | #include "device-dbus-glue.h" 26 | #include "marshal.h" 27 | 28 | static DBusGProxy *manager = NULL; 29 | static DBusGConnection *connection = NULL; 30 | static char *finger_name = "any"; 31 | static gboolean g_fatal_warnings = FALSE; 32 | static char **usernames = NULL; 33 | 34 | static void create_manager(void) 35 | { 36 | GError *error = NULL; 37 | 38 | connection = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error); 39 | if (connection == NULL) 40 | g_error("Failed to connect to session bus: %s", error->message); 41 | 42 | manager = dbus_g_proxy_new_for_name(connection, 43 | "net.reactivated.Fprint", "/net/reactivated/Fprint/Manager", 44 | "net.reactivated.Fprint.Manager"); 45 | } 46 | 47 | static DBusGProxy *open_device(const char *username) 48 | { 49 | GError *error = NULL; 50 | gchar *path; 51 | DBusGProxy *dev; 52 | 53 | if (!net_reactivated_Fprint_Manager_get_default_device(manager, &path, &error)) 54 | g_error("list_devices failed: %s", error->message); 55 | 56 | if (path == NULL) { 57 | g_print("No devices found\n"); 58 | exit(1); 59 | } 60 | 61 | g_print("Using device %s\n", path); 62 | 63 | /* FIXME use for_name_owner?? */ 64 | dev = dbus_g_proxy_new_for_name(connection, "net.reactivated.Fprint", 65 | path, "net.reactivated.Fprint.Device"); 66 | 67 | g_free (path); 68 | 69 | if (!net_reactivated_Fprint_Device_claim(dev, username, &error)) 70 | g_error("failed to claim device: %s", error->message); 71 | 72 | return dev; 73 | } 74 | 75 | static void find_finger(DBusGProxy *dev, const char *username) 76 | { 77 | GError *error = NULL; 78 | char **fingers; 79 | guint i; 80 | 81 | if (!net_reactivated_Fprint_Device_list_enrolled_fingers(dev, username, &fingers, &error)) 82 | g_error("ListEnrolledFingers failed: %s", error->message); 83 | 84 | if (fingers == NULL || g_strv_length (fingers) == 0) { 85 | g_print("No fingers enrolled for this device.\n"); 86 | exit(1); 87 | } 88 | 89 | g_print("Listing enrolled fingers:\n"); 90 | for (i = 0; fingers[i] != NULL; i++) { 91 | g_print(" - #%d: %s\n", i, fingers[i]); 92 | } 93 | 94 | if (strcmp (finger_name, "any") == 0) 95 | finger_name = fingers[0]; 96 | 97 | g_strfreev (fingers); 98 | } 99 | 100 | static void verify_result(GObject *object, const char *result, gboolean done, void *user_data) 101 | { 102 | gboolean *verify_completed = user_data; 103 | g_print("Verify result: %s (%s)\n", result, done ? "done" : "not done"); 104 | if (done != FALSE) 105 | *verify_completed = TRUE; 106 | } 107 | 108 | static void verify_finger_selected(GObject *object, const char *name, void *user_data) 109 | { 110 | g_print("Verifying: %s\n", name); 111 | } 112 | 113 | static void do_verify(DBusGProxy *dev) 114 | { 115 | GError *error; 116 | gboolean verify_completed = FALSE; 117 | 118 | dbus_g_proxy_add_signal(dev, "VerifyStatus", G_TYPE_STRING, G_TYPE_BOOLEAN, NULL); 119 | dbus_g_proxy_add_signal(dev, "VerifyFingerSelected", G_TYPE_INT, NULL); 120 | dbus_g_proxy_connect_signal(dev, "VerifyStatus", G_CALLBACK(verify_result), 121 | &verify_completed, NULL); 122 | dbus_g_proxy_connect_signal(dev, "VerifyFingerSelected", G_CALLBACK(verify_finger_selected), 123 | NULL, NULL); 124 | 125 | if (!net_reactivated_Fprint_Device_verify_start(dev, finger_name, &error)) 126 | g_error("VerifyStart failed: %s", error->message); 127 | 128 | while (!verify_completed) 129 | g_main_context_iteration(NULL, TRUE); 130 | 131 | dbus_g_proxy_disconnect_signal(dev, "VerifyStatus", G_CALLBACK(verify_result), &verify_completed); 132 | dbus_g_proxy_disconnect_signal(dev, "VerifyFingerSelected", G_CALLBACK(verify_finger_selected), NULL); 133 | 134 | if (!net_reactivated_Fprint_Device_verify_stop(dev, &error)) 135 | g_error("VerifyStop failed: %s", error->message); 136 | } 137 | 138 | static void release_device(DBusGProxy *dev) 139 | { 140 | GError *error = NULL; 141 | if (!net_reactivated_Fprint_Device_release(dev, &error)) 142 | g_error("ReleaseDevice failed: %s", error->message); 143 | } 144 | 145 | static const GOptionEntry entries[] = { 146 | { "finger", 'f', 0, G_OPTION_ARG_STRING, &finger_name, "Finger selected to verify (default is automatic)", NULL }, 147 | {"g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &g_fatal_warnings, "Make all warnings fatal", NULL}, 148 | { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &usernames, NULL, "[username]" }, 149 | { NULL } 150 | }; 151 | 152 | int main(int argc, char **argv) 153 | { 154 | GOptionContext *context; 155 | GMainLoop *loop; 156 | GError *err = NULL; 157 | DBusGProxy *dev; 158 | char *username; 159 | 160 | g_type_init(); 161 | 162 | dbus_g_object_register_marshaller (fprintd_marshal_VOID__STRING_BOOLEAN, 163 | G_TYPE_NONE, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_INVALID); 164 | 165 | context = g_option_context_new ("Verify a fingerprint"); 166 | g_option_context_add_main_entries (context, entries, NULL); 167 | 168 | if (g_option_context_parse (context, &argc, &argv, &err) == FALSE) { 169 | g_print ("couldn't parse command-line options: %s\n", err->message); 170 | g_error_free (err); 171 | return 1; 172 | } 173 | 174 | if (usernames == NULL) { 175 | username = ""; 176 | } else { 177 | username = usernames[0]; 178 | } 179 | 180 | if (g_fatal_warnings) { 181 | GLogLevelFlags fatal_mask; 182 | 183 | fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK); 184 | fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL; 185 | g_log_set_always_fatal (fatal_mask); 186 | } 187 | 188 | loop = g_main_loop_new(NULL, FALSE); 189 | create_manager(); 190 | 191 | dev = open_device(username); 192 | find_finger(dev, username); 193 | do_verify(dev); 194 | release_device(dev); 195 | return 0; 196 | } 197 | 198 | --------------------------------------------------------------------------------