Imported Upstream version 1.5.3 upstream/1.5.3
authorAnas Nashif <anas.nashif@intel.com>
Thu, 28 Mar 2013 01:49:10 +0000 (18:49 -0700)
committerAnas Nashif <anas.nashif@intel.com>
Thu, 28 Mar 2013 01:49:10 +0000 (18:49 -0700)
36 files changed:
.gitignore [new file with mode: 0644]
LICENCE.GPL [new file with mode: 0644]
LICENCE.LGPL [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
key.dns_resolver.8 [new file with mode: 0644]
key.dns_resolver.c [new file with mode: 0644]
keyctl.1 [new file with mode: 0644]
keyctl.3 [new file with mode: 0644]
keyctl.c [new file with mode: 0644]
keyctl_chown.3 [new file with mode: 0644]
keyctl_clear.3 [new file with mode: 0644]
keyctl_describe.3 [new file with mode: 0644]
keyctl_get_keyring_ID.3 [new file with mode: 0644]
keyctl_get_security.3 [new file with mode: 0644]
keyctl_instantiate.3 [new file with mode: 0644]
keyctl_join_session_keyring.3 [new file with mode: 0644]
keyctl_link.3 [new file with mode: 0644]
keyctl_read.3 [new file with mode: 0644]
keyctl_revoke.3 [new file with mode: 0644]
keyctl_search.3 [new file with mode: 0644]
keyctl_session_to_parent.3 [new file with mode: 0644]
keyctl_set_reqkey_keyring.3 [new file with mode: 0644]
keyctl_set_timeout.3 [new file with mode: 0644]
keyctl_setperm.3 [new file with mode: 0644]
keyctl_update.3 [new file with mode: 0644]
keyutils.c [new file with mode: 0644]
keyutils.h [new file with mode: 0644]
keyutils.spec [new file with mode: 0644]
recursive_key_scan.3 [new file with mode: 0644]
request-key-debug.sh [new file with mode: 0755]
request-key.8 [new file with mode: 0644]
request-key.c [new file with mode: 0644]
request-key.conf [new file with mode: 0644]
request-key.conf.5 [new file with mode: 0644]
version.lds [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..42a84d9
--- /dev/null
@@ -0,0 +1,9 @@
+*~
+*.o
+*.os
+*.so
+*.a
+*.so.*
+keyctl
+request-key
+key.dns_resolver
diff --git a/LICENCE.GPL b/LICENCE.GPL
new file mode 100644 (file)
index 0000000..4505352
--- /dev/null
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc. <http://fsf.org/>
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+       Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/LICENCE.LGPL b/LICENCE.LGPL
new file mode 100644 (file)
index 0000000..519334a
--- /dev/null
@@ -0,0 +1,504 @@
+                 GNU LESSER GENERAL PUBLIC LICENSE
+                      Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc. <http://fsf.org/>
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+                 GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..9e3fa9b
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,240 @@
+CPPFLAGS       := -I.
+CFLAGS         := $(CPPFLAGS) -g -Wall -Werror
+INSTALL                := install
+DESTDIR                :=
+SPECFILE       := keyutils.spec
+NO_GLIBC_KEYERR        := 0
+NO_ARLIB       := 0
+ETCDIR         := /etc
+BINDIR         := /bin
+SBINDIR                := /sbin
+SHAREDIR       := /usr/share/keyutils
+MAN1           := /usr/share/man/man1
+MAN3           := /usr/share/man/man3
+MAN5           := /usr/share/man/man5
+MAN8           := /usr/share/man/man8
+INCLUDEDIR     := /usr/include
+LNS            := ln -sf
+
+###############################################################################
+#
+# Determine the current package version from the specfile
+#
+###############################################################################
+vermajor       := $(shell grep "%define vermajor" $(SPECFILE))
+verminor       := $(shell grep "%define verminor" $(SPECFILE))
+MAJOR          := $(word 3,$(vermajor))
+MINOR          := $(word 3,$(verminor))
+VERSION                := $(MAJOR).$(MINOR)
+
+###############################################################################
+#
+# Determine the current library version from the version script
+#
+###############################################################################
+libversion     := $(filter KEYUTILS_%,$(shell grep ^KEYUTILS_ version.lds))
+libversion     := $(lastword $(libversion))
+libversion     := $(lastword $(libversion))
+APIVERSION     := $(subst KEYUTILS_,,$(libversion))
+vernumbers     := $(subst ., ,$(APIVERSION))
+APIMAJOR       := $(firstword $(vernumbers))
+
+ARLIB          := libkeyutils.a
+DEVELLIB       := libkeyutils.so
+SONAME         := libkeyutils.so.$(APIMAJOR)
+LIBNAME                := libkeyutils.so.$(APIVERSION)
+
+###############################################################################
+#
+# Guess at the appropriate lib directory and word size
+#
+###############################################################################
+LIBDIR         := $(shell ldd /usr/bin/make | grep '\(/libc\)' | sed -e 's!.*\(/.*\)/libc[.].*!\1!')
+USRLIBDIR      := $(patsubst /lib/%,/usr/lib/%,$(LIBDIR))
+BUILDFOR       := $(shell file /usr/bin/make | sed -e 's!.*ELF \(32\|64\)-bit.*!\1!')-bit
+
+LNS            := ln -sf
+
+ifeq ($(BUILDFOR),32-bit)
+CFLAGS         += -m32
+LIBDIR         := /lib
+USRLIBDIR      := /usr/lib
+else
+ifeq ($(BUILDFOR),64-bit)
+CFLAGS         += -m64
+LIBDIR         := /lib64
+USRLIBDIR      := /usr/lib64
+endif
+endif
+
+###############################################################################
+#
+# This is necessary if glibc doesn't know about the key management error codes
+#
+###############################################################################
+ifeq ($(NO_GLIBC_KEYERR),1)
+CFLAGS += -DNO_GLIBC_KEYERR
+LIBLIBS        := -ldl -lc
+else
+LIBLIBS        :=
+endif
+
+###############################################################################
+#
+# Normal build rule
+#
+###############################################################################
+all: $(DEVELLIB) keyctl request-key key.dns_resolver
+
+###############################################################################
+#
+# Build the libraries
+#
+###############################################################################
+#RPATH = -Wl,-rpath,$(LIBDIR)
+
+ifeq ($(NO_ARLIB),0)
+all: $(ARLIB)
+$(ARLIB): keyutils.o
+       $(AR) rcs $@ $<
+endif
+
+keyutils.o: keyutils.c keyutils.h Makefile
+       $(CC) $(CPPFLAGS) $(CFLAGS) -UNO_GLIBC_KEYERR -o $@ -c $<
+
+
+$(DEVELLIB): $(SONAME)
+       ln -sf $< $@
+
+$(SONAME): $(LIBNAME)
+       ln -sf $< $@
+
+LIBVERS := -shared -Wl,-soname,$(SONAME) -Wl,--version-script,version.lds
+
+$(LIBNAME): keyutils.os version.lds Makefile
+       $(CC) $(CFLAGS) -fPIC $(LDFLAGS) $(LIBVERS) -o $@ keyutils.os $(LIBLIBS)
+
+keyutils.os: keyutils.c keyutils.h Makefile
+       $(CC) $(CFLAGS) -fPIC -o $@ -c $<
+
+###############################################################################
+#
+# Build the programs
+#
+###############################################################################
+%.o: %.c keyutils.h Makefile
+       $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<
+
+keyctl: keyctl.o -lkeyutils
+       $(CC) -L. $(CFLAGS) $(LDFLAGS) $(RPATH) -o $@ $< -lkeyutils
+
+request-key: request-key.o -lkeyutils
+       $(CC) -L. $(CFLAGS) $(LDFLAGS) $(RPATH) -o $@ $< -lkeyutils
+
+key.dns_resolver: key.dns_resolver.o -lkeyutils
+       $(CC) -L. $(CFLAGS) $(LDFLAGS) $(RPATH) -o $@ $< -lkeyutils -lresolv
+
+###############################################################################
+#
+# Install everything
+#
+###############################################################################
+install: all
+ifeq ($(NO_ARLIB),0)
+       $(INSTALL) -D -m 0644 $(ARLIB) $(DESTDIR)$(USRLIBDIR)/$(ARLIB)
+endif
+       $(INSTALL) -D $(LIBNAME) $(DESTDIR)$(LIBDIR)/$(LIBNAME)
+       $(LNS) $(LIBNAME) $(DESTDIR)$(LIBDIR)/$(SONAME)
+       mkdir -p $(DESTDIR)$(USRLIBDIR)
+       $(LNS) $(LIBDIR)/$(SONAME) $(DESTDIR)$(USRLIBDIR)/$(DEVELLIB)
+       $(INSTALL) -D keyctl $(DESTDIR)$(BINDIR)/keyctl
+       $(INSTALL) -D request-key $(DESTDIR)$(SBINDIR)/request-key
+       $(INSTALL) -D request-key-debug.sh $(DESTDIR)$(SHAREDIR)/request-key-debug.sh
+       $(INSTALL) -D key.dns_resolver $(DESTDIR)$(SBINDIR)/key.dns_resolver
+       $(INSTALL) -D -m 0644 request-key.conf $(DESTDIR)$(ETCDIR)/request-key.conf
+       $(INSTALL) -D -m 0644 keyctl.1 $(DESTDIR)$(MAN1)/keyctl.1
+       $(INSTALL) -D -m 0644 keyctl_chown.3 $(DESTDIR)$(MAN3)/keyctl_chown.3
+       $(INSTALL) -D -m 0644 keyctl_clear.3 $(DESTDIR)$(MAN3)/keyctl_clear.3
+       $(INSTALL) -D -m 0644 keyctl_describe.3 $(DESTDIR)$(MAN3)/keyctl_describe.3
+       $(LNS) keyctl_describe.3 $(DESTDIR)$(MAN3)/keyctl_describe_alloc.3
+       $(INSTALL) -D -m 0644 keyctl_get_keyring_ID.3 $(DESTDIR)$(MAN3)/keyctl_get_keyring_ID.3
+       $(INSTALL) -D -m 0644 keyctl_get_security.3 $(DESTDIR)$(MAN3)/keyctl_get_security.3
+       $(LNS) keyctl_get_security.3 $(DESTDIR)$(MAN3)/keyctl_get_security_alloc.3
+       $(INSTALL) -D -m 0644 keyctl_instantiate.3 $(DESTDIR)$(MAN3)/keyctl_instantiate.3
+       $(LNS) keyctl_instantiate.3 $(DESTDIR)$(MAN3)/keyctl_instantiate_iov.3
+       $(LNS) keyctl_instantiate.3 $(DESTDIR)$(MAN3)/keyctl_reject.3
+       $(LNS) keyctl_instantiate.3 $(DESTDIR)$(MAN3)/keyctl_negate.3
+       $(LNS) keyctl_instantiate.3 $(DESTDIR)$(MAN3)/keyctl_assume_authority.3
+       $(INSTALL) -D -m 0644 keyctl_join_session_keyring.3 $(DESTDIR)$(MAN3)/keyctl_join_session_keyring.3
+       $(INSTALL) -D -m 0644 keyctl_link.3 $(DESTDIR)$(MAN3)/keyctl_link.3
+       $(LNS) keyctl_link.3 $(DESTDIR)$(MAN3)/keyctl_unlink.3
+       $(INSTALL) -D -m 0644 keyctl_read.3 $(DESTDIR)$(MAN3)/keyctl_read.3
+       $(LNS) keyctl_read.3 $(DESTDIR)$(MAN3)/keyctl_read_alloc.3
+       $(INSTALL) -D -m 0644 keyctl_revoke.3 $(DESTDIR)$(MAN3)/keyctl_revoke.3
+       $(INSTALL) -D -m 0644 keyctl_search.3 $(DESTDIR)$(MAN3)/keyctl_search.3
+       $(INSTALL) -D -m 0644 keyctl_setperm.3 $(DESTDIR)$(MAN3)/keyctl_setperm.3
+       $(INSTALL) -D -m 0644 keyctl_set_reqkey_keyring.3 $(DESTDIR)$(MAN3)/keyctl_set_reqkey_keyring.3
+       $(INSTALL) -D -m 0644 keyctl_set_timeout.3 $(DESTDIR)$(MAN3)/keyctl_set_timeout.3
+       $(INSTALL) -D -m 0644 keyctl_update.3 $(DESTDIR)$(MAN3)/keyctl_update.3
+       $(INSTALL) -D -m 0644 recursive_key_scan.3 $(DESTDIR)$(MAN3)/recursive_key_scan.3
+       $(LNS) recursive_key_scan.3 $(DESTDIR)$(MAN3)/recursive_session_key_scan.3
+       $(INSTALL) -D -m 0644 request-key.conf.5 $(DESTDIR)$(MAN5)/request-key.conf.5
+       $(INSTALL) -D -m 0644 request-key.8 $(DESTDIR)$(MAN8)/request-key.8
+       $(INSTALL) -D -m 0644 key.dns_resolver.8 $(DESTDIR)$(MAN8)/key.dns_resolver.8
+       $(INSTALL) -D -m 0644 keyutils.h $(DESTDIR)$(INCLUDEDIR)/keyutils.h
+
+###############################################################################
+#
+# Clean up
+#
+###############################################################################
+clean:
+       $(RM) libkeyutils*
+       $(RM) keyctl request-key key.dns_resolver
+       $(RM) *.o *.os *~
+       $(RM) debugfiles.list debugsources.list
+
+distclean: clean
+       $(RM) -r rpmbuild
+
+###############################################################################
+#
+# Generate a tarball
+#
+###############################################################################
+TARBALL        := keyutils-$(VERSION).tar.bz2
+SRCBALL        := rpmbuild/SOURCES/$(TARBALL)
+
+dist   := $(word 2,$(shell grep "%dist" /etc/rpm/macros.dist))
+release        := $(word 2,$(shell grep ^Release: $(SPECFILE)))
+release        := $(subst %{?dist},$(dist),$(release))
+rpmver := $(VERSION)-$(release)
+SRPM   := rpmbuild/SRPMS/keyutils-$(rpmver).src.rpm
+
+RPMBUILDDIRS := \
+               --define "_srcrpmdir $(PWD)/rpmbuild/SRPMS" \
+               --define "_rpmdir $(PWD)/rpmbuild/RPMS" \
+               --define "_sourcedir $(PWD)/rpmbuild/SOURCES" \
+               --define "_specdir $(PWD)/rpmbuild/SPECS" \
+               --define "_builddir $(PWD)/rpmbuild/BUILD" \
+               --define "_buildrootdir $(PWD)/rpmbuild/BUILDROOT"
+
+rpm:
+       mkdir -p rpmbuild/{SPECS,SOURCES,BUILD,BUILDROOT,RPMS,SRPMS}
+       git archive --prefix=keyutils-$(VERSION)/ --format tar -o $(SRCBALL) HEAD
+       rpmbuild -ts $(SRCBALL) --define "_srcrpmdir rpmbuild/SRPMS"
+       rpmbuild --rebuild $(SRPM) $(RPMBUILDDIRS)
+
+###############################################################################
+#
+# Build debugging
+#
+###############################################################################
+show_vars:
+       @echo VERSION=$(VERSION)
+       @echo APIVERSION=$(APIVERSION)
+       @echo LIBDIR=$(LIBDIR)
+       @echo USRLIBDIR=$(USRLIBDIR)
+       @echo BUILDFOR=$(BUILDFOR)
+       @echo SONAME=$(SONAME)
+       @echo LIBNAME=$(LIBNAME)
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..5c3d94d
--- /dev/null
+++ b/README
@@ -0,0 +1,15 @@
+These tools are used to control the key management system built into the Linux
+kernel.
+
+To build and install the tools and manual pages, run:
+
+       make
+       make install
+
+If your glibc does not contain definitions for the new error codes and system
+calls, then try:
+
+       make NO_GLIBC_KEYERR=1
+
+The tools are licensed under the GPL and the utility library under the LGPL.
+Copies of these are included in this tarball.
diff --git a/key.dns_resolver.8 b/key.dns_resolver.8
new file mode 100644 (file)
index 0000000..8347a0d
--- /dev/null
@@ -0,0 +1,30 @@
+.\"
+.\" Copyright (C) 2011 Red Hat, Inc. All Rights Reserved.
+.\" Written by David Howells (dhowells@redhat.com)
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License
+.\" as published by the Free Software Foundation; either version
+.\" 2 of the License, or (at your option) any later version.
+.\"
+.TH KEY.DNS_RESOLVER 8 "04 Mar 2011" Linux "Linux Key Management Utilities"
+.SH NAME
+key.dns_resolver - Upcall for request-key to handle dns_resolver keys
+.SH SYNOPSIS
+\fB/sbin/key.dns_resolver \fR<key>
+.br
+\fB/sbin/key.dns_resolver \fR-D [-v] [-v] <keydesc> <calloutinfo>
+.SH DESCRIPTION
+This program is invoked by request-key on behalf of the kernel when kernel
+services (such as NFS, CIFS and AFS) want to perform a hostname lookup and the
+kernel does not have the key cached.  It is not ordinarily intended to be
+called directly.
+.P
+It can be called in debugging mode to test its functionality by passing a
+\fB-D\fR flag on the command line.  For this to work, the key description and
+the callout information must be supplied.  Verbosity can be increased by
+supplying one or more \fB-v\fR flags.
+.SH ERRORS
+All errors will be logged to the syslog.
+.SH SEE ALSO
+\fBrequest-key\fR(8), \fBrequest-key.conf\fR(5)
diff --git a/key.dns_resolver.c b/key.dns_resolver.c
new file mode 100644 (file)
index 0000000..49857a5
--- /dev/null
@@ -0,0 +1,749 @@
+/*
+ * DNS Resolver Module User-space Helper for AFSDB records
+ *
+ * Copyright (C) Wang Lei (wang840925@gmail.com) 2010
+ * Authors: Wang Lei (wang840925@gmail.com)
+ *          David Howells (dhowells@redhat.com)
+ *
+ * This is a userspace tool for querying AFSDB RR records in the DNS on behalf
+ * of the kernel, and converting the VL server addresses to IPv4 format so that
+ * they can be used by the kAFS filesystem.
+ *
+ * Compile with:
+ *
+ *     cc -o key.dns_resolver key.dns_resolver.c -lresolv -lkeyutils
+ *
+ * As some function like res_init() should use the static liberary, which is a
+ * bug of libresolv, that is the reason for cifs.upcall to reimplement.
+ *
+ * To use this program, you must tell /sbin/request-key how to invoke it.  You
+ * need to have the keyutils package installed and something like the following
+ * lines added to your /etc/request-key.conf file:
+ *
+ *     #OP    TYPE         DESCRIPTION CALLOUT INFO PROGRAM ARG1 ARG2 ARG3 ...
+ *     ====== ============ =========== ============ ==========================
+ *     create dns_resolver afsdb:*     *            /sbin/key.dns_resolver %k
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#define _GNU_SOURCE
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <keyutils.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+
+static const char *DNS_PARSE_VERSION = "1.0";
+static const char prog[] = "key.dns_resolver";
+static const char key_type[] = "dns_resolver";
+static const char a_query_type[] = "a";
+static const char aaaa_query_type[] = "aaaa";
+static const char afsdb_query_type[] = "afsdb";
+static key_serial_t key;
+static int verbose;
+static int debug_mode;
+
+
+#define        MAX_VLS                 15      /* Max Volume Location Servers Per-Cell */
+#define DNS_EXPIRY_PREFIX      "expiry_time="
+#define DNS_EXPIRY_TIME_LEN    10 /* 2^32 - 1 = 4294967295 */
+#define AFSDB_MAX_DATA_LEN                                             \
+       ((MAX_VLS * (INET6_ADDRSTRLEN + 1)) + sizeof(DNS_EXPIRY_PREFIX) + \
+        DNS_EXPIRY_TIME_LEN + 1 /* '#'*/ + 1 /* end 0 */)
+
+#define        INET_IP4_ONLY           0x1
+#define        INET_IP6_ONLY           0x2
+#define        INET_ALL                0xFF
+#define ONE_ADDR_ONLY          0x100
+#define LIST_MULTIPLE_ADDRS    0x200
+
+/*
+ * segmental payload
+ */
+#define N_PAYLOAD 256
+struct iovec payload[N_PAYLOAD];
+int payload_index;
+
+/*
+ * Print an error to stderr or the syslog, negate the key being created and
+ * exit
+ */
+static __attribute__((format(printf, 1, 2), noreturn))
+void error(const char *fmt, ...)
+{
+       va_list va;
+
+       va_start(va, fmt);
+       if (isatty(2)) {
+               vfprintf(stderr, fmt, va);
+               fputc('\n', stderr);
+       } else {
+               vsyslog(LOG_ERR, fmt, va);
+       }
+       va_end(va);
+
+       /*
+        * on error, negatively instantiate the key ourselves so that we can
+        * make sure the kernel doesn't hang it off of a searchable keyring
+        * and interfere with the next attempt to instantiate the key.
+        */
+       if (!debug_mode)
+               keyctl_negate(key, 1, KEY_REQKEY_DEFL_DEFAULT);
+
+       exit(1);
+}
+
+#define error(FMT, ...) error("Error: " FMT, ##__VA_ARGS__);
+
+/*
+ * Just print an error to stderr or the syslog
+ */
+static __attribute__((format(printf, 1, 2)))
+void _error(const char *fmt, ...)
+{
+       va_list va;
+
+       va_start(va, fmt);
+       if (isatty(2)) {
+               vfprintf(stderr, fmt, va);
+               fputc('\n', stderr);
+       } else {
+               vsyslog(LOG_ERR, fmt, va);
+       }
+       va_end(va);
+}
+
+/*
+ * Print status information
+ */
+static __attribute__((format(printf, 1, 2)))
+void info(const char *fmt, ...)
+{
+       va_list va;
+
+       if (verbose < 1)
+               return;
+
+       va_start(va, fmt);
+       if (isatty(1)) {
+               fputs("I: ", stdout);
+               vfprintf(stdout, fmt, va);
+               fputc('\n', stdout);
+       } else {
+               vsyslog(LOG_INFO, fmt, va);
+       }
+       va_end(va);
+}
+
+/*
+ * Print a nameserver error and exit
+ */
+static const int ns_errno_map[] = {
+       [0]                     = ECONNREFUSED,
+       [HOST_NOT_FOUND]        = ENODATA,
+       [TRY_AGAIN]             = EAGAIN,
+       [NO_RECOVERY]           = ECONNREFUSED,
+       [NO_DATA]               = ENODATA,
+};
+
+static __attribute__((noreturn))
+void nsError(int err, const char *domain)
+{
+       unsigned timeout = 1 * 60;
+       int ret;
+
+       if (isatty(2))
+               fprintf(stderr, "%s: %s.\n", domain, hstrerror(err));
+       else
+               syslog(LOG_INFO, "%s: %s", domain, hstrerror(err));
+
+       if (err >= sizeof(ns_errno_map) / sizeof(ns_errno_map[0]))
+               err = ECONNREFUSED;
+       else
+               err = ns_errno_map[err];
+
+       info("Reject the key with error %d", err);
+
+       if (err == EAGAIN)
+               timeout = 1;
+       else if (err == ECONNREFUSED)
+               timeout = 10;
+
+       if (!debug_mode) {
+               ret = keyctl_reject(key, timeout, err, KEY_REQKEY_DEFL_DEFAULT);
+               if (ret == -1)
+                       error("%s: keyctl_reject: %m", __func__);
+       }
+       exit(0);
+}
+
+/*
+ * Print debugging information
+ */
+static __attribute__((format(printf, 1, 2)))
+void debug(const char *fmt, ...)
+{
+       va_list va;
+
+       if (verbose < 2)
+               return;
+
+       va_start(va, fmt);
+       if (isatty(1)) {
+               fputs("D: ", stdout);
+               vfprintf(stdout, fmt, va);
+               fputc('\n', stdout);
+       } else {
+               vsyslog(LOG_DEBUG, fmt, va);
+       }
+       va_end(va);
+}
+
+/*
+ * Append an address to the payload segment list
+ */
+static void append_address_to_payload(char *p, size_t sz)
+{
+       int loop;
+
+       debug("append '%*.*s'", (int)sz, (int)sz, p);
+
+       /* discard duplicates */
+       for (loop = 0; loop < payload_index; loop++)
+               if (payload[loop].iov_len == sz &&
+                   memcmp(payload[loop].iov_base, p, sz) == 0)
+                       return;
+
+       if (payload_index != 0) {
+               if (payload_index + 2 > N_PAYLOAD - 1)
+                       return;
+               payload[payload_index  ].iov_base = ",";
+               payload[payload_index++].iov_len = 1;
+       } else {
+               if (payload_index + 1 > N_PAYLOAD - 1)
+                       return;
+       }
+
+       payload[payload_index  ].iov_base = p;
+       payload[payload_index++].iov_len = sz;
+}
+
+/*
+ * Dump the payload when debugging
+ */
+static void dump_payload(void)
+{
+       size_t plen, n;
+       char *buf, *p;
+       int loop;
+
+       if (debug_mode)
+               verbose = 1;
+       if (verbose < 1)
+               return;
+
+       plen = 0;
+       for (loop = 0; loop < payload_index; loop++) {
+               n = payload[loop].iov_len;
+               debug("seg[%d]: %zu", loop, n);
+               plen += n;
+       }
+       if (plen == 0) {
+               info("The key instantiation data is empty");
+               return;
+       }
+
+       debug("total: %zu", plen);
+       buf = malloc(plen + 1);
+       if (!buf)
+               return;
+
+       p = buf;
+       for (loop = 0; loop < payload_index; loop++) {
+               n = payload[loop].iov_len;
+               memcpy(p, payload[loop].iov_base, n);
+               p += n;
+       }
+
+       info("The key instantiation data is '%s'", buf);
+       free(buf);
+}
+
+/*
+ * Perform address resolution on a hostname and add the resulting address as a
+ * string to the list of payload segments.
+ */
+static int
+dns_resolver(const char *server_name, unsigned mask)
+{
+       struct addrinfo hints, *addr, *ai;
+       size_t slen;
+       char buf[INET6_ADDRSTRLEN + 1], *seg;
+       int ret, len;
+       void *sa;
+
+       debug("Resolve '%s' with %x", server_name, mask);
+
+       memset(&hints, 0, sizeof(hints));
+       switch (mask & INET_ALL) {
+       case INET_IP4_ONLY:     hints.ai_family = AF_INET;      debug("IPv4"); break;
+       case INET_IP6_ONLY:     hints.ai_family = AF_INET6;     debug("IPv6"); break;
+       default: break;
+       }
+
+       /* resolve name to ip */
+       ret = getaddrinfo(server_name, NULL, &hints, &addr);
+       if (ret) {
+               info("unable to resolve hostname: %s [%s]",
+                    server_name, gai_strerror(ret));
+               return -1;
+       }
+
+       debug("getaddrinfo = %d", ret);
+
+       for (ai = addr; ai; ai = ai->ai_next) {
+               debug("RR: %x,%x,%x,%x,%x,%s",
+                     ai->ai_flags, ai->ai_family,
+                     ai->ai_socktype, ai->ai_protocol,
+                     ai->ai_addrlen, ai->ai_canonname);
+
+               /* convert address to string */
+               switch (ai->ai_family) {
+               case AF_INET:
+                       if (!(mask & INET_IP4_ONLY))
+                               continue;
+                       sa = &(((struct sockaddr_in *)ai->ai_addr)->sin_addr);
+                       len = INET_ADDRSTRLEN;
+                       break;
+               case AF_INET6:
+                       if (!(mask & INET_IP6_ONLY))
+                               continue;
+                       sa = &(((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr);
+                       len = INET6_ADDRSTRLEN;
+                       break;
+               default:
+                       debug("Address of unknown family %u", addr->ai_family);
+                       continue;
+               }
+
+               if (!inet_ntop(ai->ai_family, sa, buf, len))
+                       error("%s: inet_ntop: %m", __func__);
+
+               slen = strlen(buf);
+               seg = malloc(slen);
+               if (!seg)
+                       error("%s: inet_ntop: %m", __func__);
+               memcpy(seg, buf, slen);
+               append_address_to_payload(seg, slen);
+               if (mask & ONE_ADDR_ONLY)
+                       break;
+       }
+
+       freeaddrinfo(addr);
+       return 0;
+}
+
+/*
+ *
+ */
+static void afsdb_hosts_to_addrs(char *vllist[],
+                                int *vlsnum,
+                                ns_msg handle,
+                                ns_sect section,
+                                unsigned mask,
+                                unsigned long *_ttl)
+{
+       int rrnum;
+       ns_rr rr;
+       int subtype, i, ret;
+       unsigned int ttl = UINT_MAX, rr_ttl;
+
+       debug("AFSDB RR count is %d", ns_msg_count(handle, section));
+
+       /* Look at all the resource records in this section. */
+       for (rrnum = 0; rrnum < ns_msg_count(handle, section); rrnum++) {
+               /* Expand the resource record number rrnum into rr. */
+               if (ns_parserr(&handle, section, rrnum, &rr)) {
+                       _error("ns_parserr failed : %m");
+                       continue;
+               }
+
+               /* We're only interested in AFSDB records */
+               if (ns_rr_type(rr) == ns_t_afsdb) {
+                       vllist[*vlsnum] = malloc(MAXDNAME);
+                       if (!vllist[*vlsnum])
+                               error("Out of memory");
+
+                       subtype = ns_get16(ns_rr_rdata(rr));
+
+                       /* Expand the name server's domain name */
+                       if (ns_name_uncompress(ns_msg_base(handle),
+                                              ns_msg_end(handle),
+                                              ns_rr_rdata(rr) + 2,
+                                              vllist[*vlsnum],
+                                              MAXDNAME) < 0)
+                               error("ns_name_uncompress failed");
+
+                       rr_ttl = ns_rr_ttl(rr);
+                       if (ttl > rr_ttl)
+                               ttl = rr_ttl;
+
+                       /* Check the domain name we've just unpacked and add it to
+                        * the list of VL servers if it is not a duplicate.
+                        * If it is a duplicate, just ignore it.
+                        */
+                       for (i = 0; i < *vlsnum; i++)
+                               if (strcasecmp(vllist[i], vllist[*vlsnum]) == 0)
+                                       goto next_one;
+
+                       /* Turn the hostname into IP addresses */
+                       ret = dns_resolver(vllist[*vlsnum], mask);
+                       if (ret) {
+                               debug("AFSDB RR can't resolve."
+                                     "subtype:%d, server name:%s, netmask:%u",
+                                     subtype, vllist[*vlsnum], mask);
+                               goto next_one;
+                       }
+
+                       info("AFSDB RR subtype:%d, server name:%s, ip:%*.*s, ttl:%u",
+                            subtype, vllist[*vlsnum],
+                            (int)payload[payload_index - 1].iov_len,
+                            (int)payload[payload_index - 1].iov_len,
+                            (char *)payload[payload_index - 1].iov_base,
+                            ttl);
+
+                       /* prepare for the next record */
+                       *vlsnum += 1;
+                       continue;
+
+               next_one:
+                       free(vllist[*vlsnum]);
+               }
+       }
+
+       *_ttl = ttl;
+       info("ttl: %u", ttl);
+}
+
+/*
+ * Look up an AFSDB record to get the VL server addresses.
+ *
+ * The callout_info is parsed for request options.  For instance, "ipv4" to
+ * request only IPv4 addresses and "ipv6" to request only IPv6 addresses.
+ */
+static __attribute__((noreturn))
+int dns_query_afsdb(key_serial_t key, const char *cell, char *options)
+{
+       int     ret;
+       char    *vllist[MAX_VLS];       /* list of name servers */
+       int     vlsnum = 0;             /* number of name servers in list */
+       unsigned mask = INET_ALL;
+       int     response_len;           /* buffer length */
+       ns_msg  handle;                 /* handle for response message */
+       unsigned long ttl = ULONG_MAX;
+       union {
+               HEADER hdr;
+               u_char buf[NS_PACKETSZ];
+       } response;             /* response buffers */
+
+       debug("Get AFSDB RR for cell name:'%s', options:'%s'", cell, options);
+
+       /* query the dns for an AFSDB resource record */
+       response_len = res_query(cell,
+                                ns_c_in,
+                                ns_t_afsdb,
+                                response.buf,
+                                sizeof(response));
+
+       if (response_len < 0)
+               /* negative result */
+               nsError(h_errno, cell);
+
+       if (ns_initparse(response.buf, response_len, &handle) < 0)
+               error("ns_initparse: %m");
+
+       /* Is the IP address family limited? */
+       if (strcmp(options, "ipv4") == 0)
+               mask = INET_IP4_ONLY;
+       else if (strcmp(options, "ipv6") == 0)
+               mask = INET_IP6_ONLY;
+
+       /* look up the hostnames we've obtained to get the actual addresses */
+       afsdb_hosts_to_addrs(vllist, &vlsnum, handle, ns_s_an, mask, &ttl);
+
+       info("DNS query AFSDB RR results:%u ttl:%lu", payload_index, ttl);
+
+       /* set the key's expiry time from the minimum TTL encountered */
+       if (!debug_mode) {
+               ret = keyctl_set_timeout(key, ttl);
+               if (ret == -1)
+                       error("%s: keyctl_set_timeout: %m", __func__);
+       }
+
+       /* handle a lack of results */
+       if (payload_index == 0)
+               nsError(NO_DATA, cell);
+
+       /* must include a NUL char at the end of the payload */
+       payload[payload_index].iov_base = "";
+       payload[payload_index++].iov_len = 1;
+       dump_payload();
+
+       /* load the key with data key */
+       if (!debug_mode) {
+               ret = keyctl_instantiate_iov(key, payload, payload_index, 0);
+               if (ret == -1)
+                       error("%s: keyctl_instantiate: %m", __func__);
+       }
+
+       exit(0);
+}
+
+/*
+ * Look up a A and/or AAAA records to get host addresses
+ *
+ * The callout_info is parsed for request options.  For instance, "ipv4" to
+ * request only IPv4 addresses, "ipv6" to request only IPv6 addresses and
+ * "list" to get multiple addresses.
+ */
+static __attribute__((noreturn))
+int dns_query_a_or_aaaa(key_serial_t key, const char *hostname, char *options)
+{
+       unsigned mask;
+       int ret;
+
+       debug("Get A/AAAA RR for hostname:'%s', options:'%s'",
+             hostname, options);
+
+       if (!options[0]) {
+               /* legacy mode */
+               mask = INET_IP4_ONLY | ONE_ADDR_ONLY;
+       } else {
+               char *key, *val;
+
+               mask = INET_ALL | ONE_ADDR_ONLY;
+
+               do {
+                       key = options;
+                       options = strchr(options, ' ');
+                       if (!options)
+                               options = key + strlen(key);
+                       else
+                               *options++ = '\0';
+                       if (!*key)
+                               continue;
+                       if (strchr(key, ','))
+                               error("Option name '%s' contains a comma", key);
+
+                       val = strchr(key, '=');
+                       if (val)
+                               *val++ = '\0';
+
+                       debug("Opt %s", key);
+
+                       if (strcmp(key, "ipv4") == 0) {
+                               mask &= ~INET_ALL;
+                               mask |= INET_IP4_ONLY;
+                       } else if (strcmp(key, "ipv6") == 0) {
+                               mask &= ~INET_ALL;
+                               mask |= INET_IP6_ONLY;
+                       } else if (strcmp(key, "list") == 0) {
+                               mask &= ~ONE_ADDR_ONLY;
+                               mask |= LIST_MULTIPLE_ADDRS;
+                       }
+
+               } while (*options);
+       }
+
+       /* Turn the hostname into IP addresses */
+       ret = dns_resolver(hostname, mask);
+       if (ret)
+               nsError(NO_DATA, hostname);
+
+       /* handle a lack of results */
+       if (payload_index == 0)
+               nsError(NO_DATA, hostname);
+
+       /* must include a NUL char at the end of the payload */
+       payload[payload_index].iov_base = "";
+       payload[payload_index++].iov_len = 1;
+       dump_payload();
+
+       /* load the key with data key */
+       if (!debug_mode) {
+               ret = keyctl_instantiate_iov(key, payload, payload_index, 0);
+               if (ret == -1)
+                       error("%s: keyctl_instantiate: %m", __func__);
+       }
+
+       exit(0);
+}
+
+/*
+ * Print usage details,
+ */
+static __attribute__((noreturn))
+void usage(void)
+{
+       if (isatty(2)) {
+               fprintf(stderr,
+                       "Usage: %s [-vv] key_serial\n",
+                       prog);
+               fprintf(stderr,
+                       "Usage: %s -D [-vv] <desc> <calloutinfo>\n",
+                       prog);
+       } else {
+               info("Usage: %s [-vv] key_serial", prog);
+       }
+       if (!debug_mode)
+               keyctl_negate(key, 1, KEY_REQKEY_DEFL_DEFAULT);
+       exit(2);
+}
+
+const struct option long_options[] = {
+       { "debug",      0, NULL, 'D' },
+       { "verbose",    0, NULL, 'v' },
+       { "version",    0, NULL, 'V' },
+       { NULL,         0, NULL, 0 }
+};
+
+/*
+ *
+ */
+int main(int argc, char *argv[])
+{
+       int ktlen, qtlen, ret;
+       char *keyend, *p;
+       char *callout_info = NULL;
+       char *buf = NULL, *name;
+
+       openlog(prog, 0, LOG_DAEMON);
+
+       while ((ret = getopt_long(argc, argv, "vD", long_options, NULL)) != -1) {
+               switch (ret) {
+               case 'D':
+                       debug_mode = 1;
+                       continue;
+               case 'V':
+                       printf("version: %s\n", DNS_PARSE_VERSION);
+                       exit(0);
+               case 'v':
+                       verbose++;
+                       continue;
+               default:
+                       if (!isatty(2))
+                               syslog(LOG_ERR, "unknown option: %c", ret);
+                       usage();
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       if (!debug_mode) {
+               if (argc != 1)
+                       usage();
+
+               /* get the key ID */
+               errno = 0;
+               key = strtol(*argv, NULL, 10);
+               if (errno != 0)
+                       error("Invalid key ID format: %m");
+
+               /* get the key description (of the form "x;x;x;x;<query_type>:<name>") */
+               if (!buf) {
+                       ret = keyctl_describe_alloc(key, &buf);
+                       if (ret == -1)
+                               error("keyctl_describe_alloc failed: %m");
+               }
+
+               /* get the callout_info (which can supply options) */
+               if (!callout_info) {
+                       ret = keyctl_read_alloc(KEY_SPEC_REQKEY_AUTH_KEY,
+                                               (void **)&callout_info);
+                       if (ret == -1)
+                               error("Invalid key callout_info read: %m");
+               }
+       } else {
+               if (argc != 2)
+                       usage();
+
+               ret = asprintf(&buf, "%s;-1;-1;0;%s", key_type, argv[0]);
+               if (ret < 0)
+                       error("Error %m");
+               callout_info = argv[1];
+       }
+
+       ret = 1;
+       info("Key description: '%s'", buf);
+       info("Callout info: '%s'", callout_info);
+
+       p = strchr(buf, ';');
+       if (!p)
+               error("Badly formatted key description '%s'", buf);
+       ktlen = p - buf;
+
+       /* make sure it's the type we are expecting */
+       if (ktlen != sizeof(key_type) - 1 ||
+           memcmp(buf, key_type, ktlen) != 0)
+               error("Key type is not supported: '%*.*s'", ktlen, ktlen, buf);
+
+       keyend = buf + ktlen + 1;
+
+       /* the actual key description follows the last semicolon */
+       keyend = rindex(keyend, ';');
+       if (!keyend)
+               error("Invalid key description: %s", buf);
+       keyend++;
+
+       name = index(keyend, ':');
+       if (!name)
+               dns_query_a_or_aaaa(key, keyend, callout_info);
+
+       qtlen = name - keyend;
+       name++;
+
+       if ((qtlen == sizeof(a_query_type) - 1 &&
+            memcmp(keyend, a_query_type, sizeof(a_query_type) - 1) == 0) ||
+           (qtlen == sizeof(aaaa_query_type) - 1 &&
+            memcmp(keyend, aaaa_query_type, sizeof(aaaa_query_type) - 1) == 0)
+           ) {
+               info("Do DNS query of A/AAAA type for:'%s' mask:'%s'",
+                    name, callout_info);
+               dns_query_a_or_aaaa(key, name, callout_info);
+       }
+
+       if (qtlen == sizeof(afsdb_query_type) - 1 &&
+           memcmp(keyend, afsdb_query_type, sizeof(afsdb_query_type) - 1) == 0
+           ) {
+               info("Do DNS query of AFSDB type for:'%s' mask:'%s'",
+                    name, callout_info);
+               dns_query_afsdb(key, name, callout_info);
+       }
+
+       error("Query type: \"%*.*s\" is not supported", qtlen, qtlen, keyend);
+}
diff --git a/keyctl.1 b/keyctl.1
new file mode 100644 (file)
index 0000000..aac69bc
--- /dev/null
+++ b/keyctl.1
@@ -0,0 +1,713 @@
+.\"
+.\" Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+.\" Written by David Howells (dhowells@redhat.com)
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License
+.\" as published by the Free Software Foundation; either version
+.\" 2 of the License, or (at your option) any later version.
+.\"
+.TH KEYCTL 1 "17 Nov 2005" Linux "Linux Key Management Utilities"
+.SH NAME
+keyctl - Key management facility control
+.SH SYNOPSIS
+\fBkeyctl\fR show
+.br
+\fBkeyctl\fR add <type> <desc> <data> <keyring>
+.br
+\fBkeyctl\fR padd <type> <desc> <keyring>
+.br
+\fBkeyctl\fR request <type> <desc> [<dest_keyring>]
+.br
+\fBkeyctl\fR request2 <type> <desc> <info> [<dest_keyring>]
+.br
+\fBkeyctl\fR prequest2 <type> <desc> [<dest_keyring>]
+.br
+\fBkeyctl\fR update <key> <data>
+.br
+\fBkeyctl\fR pupdate <key>
+.br
+\fBkeyctl\fR newring <name> <keyring>
+.br
+\fBkeyctl\fR revoke <key>
+.br
+\fBkeyctl\fR clear <keyring>
+.br
+\fBkeyctl\fR link <key> <keyring>
+.br
+\fBkeyctl\fR unlink <key> <keyring>
+.br
+\fBkeyctl\fR search <keyring> <type> <desc> [<dest_keyring>]
+.br
+\fBkeyctl\fR read <key>
+.br
+\fBkeyctl\fR pipe <key>
+.br
+\fBkeyctl\fR print <key>
+.br
+\fBkeyctl\fR list <keyring>
+.br
+\fBkeyctl\fR rlist <keyring>
+.br
+\fBkeyctl\fR describe <keyring>
+.br
+\fBkeyctl\fR rdescribe <keyring> [sep]
+.br
+\fBkeyctl\fR chown <key> <uid>
+.br
+\fBkeyctl\fR chgrp <key> <gid>
+.br
+\fBkeyctl\fR setperm <key> <mask>
+.br
+\fBkeyctl\fR session
+.br
+\fBkeyctl\fR session - [<prog> <arg1> <arg2> ...]
+.br
+\fBkeyctl\fR session <name> [<prog> <arg1> <arg2> ...]
+.br
+\fBkeyctl\fR instantiate <key> <data> <keyring>
+.br
+\fBkeyctl\fR pinstantiate <key> <keyring>
+.br
+\fBkeyctl\fR negate <key> <timeout> <keyring>
+.br
+\fBkeyctl\fR reject <key> <timeout> <error> <keyring>
+.br
+\fBkeyctl\fR timeout <key> <timeout>
+.br
+\fBkeyctl\fR security <key>
+.br
+\fBkeyctl\fR reap [-v]
+.br
+\fBkeyctl\fR purge <type>
+.br
+\fBkeyctl\fR purge [-i] [-p] <type> <desc>
+.br
+\fBkeyctl\fR purge -s <type> <desc>
+.SH DESCRIPTION
+This program is used to control the key management facility in various ways
+using a variety of subcommands.
+.SH KEY IDENTIFIERS
+.P
+The key identifiers passed to or returned from keyctl are, in general, positive
+integers. There are, however, some special values with special meanings that
+can be passed as arguments:
+.P
+(*) No key: \fB0\fR
+.P
+(*) Thread keyring: \fB@t\fR or \fB-1\fR
+.P
+Each thread may have its own keyring. This is searched first, before all
+others. The thread keyring is replaced by (v)fork, exec and clone.
+.P
+(*) Process keyring: \fB@p\fR or \fB-2\fR
+.P
+Each process (thread group) may have its own keyring. This is shared between
+all members of a group and will be searched after the thread keyring. The
+process keyring is replaced by (v)fork and exec.
+.P
+(*) Session keyring: \fB@s\fR or \fB-3\fR
+.P
+Each process subscribes to a session keyring that is inherited across (v)fork,
+exec and clone. This is searched after the process keyring. Session keyrings
+can be named and an extant keyring can be joined in place of a process's
+current session keyring.
+.P
+(*) User specific keyring: \fB@u\fR or \fB-4\fR
+.P
+This keyring is shared between all the processes owned by a particular user. It
+isn't searched directly, but is normally linked to from the session keyring.
+.P
+(*) User default session keyring: \fB@us\fR or \fB-5\fR
+.P
+This is the default session keyring for a particular user. Login processes that
+change to a particular user will bind to this session until another session is
+set.
+.P
+(*) Group specific keyring: \fB@g\fR or \fB-6\fR
+.P
+This is a place holder for a group specific keyring, but is not actually
+implemented yet in the kernel.
+.P
+(*) Assumed request_key authorisation key: \fB@a\fR or \fB-7\fR
+.P
+This selects the authorisation key provided to the request_key() helper to
+permit it to access the callers keyrings and instantiate the target key.
+.SH COMMAND SYNTAX
+Any non-ambiguous shortening of a command name may be used in lieu of the full
+command name. This facility should not be used in scripting as new commands may
+be added in future that then cause ambiguity.
+.P
+(*) \fBShow process keyrings\fR
+.P
+\fBkeyctl show\fR
+.P
+This command recursively shows what keyrings a process is subscribed to and
+what keys and keyrings they contain.
+.P
+(*) \fBAdd a key to a keyring\fR
+.P
+\fBkeyctl add\fR <type> <desc> <data> <keyring>
+.br
+\fBkeyctl padd\fR <type> <desc> <keyring>
+.P
+This command creates a key of the specified type and description; instantiates
+it with the given data and attaches it to the specified keyring. It then prints
+the new key's ID on stdout:
+.P
+.RS
+testbox>keyctl add user mykey stuff @u
+.br
+26
+.RE
+.P
+The \fBpadd\fR variant of the command reads the data from stdin rather than
+taking it from the command line:
+.P
+.RS
+testbox>echo -n stuff | keyctl padd user mykey @u
+.br
+26
+.RE
+.P
+(*) \fBRequest a key\fR
+.P
+\fBkeyctl request\fR <type> <desc> [<dest_keyring>]
+.br
+\fBkeyctl request2\fR <type> <desc> <info> [<dest_keyring>]
+.br
+\fBkeyctl prequest2\fR <type> <desc> [<dest_keyring>]
+.P
+These three commands request the lookup of a key of the given type and
+description. The process's keyrings will be searched, and if a match is found
+the matching key's ID will be printed to stdout; and if a destination keyring
+is given, the key will be added to that keyring also.
+.P
+If there is no key, the first command will simply return the error ENOKEY and
+fail. The second and third commands will create a partial key with the type and
+description, and call out to \fB/sbin/request-key\fR with that key and the
+extra information supplied. This will then attempt to instantiate the key in
+some manner, such that a valid key is obtained.
+.P
+The third command is like the second, except that the callout information is
+read from stdin rather than being passed on the command line.
+.P
+If a valid key is obtained, the ID will be printed and the key attached as if
+the original search had succeeded.
+.P
+If there wasn't a valid key obtained, a temporary negative key will be attached
+to the destination keyring if given and the error "Requested key not available"
+will be given.
+.P
+.RS
+testbox>keyctl request2 user debug:hello wibble
+.br
+23
+.br
+testbox>echo -n wibble | keyctl prequest2 user debug:hello
+.br
+23
+.br
+testbox>keyctl request user debug:hello
+.br
+23
+.RE
+.P
+(*) \fBUpdate a key\fR
+.P
+\fBkeyctl update\fR <key> <data>
+.br
+\fBkeyctl pupdate\fR <key>
+.P
+This command replaces the data attached to a key with a new set of data. If the
+type of the key doesn't support update then error "Operation not supported"
+will be returned.
+.P
+.RS
+testbox>keyctl update 23 zebra
+.RE
+.P
+The \fBpupdate\fR variant of the command reads the data from stdin rather than
+taking it from the command line:
+.P
+.RS
+testbox>echo -n zebra | keyctl pupdate 23
+.RE
+.P
+(*) \fBCreate a keyring\fR
+.P
+\fBkeyctl newring\fR <name> <keyring>
+.P
+This command creates a new keyring of the specified name and attaches it to the
+specified keyring. The ID of the new keyring will be printed to stdout if
+successful.
+.P
+.RS
+testbox>keyctl newring squelch @us
+.br
+27
+.RE
+.P
+(*) \fBRevoke a key\fR
+.P
+\fBkeyctl revoke\fR <key>
+.P
+This command marks a key as being revoked. Any further operations on that key
+(apart from unlinking it) will return error "Key has been revoked".
+.P
+.RS
+testbox>keyctl revoke 26
+.br
+testbox>keyctl describe 26
+.br
+keyctl_describe: Key has been revoked
+.RE
+.P
+(*) \fBClear a keyring\fR
+.P
+\fBkeyctl clear\fR <keyring>
+.P
+This command unlinks all the keys attached to the specified keyring. Error
+"Not a directory" will be returned if the key specified is not a keyring.
+.P
+.RS
+testbox>keyctl clear 27
+.RE
+.P
+(*) \fBLink a key to a keyring\fR
+.P
+\fBkeyctl link\fR <key> <keyring>
+.P
+This command makes a link from the key to the keyring if there's enough
+capacity to do so. Error "Not a directory" will be returned if the destination
+is not a keyring. Error "Permission denied" will be returned if the key doesn't
+have link permission or the keyring doesn't have write permission. Error "File
+table overflow" will be returned if the keyring is full. Error "Resource
+deadlock avoided" will be returned if an attempt was made to introduce a
+recursive link.
+.P
+.RS
+testbox>keyctl link 23 27
+.br
+testbox>keyctl link 27 27
+.br
+keyctl_link: Resource deadlock avoided
+.RE
+.P
+(*) \fBUnlink a key from a keyring or the session keyring tree\fR
+.P
+\fBkeyctl unlink\fR <key> [<keyring>]
+.P
+If the keyring is specified, this command removes a link to the key from the
+keyring. Error "Not a directory" will be returned if the destination is not a
+keyring. Error "Permission denied" will be returned if the keyring doesn't have
+write permission. Error "No such file or directory" will be returned if the key
+is not linked to by the keyring.
+.P
+If the keyring is not specified, this command performs a depth-first search of
+the session keyring tree and removes all the links to the nominated key that it
+finds (and that it is permitted to remove).  It prints the number of successful
+unlinks before exiting.
+.P
+.RS
+testbox>keyctl unlink 23 27
+.RE
+.P
+(*) \fBSearch a keyring\fR
+.P
+\fBkeyctl search\fR <keyring> <type> <desc> [<dest_keyring>]
+.P
+This command non-recursively searches a keyring for a key of a particular type
+and description. If found, the ID of the key will be printed on stdout and the
+key will be attached to the destination keyring if present. Error "Requested
+key not available" will be returned if the key is not found.
+.P
+.RS
+testbox>keyctl search @us user debug:hello
+.br
+23
+.br
+testbox>keyctl search @us user debug:bye
+.br
+keyctl_search: Requested key not available
+.RE
+.P
+(*) \fBRead a key\fR
+.P
+\fBkeyctl read\fR <key>
+.br
+\fBkeyctl pipe\fR <key>
+.br
+\fBkeyctl print\fR <key>
+.P
+These commands read the payload of a key. "read" prints it on stdout as a hex
+dump, "pipe" dumps the raw data to stdout and "print" dumps it to stdout
+directly if it's entirely printable or as a hexdump preceded by ":hex:" if not.
+.P
+If the key type does not support reading of the payload, then error "Operation
+not supported" will be returned.
+.P
+.RS
+testbox>keyctl read 26
+.br
+1 bytes of data in key:
+.br
+62
+.br
+testbox>keyctl print 26
+.br
+b
+.br
+testbox>keyctl pipe 26
+.br
+btestbox>
+.RE
+.P
+(*) \fBList a keyring\fR
+.P
+\fBkeyctl list\fR <keyring>
+.br
+\fBkeyctl rlist\fR <keyring>
+.P
+These commands list the contents of a key as a keyring. "list" pretty prints
+the contents and "rlist" just produces a space-separated list of key IDs.
+.P
+No attempt is made to check that the specified keyring is a keyring.
+.P
+.RS
+testbox>keyctl list @us
+.br
+2 keys in keyring:
+.br
+       22: vrwsl----------  4043    -1 keyring: _uid.4043
+.br
+       23: vrwsl----------  4043  4043 user: debug:hello
+.br
+testbox>keyctl rlist @us
+.br
+22 23
+.RE
+.P
+(*) \fBDescribe a key\fR
+.P
+\fBkeyctl describe\fR <keyring>
+.br
+\fBkeyctl rdescribe\fR <keyring> [sep]
+.P
+These commands fetch a description of a keyring. "describe" pretty prints the
+description in the same fashion as the "list" command; "rdescribe" prints the
+raw data returned from the kernel.
+.P
+.RS
+testbox>keyctl describe @us
+       -5: vrwsl----------  4043    -1 keyring: _uid_ses.4043
+testbox>keyctl rdescribe @us
+keyring;4043;-1;3f1f0000;_uid_ses.4043
+.RE
+.P
+The raw string is "<type>;<uid>;<gid>;<perms>;<description>", where \fIuid\fR
+and \fIgid\fR are the decimal user and group IDs, \fIperms\fR is the
+permissions mask in hex, \fItype\fR and \fIdescription\fR are the type name and
+description strings (neither of which will contain semicolons).
+.P
+(*) \fBChange the access controls on a key\fR
+.P
+\fBkeyctl chown\fR <key> <uid>
+.br
+\fBkeyctl chgrp\fR <key> <gid>
+.P
+These two commands change the UID and GID associated with evaluating a key's
+permissions mask. The UID also governs which quota a key is taken out of.
+.P
+The chown command is not currently supported; attempting it will earn the error
+"Operation not supported" at best.
+.P
+For non-superuser users, the GID may only be set to the process's GID or a GID
+in the process's groups list. The superuser may set any GID it likes.
+.P
+.RS
+testbox>sudo keyctl chown 27 0
+.br
+keyctl_chown: Operation not supported
+.br
+testbox>sudo keyctl chgrp 27 0
+.RE
+.P
+(*) \fBSet the permissions mask on a key\fR
+.P
+\fBkeyctl setperm\fR <key> <mask>
+.P
+This command changes the permission control mask on a key. The mask may be
+specified as a hex number if it begins "0x", an octal number if it begins "0"
+or a decimal number otherwise.
+.P
+The hex numbers are a combination of:
+.P
+.RS
+Possessor UID       GID       Other     Permission Granted
+.br
+========  ========  ========  ========  ==================
+.br
+01000000  00010000  00000100  00000001  View
+.br
+02000000  00020000  00000200  00000002  Read
+.br
+04000000  00040000  00000400  00000004  Write
+.br
+08000000  00080000  00000800  00000008  Search
+.br
+10000000  00100000  00001000  00000010  Link
+.br
+20000000  00200000  00002000  00000020  Set Attribute
+.br
+3f000000  003f0000  00003f00  0000003f  All
+.RE
+.P
+\fIView\fR permits the type, description and other parameters of a key to be
+viewed.
+.P
+\fIRead\fR permits the payload (or keyring list) to be read if supported by the
+type.
+.P
+\fIWrite\fR permits the payload (or keyring list) to be modified or updated.
+.P
+\fISearch\fR on a key permits it to be found when a keyring to which it is
+linked is searched.
+.P
+\fILink\fR permits a key to be linked to a keyring.
+.P
+\fISet Attribute\fR permits a key to have its owner, group membership,
+permissions mask and timeout changed.
+.P
+.RS
+testbox>keyctl setperm 27 0x1f1f1f00
+.RE
+.P
+(*) \fBStart a new session with fresh keyrings\fR
+.P
+\fBkeyctl session\fR
+.br
+\fBkeyctl session\fR - [<prog> <arg1> <arg2> ...]
+.br
+\fBkeyctl session\fR <name> [<prog> <arg1> <arg2> ...]
+.P
+These commands join or create a new keyring and then run a shell or other
+program with that keyring as the session key.
+.P
+The variation with no arguments just creates an anonymous session keyring and
+attaches that as the session keyring; it then exec's $SHELL.
+.P
+The variation with a dash in place of a name creates an anonymous session
+keyring and attaches that as the session keyring; it then exec's the supplied
+command, or $SHELL if one isn't supplied.
+.P
+The variation with a name supplied creates or joins the named keyring and
+attaches that as the session keyring; it then exec's the supplied command, or
+$SHELL if one isn't supplied.
+.P
+.RS
+testbox>keyctl rdescribe @s
+.br
+keyring;4043;-1;3f1f0000;_uid_ses.4043
+.P
+testbox>keyctl session
+.br
+Joined session keyring: 28
+.br
+testbox>keyctl rdescribe @s
+.br
+keyring;4043;4043;3f1f0000;_ses.24082
+.P
+testbox>keyctl session -
+.br
+Joined session keyring: 29
+.br
+testbox>keyctl rdescribe @s
+.br
+keyring;4043;4043;3f1f0000;_ses.24139
+.P
+testbox>keyctl session - keyctl rdescribe @s
+.br
+Joined session keyring: 30
+.br
+keyring;4043;4043;3f1f0000;_ses.24185
+.P
+testbox>keyctl session fish 
+.br
+Joined session keyring: 34
+.br
+testbox>keyctl rdescribe @s
+.br
+keyring;4043;4043;3f1f0000;fish
+.P
+testbox>keyctl session fish keyctl rdesc @s
+.br
+Joined session keyring: 35
+.br
+keyring;4043;4043;3f1f0000;fish
+.RE
+.P
+(*) \fBInstantiate a key\fR
+.P
+\fBkeyctl instantiate\fR <key> <data> <keyring>
+.br
+\fBkeyctl pinstantiate\fR <key> <keyring>
+.br
+\fBkeyctl negate\fR <key> <timeout> <keyring>
+.br
+\fBkeyctl reject\fR <key> <timeout> <error> <keyring>
+.P
+These commands are used to attach data to a partially set up key (as created by
+the kernel and passed to /sbin/request-key).  "instantiate" marks a key as
+being valid and attaches the data as the payload.  "negate" and "reject" mark a
+key as invalid and sets a timeout on it so that it'll go away after a while.
+This prevents a lot of quickly sequential requests from slowing the system down
+overmuch when they all fail, as all subsequent requests will then fail with
+error "Requested key not found" (if negated) or the specified error (if
+rejected) until the negative key has expired.
+.P
+Reject's error argument can either be a UNIX error number or one of
+.BR "" "'" rejected "', '" expired "' or '" revoked "'."
+.P
+The newly instantiated key will be attached to the specified keyring.
+.P
+These commands may only be run from the program run by request-key - a special
+authorisation key is set up by the kernel and attached to the request-key's
+session keyring. This special key is revoked once the key to which it refers
+has been instantiated one way or another.
+.P
+.RS
+testbox>keyctl instantiate $1 "Debug $3" $4
+.br
+testbox>keyctl negate $1 30 $4
+.br
+testbox>keyctl reject $1 30 64 $4
+.RE
+.P
+The \fBpinstantiate\fR variant of the command reads the data from stdin rather
+than taking it from the command line:
+.P
+.RS
+testbox>echo -n "Debug $3" | keyctl pinstantiate $1 $4
+.RE
+.P
+(*) \fBSet the expiry time on a key\fR
+.P
+\fBkeyctl timeout\fR <key> <timeout>
+.P
+This command is used to set the timeout on a key, or clear an existing timeout
+if the value specified is zero. The timeout is given as a number of seconds
+into the future.
+.P
+.RS
+testbox>keyctl timeout $1 45
+.RE
+.P
+(*) \fBRetrieve a key's security context\fR
+.P
+\fBkeyctl security\fR <key>
+.P
+This command is used to retrieve a key's LSM security context.  The label is
+printed on stdout.
+.P
+.RS
+testbox>keyctl security @s
+.br
+unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
+.RE
+.P
+(*) \fBGive the parent process a new session keyring\fR
+.P
+\fBkeyctl new_session\fR
+.P
+This command is used to give the invoking process (typically a shell) a new
+session keyring, discarding its old session keyring.
+.P
+.RS
+testbox> keyctl session foo
+.br
+Joined session keyring: 723488146
+.br
+testbox> keyctl show
+.br
+Session Keyring
+.br
+       -3 --alswrv      0     0  keyring: foo
+.br
+testbox> keyctl new_session
+.br
+490511412
+.br
+testbox> keyctl show
+.br
+Session Keyring
+.br
+       -3 --alswrv      0     0  keyring: _ses
+.RE
+.P
+Note that this affects the \fIparent\fP of the process that invokes the system
+call, and so may only affect processes with matching credentials.
+Furthermore, the change does not take effect till the parent process next
+transitions from kernel space to user space - typically when the \fBwait\fP()
+system call returns.
+.P
+(*) \fBRemove dead keys from the session keyring tree\fR
+.P
+\fBkeyctl reap\fR
+.P
+This command performs a depth-first search of the caller's session keyring tree
+and attempts to unlink any key that it finds that is inaccessible due to
+expiry, revocation, rejection or negation.  It does not attempt to remove live
+keys that are unavailable simply due to a lack of granted permission.
+.P
+A key that is designated reapable will only be removed from a keyring if the
+caller has Write permission on that keyring, and only keyrings that grant
+Search permission to the caller will be searched.
+.P
+The command prints the number of keys reaped before it exits.  If the \fB-v\fR
+flag is passed then the reaped keys are listed as they're being reaped,
+together with the success or failure of the unlink.
+.P
+(*) \fBRemove matching keys from the session keyring tree\fR
+.P
+\fBkeyctl\fR purge <type>
+.br
+\fBkeyctl\fR purge [-i] [-p] <type> <desc>
+.br
+\fBkeyctl\fR purge -s <type> <desc>
+.P
+These commands perform a depth-first search to find matching keys in the
+caller's session keyring tree and attempts to unlink them.  The number of
+keys successfully unlinked is printed at the end.
+.P
+The keyrings must grant Read and View permission to the caller to be searched,
+and the keys to be removed must also grant View permission.  Keys can only be
+removed from keyrings that grant Write permission.
+.P
+The first variant purges all keys of the specified type.
+.P
+The second variant purges all keys of the specified type that also match the
+given description literally.  The -i flag allows a case-independent match and
+the -p flag allows a prefix match.
+.P
+The third variant purges all keys of the specified type and matching
+description using the key type's comparator in the kernel to match the
+description.  This permits the key type to match a key with a variety of
+descriptions.
+.P
+.SH ERRORS
+.P
+There are a number of common errors returned by this program:
+.P
+"Not a directory" - a key wasn't a keyring.
+.P
+"Requested key not found" - the looked for key isn't available.
+.P
+"Key has been revoked" - a revoked key was accessed.
+.P
+"Key has expired" - an expired key was accessed.
+.P
+"Permission denied" - permission was denied by a UID/GID/mask combination.
+
+.SH SEE ALSO
+\fBkeyctl\fR(1), \fBrequest-key.conf\fR(5)
diff --git a/keyctl.3 b/keyctl.3
new file mode 100644 (file)
index 0000000..d679b7f
--- /dev/null
+++ b/keyctl.3
@@ -0,0 +1,94 @@
+.\"
+.\" Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+.\" Written by David Howells (dhowells@redhat.com)
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public Licence
+.\" as published by the Free Software Foundation; either version
+.\" 2 of the Licence, or (at your option) any later version.
+.\"
+.TH KEYCTL 3 "18 Mar 2010" Linux "Linux Key Management Calls"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+keyctl_*() \- Key management function wrappers
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+The
+.BR keyctl ()
+system call is a multiplexor for a number of key management functions.  These
+should be called via the wrappers in the libkeyutils library.
+.P
+The functions can be compiled in by including the keyutils header file:
+.sp
+.RS
+.nf
+.B #include <keyutils.h>
+.RE
+.P
+and then telling the linker it should link in the library:
+.sp
+.RS
+.nf
+.B -lkeyutils
+.RE
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH KEYCTL FUNCTIONS
+.BR keyctl_assume_authority (3)
+.br
+.BR keyctl_clear (3)
+.br
+.BR keyctl_describe (3)
+.br
+.BR keyctl_describe_alloc (3)
+.br
+.BR keyctl_get_keyring_ID (3)
+.br
+.BR keyctl_instantiate (3)
+.br
+.BR keyctl_instantiate_iov (3)
+.br
+.BR keyctl_join_session_keyring (3)
+.br
+.BR keyctl_link (3)
+.br
+.BR keyctl_negate (3)
+.br
+.BR keyctl_read (3)
+.br
+.BR keyctl_read_alloc (3)
+.br
+.BR keyctl_reject (3)
+.br
+.BR keyctl_revoke (3)
+.br
+.BR keyctl_search (3)
+.br
+.BR keyctl_security (3)
+.br
+.BR keyctl_security_alloc (3)
+.br
+.BR keyctl_set_reqkey_keyring (3)
+.br
+.BR keyctl_set_timeout (3)
+.br
+.BR keyctl_setperm (3)
+.br
+.BR keyctl_unlink (3)
+.br
+.BR keyctl_update (3)
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH UTILITY FUNCTIONS
+.BR recursive_key_scan (3)
+.br
+.BR recursive_session_key_scan (3)
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SEE ALSO
+.BR keyctl (1),
+.br
+.BR add_key (2),
+.br
+.BR keyctl (2),
+.br
+.BR request_key (2),
+.br
+.BR request-key (8)
diff --git a/keyctl.c b/keyctl.c
new file mode 100644 (file)
index 0000000..2b41367
--- /dev/null
+++ b/keyctl.c
@@ -0,0 +1,1686 @@
+/* keyctl.c: key control program
+ *
+ * Copyright (C) 2005, 2011 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <asm/unistd.h>
+#include "keyutils.h"
+
+struct command {
+       int (*action)(int argc, char *argv[]);
+       const char      *name;
+       const char      *format;
+};
+
+static int act_keyctl_show(int argc, char *argv[]);
+static int act_keyctl_add(int argc, char *argv[]);
+static int act_keyctl_padd(int argc, char *argv[]);
+static int act_keyctl_request(int argc, char *argv[]);
+static int act_keyctl_request2(int argc, char *argv[]);
+static int act_keyctl_prequest2(int argc, char *argv[]);
+static int act_keyctl_update(int argc, char *argv[]);
+static int act_keyctl_pupdate(int argc, char *argv[]);
+static int act_keyctl_newring(int argc, char *argv[]);
+static int act_keyctl_revoke(int argc, char *argv[]);
+static int act_keyctl_clear(int argc, char *argv[]);
+static int act_keyctl_link(int argc, char *argv[]);
+static int act_keyctl_unlink(int argc, char *argv[]);
+static int act_keyctl_search(int argc, char *argv[]);
+static int act_keyctl_read(int argc, char *argv[]);
+static int act_keyctl_pipe(int argc, char *argv[]);
+static int act_keyctl_print(int argc, char *argv[]);
+static int act_keyctl_list(int argc, char *argv[]);
+static int act_keyctl_rlist(int argc, char *argv[]);
+static int act_keyctl_describe(int argc, char *argv[]);
+static int act_keyctl_rdescribe(int argc, char *argv[]);
+static int act_keyctl_chown(int argc, char *argv[]);
+static int act_keyctl_chgrp(int argc, char *argv[]);
+static int act_keyctl_setperm(int argc, char *argv[]);
+static int act_keyctl_session(int argc, char *argv[]);
+static int act_keyctl_instantiate(int argc, char *argv[]);
+static int act_keyctl_pinstantiate(int argc, char *argv[]);
+static int act_keyctl_negate(int argc, char *argv[]);
+static int act_keyctl_timeout(int argc, char *argv[]);
+static int act_keyctl_security(int argc, char *argv[]);
+static int act_keyctl_new_session(int argc, char *argv[]);
+static int act_keyctl_reject(int argc, char *argv[]);
+static int act_keyctl_reap(int argc, char *argv[]);
+static int act_keyctl_purge(int argc, char *argv[]);
+
+const struct command commands[] = {
+       { act_keyctl_add,       "add",          "<type> <desc> <data> <keyring>" },
+       { act_keyctl_chgrp,     "chgrp",        "<key> <gid>" },
+       { act_keyctl_chown,     "chown",        "<key> <uid>" },
+       { act_keyctl_clear,     "clear",        "<keyring>" },
+       { act_keyctl_describe,  "describe",     "<keyring>" },
+       { act_keyctl_instantiate, "instantiate","<key> <data> <keyring>" },
+       { act_keyctl_link,      "link",         "<key> <keyring>" },
+       { act_keyctl_list,      "list",         "<keyring>" },
+       { act_keyctl_negate,    "negate",       "<key> <timeout> <keyring>" },
+       { act_keyctl_new_session, "new_session",        "" },
+       { act_keyctl_newring,   "newring",      "<name> <keyring>" },
+       { act_keyctl_padd,      "padd",         "<type> <desc> <keyring>" },
+       { act_keyctl_pinstantiate, "pinstantiate","<key> <keyring>" },
+       { act_keyctl_pipe,      "pipe",         "<key>" },
+       { act_keyctl_prequest2, "prequest2",    "<type> <desc> [<dest_keyring>]" },
+       { act_keyctl_print,     "print",        "<key>" },
+       { act_keyctl_pupdate,   "pupdate",      "<key>" },
+       { act_keyctl_purge,     "purge",        "<type>" },
+       { NULL,                 "purge",        "[-p] [-i] <type> <desc>" },
+       { NULL,                 "purge",        "-s <type> <desc>" },
+       { act_keyctl_rdescribe, "rdescribe",    "<keyring> [sep]" },
+       { act_keyctl_read,      "read",         "<key>" },
+       { act_keyctl_reap,      "reap",         "[-v]" },
+       { act_keyctl_reject,    "reject",       "<key> <timeout> <error> <keyring>" },
+       { act_keyctl_request,   "request",      "<type> <desc> [<dest_keyring>]" },
+       { act_keyctl_request2,  "request2",     "<type> <desc> <info> [<dest_keyring>]" },
+       { act_keyctl_revoke,    "revoke",       "<key>" },
+       { act_keyctl_rlist,     "rlist",        "<keyring>" },
+       { act_keyctl_search,    "search",       "<keyring> <type> <desc> [<dest_keyring>]" },
+       { act_keyctl_security,  "security",     "<key>" },
+       { act_keyctl_session,   "session",      "" },
+       { NULL,                 "session",      "- [<prog> <arg1> <arg2> ...]" },
+       { NULL,                 "session",      "<name> [<prog> <arg1> <arg2> ...]" },
+       { act_keyctl_setperm,   "setperm",      "<key> <mask>" },
+       { act_keyctl_show,      "show",         "" },
+       { act_keyctl_timeout,   "timeout",      "<key> <timeout>" },
+       { act_keyctl_unlink,    "unlink",       "<key> [<keyring>]" },
+       { act_keyctl_update,    "update",       "<key> <data>" },
+       { NULL,                 NULL,           NULL }
+};
+
+static int dump_key_tree(key_serial_t keyring, const char *name);
+static void format(void) __attribute__((noreturn));
+static void error(const char *msg) __attribute__((noreturn));
+static key_serial_t get_key_id(const char *arg);
+
+static uid_t myuid;
+static gid_t mygid, *mygroups;
+static int myngroups;
+static int verbose;
+
+/*****************************************************************************/
+/*
+ * handle an error
+ */
+static inline void error(const char *msg)
+{
+       perror(msg);
+       exit(1);
+
+} /* end error() */
+
+/*****************************************************************************/
+/*
+ * execute the appropriate subcommand
+ */
+int main(int argc, char *argv[])
+{
+       const struct command *cmd, *best;
+       int n;
+
+       argv++;
+       argc--;
+
+       if (argc == 0)
+               format();
+
+       /* find the best fit command */
+       best = NULL;
+       n = strlen(*argv);
+
+       for (cmd = commands; cmd->name; cmd++) {
+               if (!cmd->action)
+                       continue;
+               if (memcmp(cmd->name, *argv, n) != 0)
+                       continue;
+
+               if (cmd->name[n] == 0) {
+                       /* exact match */
+                       best = cmd;
+                       break;
+               }
+
+               /* partial match */
+               if (best) {
+                       fprintf(stderr, "Ambiguous command\n");
+                       exit(2);
+               }
+
+               best = cmd;
+       }
+
+       if (!best) {
+               fprintf(stderr, "Unknown command\n");
+               exit(2);
+       }
+
+       /* grab my UID, GID and groups */
+       myuid = geteuid();
+       mygid = getegid();
+       myngroups = getgroups(0, NULL);
+
+       if (myuid == -1 || mygid == -1 || myngroups == -1)
+               error("Unable to get UID/GID/#Groups\n");
+
+       mygroups = calloc(myngroups, sizeof(gid_t));
+       if (!mygroups)
+               error("calloc");
+
+       myngroups = getgroups(myngroups, mygroups);
+       if (myngroups < 0)
+               error("Unable to get Groups\n");
+
+       return best->action(argc, argv);
+
+} /* end main() */
+
+/*****************************************************************************/
+/*
+ * display command format information
+ */
+static void format(void)
+{
+       const struct command *cmd;
+
+       fprintf(stderr, "Format:\n");
+
+       for (cmd = commands; cmd->name; cmd++)
+               fprintf(stderr, "  keyctl %s %s\n", cmd->name, cmd->format);
+
+       fprintf(stderr, "\n");
+       fprintf(stderr, "Key/keyring ID:\n");
+       fprintf(stderr, "  <nnn>   numeric keyring ID\n");
+       fprintf(stderr, "  @t      thread keyring\n");
+       fprintf(stderr, "  @p      process keyring\n");
+       fprintf(stderr, "  @s      session keyring\n");
+       fprintf(stderr, "  @u      user keyring\n");
+       fprintf(stderr, "  @us     user default session keyring\n");
+       fprintf(stderr, "  @g      group keyring\n");
+       fprintf(stderr, "  @a      assumed request_key authorisation key\n");
+       fprintf(stderr, "\n");
+       fprintf(stderr, "<type> can be \"user\" for a user-defined keyring\n");
+       fprintf(stderr, "If you do this, prefix the description with \"<subtype>:\"\n");
+
+       exit(2);
+
+} /* end format() */
+
+/*****************************************************************************/
+/*
+ * grab data from stdin
+ */
+static char *grab_stdin(void)
+{
+       static char input[65536 + 1];
+       int n, tmp;
+
+       n = 0;
+       do {
+               tmp = read(0, input + n, sizeof(input) - 1 - n);
+               if (tmp < 0)
+                       error("stdin");
+
+               if (tmp == 0)
+                       break;
+
+               n += tmp;
+
+       } while (n < sizeof(input));
+
+       if (n >= sizeof(input)) {
+               fprintf(stderr, "Too much data read on stdin\n");
+               exit(1);
+       }
+
+       input[n] = '\0';
+
+       return input;
+
+} /* end grab_stdin() */
+
+/*****************************************************************************/
+/*
+ * convert the permissions mask to a string representing the permissions we
+ * have actually been granted
+ */
+static void calc_perms(char *pretty, key_perm_t perm, uid_t uid, gid_t gid)
+{
+       unsigned perms;
+       gid_t *pg;
+       int loop;
+
+       perms = (perm & KEY_POS_ALL) >> 24;
+
+       if (uid == myuid) {
+               perms |= (perm & KEY_USR_ALL) >> 16;
+               goto write_mask;
+       }
+
+       if (gid != -1) {
+               if (gid == mygid) {
+                       perms |= (perm & KEY_GRP_ALL) >> 8;
+                       goto write_mask;
+               }
+
+               pg = mygroups;
+               for (loop = myngroups; loop > 0; loop--, pg++) {
+                       if (gid == *pg) {
+                               perms |= (perm & KEY_GRP_ALL) >> 8;
+                               goto write_mask;
+                       }
+               }
+       }
+
+       perms |= (perm & KEY_OTH_ALL);
+
+write_mask:
+       sprintf(pretty, "--%c%c%c%c%c%c",
+               perms & KEY_OTH_SETATTR ? 'a' : '-',
+               perms & KEY_OTH_LINK    ? 'l' : '-',
+               perms & KEY_OTH_SEARCH  ? 's' : '-',
+               perms & KEY_OTH_WRITE   ? 'w' : '-',
+               perms & KEY_OTH_READ    ? 'r' : '-',
+               perms & KEY_OTH_VIEW    ? 'v' : '-');
+
+} /* end calc_perms() */
+
+/*****************************************************************************/
+/*
+ * show the parent process's session keyring
+ */
+static int act_keyctl_show(int argc, char *argv[])
+{
+       if (argc != 1)
+               format();
+
+       dump_key_tree(KEY_SPEC_SESSION_KEYRING, "Session Keyring");
+       return 0;
+
+} /* end act_keyctl_show() */
+
+/*****************************************************************************/
+/*
+ * add a key
+ */
+static int act_keyctl_add(int argc, char *argv[])
+{
+       key_serial_t dest;
+       int ret;
+
+       if (argc != 5)
+               format();
+
+       dest = get_key_id(argv[4]);
+
+       ret = add_key(argv[1], argv[2], argv[3], strlen(argv[3]), dest);
+       if (ret < 0)
+               error("add_key");
+
+       /* print the resulting key ID */
+       printf("%d\n", ret);
+       return 0;
+
+} /* end act_keyctl_add() */
+
+/*****************************************************************************/
+/*
+ * add a key, reading from a pipe
+ */
+static int act_keyctl_padd(int argc, char *argv[])
+{
+       char *args[6];
+
+       if (argc != 4)
+               format();
+
+       args[0] = argv[0];
+       args[1] = argv[1];
+       args[2] = argv[2];
+       args[3] = grab_stdin();
+       args[4] = argv[3];
+       args[5] = NULL;
+
+       return act_keyctl_add(5, args);
+
+} /* end act_keyctl_padd() */
+
+/*****************************************************************************/
+/*
+ * request a key
+ */
+static int act_keyctl_request(int argc, char *argv[])
+{
+       key_serial_t dest;
+       int ret;
+
+       if (argc != 3 && argc != 4)
+               format();
+
+       dest = 0;
+       if (argc == 4)
+               dest = get_key_id(argv[3]);
+
+       ret = request_key(argv[1], argv[2], NULL, dest);
+       if (ret < 0)
+               error("request_key");
+
+       /* print the resulting key ID */
+       printf("%d\n", ret);
+       return 0;
+
+} /* end act_keyctl_request() */
+
+/*****************************************************************************/
+/*
+ * request a key, with recourse to /sbin/request-key
+ */
+static int act_keyctl_request2(int argc, char *argv[])
+{
+       key_serial_t dest;
+       int ret;
+
+       if (argc != 4 && argc != 5)
+               format();
+
+       dest = 0;
+       if (argc == 5)
+               dest = get_key_id(argv[4]);
+
+       ret = request_key(argv[1], argv[2], argv[3], dest);
+       if (ret < 0)
+               error("request_key");
+
+       /* print the resulting key ID */
+       printf("%d\n", ret);
+       return 0;
+
+} /* end act_keyctl_request2() */
+
+/*****************************************************************************/
+/*
+ * request a key, with recourse to /sbin/request-key, reading the callout info
+ * from a pipe
+ */
+static int act_keyctl_prequest2(int argc, char *argv[])
+{
+       char *args[6];
+
+       if (argc != 3 && argc != 4)
+               format();
+
+       args[0] = argv[0];
+       args[1] = argv[1];
+       args[2] = argv[2];
+       args[3] = grab_stdin();
+       args[4] = argv[3];
+       args[5] = NULL;
+
+       return act_keyctl_request2(argc + 1, args);
+
+} /* end act_keyctl_prequest2() */
+
+/*****************************************************************************/
+/*
+ * update a key
+ */
+static int act_keyctl_update(int argc, char *argv[])
+{
+       key_serial_t key;
+
+       if (argc != 3)
+               format();
+
+       key = get_key_id(argv[1]);
+
+       if (keyctl_update(key, argv[2], strlen(argv[2])) < 0)
+               error("keyctl_update");
+
+       return 0;
+
+} /* end act_keyctl_update() */
+
+/*****************************************************************************/
+/*
+ * update a key, reading from a pipe
+ */
+static int act_keyctl_pupdate(int argc, char *argv[])
+{
+       char *args[4];
+
+       if (argc != 2)
+               format();
+
+       args[0] = argv[0];
+       args[1] = argv[1];
+       args[2] = grab_stdin();
+       args[3] = NULL;
+
+       return act_keyctl_update(3, args);
+
+} /* end act_keyctl_pupdate() */
+
+/*****************************************************************************/
+/*
+ * create a new keyring
+ */
+static int act_keyctl_newring(int argc, char *argv[])
+{
+       key_serial_t dest;
+       int ret;
+
+       if (argc != 3)
+               format();
+
+       dest = get_key_id(argv[2]);
+
+       ret = add_key("keyring", argv[1], NULL, 0, dest);
+       if (ret < 0)
+               error("add_key");
+
+       printf("%d\n", ret);
+       return 0;
+
+} /* end act_keyctl_newring() */
+
+/*****************************************************************************/
+/*
+ * revoke a key
+ */
+static int act_keyctl_revoke(int argc, char *argv[])
+{
+       key_serial_t key;
+
+       if (argc != 2)
+               format();
+
+       key = get_key_id(argv[1]);
+
+       if (keyctl_revoke(key) < 0)
+               error("keyctl_revoke");
+
+       return 0;
+
+} /* end act_keyctl_revoke() */
+
+/*****************************************************************************/
+/*
+ * clear a keyring
+ */
+static int act_keyctl_clear(int argc, char *argv[])
+{
+       key_serial_t keyring;
+
+       if (argc != 2)
+               format();
+
+       keyring = get_key_id(argv[1]);
+
+       if (keyctl_clear(keyring) < 0)
+               error("keyctl_clear");
+
+       return 0;
+
+} /* end act_keyctl_clear() */
+
+/*****************************************************************************/
+/*
+ * link a key to a keyring
+ */
+static int act_keyctl_link(int argc, char *argv[])
+{
+       key_serial_t keyring, key;
+
+       if (argc != 3)
+               format();
+
+       key = get_key_id(argv[1]);
+       keyring = get_key_id(argv[2]);
+
+       if (keyctl_link(key, keyring) < 0)
+               error("keyctl_link");
+
+       return 0;
+
+} /* end act_keyctl_link() */
+
+/*
+ * Attempt to unlink a key matching the ID
+ */
+static int act_keyctl_unlink_func(key_serial_t parent, key_serial_t key,
+                                 char *desc, int desc_len, void *data)
+{
+       key_serial_t *target = data;
+
+       if (key == *target)
+               return keyctl_unlink(key, parent) < 0 ? 0 : 1;
+       return 0;
+}
+
+/*
+ * Unlink a key from a keyring or from the session keyring tree.
+ */
+static int act_keyctl_unlink(int argc, char *argv[])
+{
+       key_serial_t keyring, key;
+       int n;
+
+       if (argc != 2 && argc != 3)
+               format();
+
+       key = get_key_id(argv[1]);
+
+       if (argc == 3) {
+               keyring = get_key_id(argv[2]);
+               if (keyctl_unlink(key, keyring) < 0)
+                       error("keyctl_unlink");
+       } else {
+               n = recursive_session_key_scan(act_keyctl_unlink_func, &key);
+               printf("%d links removed\n", n);
+       }
+
+       return 0;
+}
+
+/*****************************************************************************/
+/*
+ * search a keyring for a key
+ */
+static int act_keyctl_search(int argc, char *argv[])
+{
+       key_serial_t keyring, dest;
+       int ret;
+
+       if (argc != 4 && argc != 5)
+               format();
+
+       keyring = get_key_id(argv[1]);
+
+       dest = 0;
+       if (argc == 5)
+               dest = get_key_id(argv[4]);
+
+       ret = keyctl_search(keyring, argv[2], argv[3], dest);
+       if (ret < 0)
+               error("keyctl_search");
+
+       /* print the ID of the key we found */
+       printf("%d\n", ret);
+       return 0;
+
+} /* end act_keyctl_search() */
+
+/*****************************************************************************/
+/*
+ * read a key
+ */
+static int act_keyctl_read(int argc, char *argv[])
+{
+       key_serial_t key;
+       void *buffer;
+       char *p;
+       int ret, sep, col;
+
+       if (argc != 2)
+               format();
+
+       key = get_key_id(argv[1]);
+
+       /* read the key payload data */
+       ret = keyctl_read_alloc(key, &buffer);
+       if (ret < 0)
+               error("keyctl_read_alloc");
+
+       if (ret == 0) {
+               printf("No data in key\n");
+               return 0;
+       }
+
+       /* hexdump the contents */
+       printf("%u bytes of data in key:\n", ret);
+
+       sep = 0;
+       col = 0;
+       p = buffer;
+
+       do {
+               if (sep) {
+                       putchar(sep);
+                       sep = 0;
+               }
+
+               printf("%02hhx", *p);
+               p++;
+
+               col++;
+               if (col % 32 == 0)
+                       sep = '\n';
+               else if (col % 4 == 0)
+                       sep = ' ';
+
+       } while (--ret > 0);
+
+       printf("\n");
+       return 0;
+
+} /* end act_keyctl_read() */
+
+/*****************************************************************************/
+/*
+ * read a key and dump raw to stdout
+ */
+static int act_keyctl_pipe(int argc, char *argv[])
+{
+       key_serial_t key;
+       void *buffer;
+       int ret;
+
+       if (argc != 2)
+               format();
+
+       key = get_key_id(argv[1]);
+
+       /* read the key payload data */
+       ret = keyctl_read_alloc(key, &buffer);
+       if (ret < 0)
+               error("keyctl_read_alloc");
+
+       if (ret > 0 && write(1, buffer, ret) < 0)
+               error("write");
+       return 0;
+
+} /* end act_keyctl_pipe() */
+
+/*****************************************************************************/
+/*
+ * read a key and dump to stdout in printable form
+ */
+static int act_keyctl_print(int argc, char *argv[])
+{
+       key_serial_t key;
+       void *buffer;
+       char *p;
+       int loop, ret;
+
+       if (argc != 2)
+               format();
+
+       key = get_key_id(argv[1]);
+
+       /* read the key payload data */
+       ret = keyctl_read_alloc(key, &buffer);
+       if (ret < 0)
+               error("keyctl_read_alloc");
+
+       /* see if it's printable */
+       p = buffer;
+       for (loop = ret; loop > 0; loop--, p++)
+               if (!isprint(*p))
+                       goto not_printable;
+
+       /* it is */
+       printf("%s\n", (char *) buffer);
+       return 0;
+
+not_printable:
+       /* it isn't */
+       printf(":hex:");
+       p = buffer;
+       for (loop = ret; loop > 0; loop--, p++)
+               printf("%02hhx", *p);
+       printf("\n");
+       return 0;
+
+} /* end act_keyctl_print() */
+
+/*****************************************************************************/
+/*
+ * list a keyring
+ */
+static int act_keyctl_list(int argc, char *argv[])
+{
+       key_serial_t keyring, key, *pk;
+       key_perm_t perm;
+       void *keylist;
+       char *buffer, pretty_mask[9];
+       uid_t uid;
+       gid_t gid;
+       int count, tlen, dpos, n, ret;
+
+       if (argc != 2)
+               format();
+
+       keyring = get_key_id(argv[1]);
+
+       /* read the key payload data */
+       count = keyctl_read_alloc(keyring, &keylist);
+       if (count < 0)
+               error("keyctl_read_alloc");
+
+       count /= sizeof(key_serial_t);
+
+       if (count == 0) {
+               printf("keyring is empty\n");
+               return 0;
+       }
+
+       /* list the keys in the keyring */
+       if (count == 1)
+               printf("1 key in keyring:\n");
+       else
+               printf("%u keys in keyring:\n", count);
+
+       pk = keylist;
+       do {
+               key = *pk++;
+
+               ret = keyctl_describe_alloc(key, &buffer);
+               if (ret < 0) {
+                       printf("%9d: key inaccessible (%m)\n", key);
+                       continue;
+               }
+
+               uid = 0;
+               gid = 0;
+               perm = 0;
+
+               tlen = -1;
+               dpos = -1;
+
+               n = sscanf((char *) buffer, "%*[^;]%n;%d;%d;%x;%n",
+                          &tlen, &uid, &gid, &perm, &dpos);
+               if (n != 3) {
+                       fprintf(stderr, "Unparseable description obtained for key %d\n", key);
+                       exit(3);
+               }
+
+               calc_perms(pretty_mask, perm, uid, gid);
+
+               printf("%9d: %s %5d %5d %*.*s: %s\n",
+                      key,
+                      pretty_mask,
+                      uid, gid,
+                      tlen, tlen, buffer,
+                      buffer + dpos);
+
+               free(buffer);
+
+       } while (--count);
+
+       return 0;
+
+} /* end act_keyctl_list() */
+
+/*****************************************************************************/
+/*
+ * produce a raw list of a keyring
+ */
+static int act_keyctl_rlist(int argc, char *argv[])
+{
+       key_serial_t keyring, key, *pk;
+       void *keylist;
+       int count;
+
+       if (argc != 2)
+               format();
+
+       keyring = get_key_id(argv[1]);
+
+       /* read the key payload data */
+       count = keyctl_read_alloc(keyring, &keylist);
+       if (count < 0)
+               error("keyctl_read_alloc");
+
+       count /= sizeof(key_serial_t);
+
+       /* list the keys in the keyring */
+       if (count <= 0) {
+               printf("\n");
+       }
+       else {
+               pk = keylist;
+               for (; count > 0; count--) {
+                       key = *pk++;
+                       printf("%d%c", key, count == 1 ? '\n' : ' ');
+               }
+       }
+
+       return 0;
+
+} /* end act_keyctl_rlist() */
+
+/*****************************************************************************/
+/*
+ * describe a key
+ */
+static int act_keyctl_describe(int argc, char *argv[])
+{
+       key_serial_t key;
+       key_perm_t perm;
+       char *buffer;
+       uid_t uid;
+       gid_t gid;
+       int tlen, dpos, n, ret;
+
+       if (argc != 2)
+               format();
+
+       key = get_key_id(argv[1]);
+
+       /* get key description */
+       ret = keyctl_describe_alloc(key, &buffer);
+       if (ret < 0)
+               error("keyctl_describe");
+
+       /* parse it */
+       uid = 0;
+       gid = 0;
+       perm = 0;
+
+       tlen = -1;
+       dpos = -1;
+
+       n = sscanf(buffer, "%*[^;]%n;%d;%d;%x;%n",
+                  &tlen, &uid, &gid, &perm, &dpos);
+       if (n != 3) {
+               fprintf(stderr, "Unparseable description obtained for key %d\n", key);
+               exit(3);
+       }
+
+       /* display it */
+       printf("%9d:"
+              " %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c"
+              " %5d %5d %*.*s: %s\n",
+              key,
+              perm & KEY_POS_SETATTR   ? 'a' : '-',
+              perm & KEY_POS_LINK      ? 'l' : '-',
+              perm & KEY_POS_SEARCH    ? 's' : '-',
+              perm & KEY_POS_WRITE     ? 'w' : '-',
+              perm & KEY_POS_READ      ? 'r' : '-',
+              perm & KEY_POS_VIEW      ? 'v' : '-',
+
+              perm & KEY_USR_SETATTR   ? 'a' : '-',
+              perm & KEY_USR_LINK      ? 'l' : '-',
+              perm & KEY_USR_SEARCH    ? 's' : '-',
+              perm & KEY_USR_WRITE     ? 'w' : '-',
+              perm & KEY_USR_READ      ? 'r' : '-',
+              perm & KEY_USR_VIEW      ? 'v' : '-',
+
+              perm & KEY_GRP_SETATTR   ? 'a' : '-',
+              perm & KEY_GRP_LINK      ? 'l' : '-',
+              perm & KEY_GRP_SEARCH    ? 's' : '-',
+              perm & KEY_GRP_WRITE     ? 'w' : '-',
+              perm & KEY_GRP_READ      ? 'r' : '-',
+              perm & KEY_GRP_VIEW      ? 'v' : '-',
+
+              perm & KEY_OTH_SETATTR   ? 'a' : '-',
+              perm & KEY_OTH_LINK      ? 'l' : '-',
+              perm & KEY_OTH_SEARCH    ? 's' : '-',
+              perm & KEY_OTH_WRITE     ? 'w' : '-',
+              perm & KEY_OTH_READ      ? 'r' : '-',
+              perm & KEY_OTH_VIEW      ? 'v' : '-',
+              uid, gid,
+              tlen, tlen, buffer,
+              buffer + dpos);
+
+       return 0;
+
+} /* end act_keyctl_describe() */
+
+/*****************************************************************************/
+/*
+ * get raw key description
+ */
+static int act_keyctl_rdescribe(int argc, char *argv[])
+{
+       key_serial_t key;
+       char *buffer, *q;
+       int ret;
+
+       if (argc != 2 && argc != 3)
+               format();
+       if (argc == 3 && !argv[2][0])
+               format();
+
+       key = get_key_id(argv[1]);
+
+       /* get key description */
+       ret = keyctl_describe_alloc(key, &buffer);
+       if (ret < 0)
+               error("keyctl_describe");
+
+       /* replace semicolon separators with requested alternative */
+       if (argc == 3) {
+               for (q = buffer; *q; q++)
+                       if (*q == ';')
+                               *q = argv[2][0];
+       }
+
+       /* display raw description */
+       printf("%s\n", buffer);
+       return 0;
+
+} /* end act_keyctl_rdescribe() */
+
+/*****************************************************************************/
+/*
+ * change a key's ownership
+ */
+static int act_keyctl_chown(int argc, char *argv[])
+{
+       key_serial_t key;
+       uid_t uid;
+       char *q;
+
+       if (argc != 3)
+               format();
+
+       key = get_key_id(argv[1]);
+
+       uid = strtoul(argv[2], &q, 0);
+       if (*q) {
+               fprintf(stderr, "Unparsable uid: '%s'\n", argv[2]);
+               exit(2);
+       }
+
+       if (keyctl_chown(key, uid, -1) < 0)
+               error("keyctl_chown");
+
+       return 0;
+
+} /* end act_keyctl_chown() */
+
+/*****************************************************************************/
+/*
+ * change a key's group ownership
+ */
+static int act_keyctl_chgrp(int argc, char *argv[])
+{
+       key_serial_t key;
+       gid_t gid;
+       char *q;
+
+       if (argc != 3)
+               format();
+
+       key = get_key_id(argv[1]);
+
+       gid = strtoul(argv[2], &q, 0);
+       if (*q) {
+               fprintf(stderr, "Unparsable gid: '%s'\n", argv[2]);
+               exit(2);
+       }
+
+       if (keyctl_chown(key, -1, gid) < 0)
+               error("keyctl_chown");
+
+       return 0;
+
+} /* end act_keyctl_chgrp() */
+
+/*****************************************************************************/
+/*
+ * set the permissions on a key
+ */
+static int act_keyctl_setperm(int argc, char *argv[])
+{
+       key_serial_t key;
+       key_perm_t perm;
+       char *q;
+
+       if (argc != 3)
+               format();
+
+       key = get_key_id(argv[1]);
+       perm = strtoul(argv[2], &q, 0);
+       if (*q) {
+               fprintf(stderr, "Unparsable permissions: '%s'\n", argv[2]);
+               exit(2);
+       }
+
+       if (keyctl_setperm(key, perm) < 0)
+               error("keyctl_setperm");
+
+       return 0;
+
+} /* end act_keyctl_setperm() */
+
+/*****************************************************************************/
+/*
+ * start a process in a new session
+ */
+static int act_keyctl_session(int argc, char *argv[])
+{
+       char *p, *q;
+       int ret;
+
+       argv++;
+       argc--;
+
+       /* no extra arguments signifies a standard shell in an anonymous
+        * session */
+       p = NULL;
+       if (argc != 0) {
+               /* a dash signifies an anonymous session */
+               p = *argv;
+               if (strcmp(p, "-") == 0)
+                       p = NULL;
+
+               argv++;
+               argc--;
+       }
+
+       /* create a new session keyring */
+       ret = keyctl_join_session_keyring(p);
+       if (ret < 0)
+               error("keyctl_join_session_keyring");
+
+       fprintf(stderr, "Joined session keyring: %d\n", ret);
+
+       /* run the standard shell if no arguments */
+       if (argc == 0) {
+               q = getenv("SHELL");
+               if (!q)
+                       q = "/bin/sh";
+               execl(q, q, NULL);
+               error(q);
+       }
+
+       /* run the command specified */
+       execvp(argv[0], argv);
+       error(argv[0]);
+
+} /* end act_keyctl_session() */
+
+/*****************************************************************************/
+/*
+ * instantiate a key that's under construction
+ */
+static int act_keyctl_instantiate(int argc, char *argv[])
+{
+       key_serial_t key, dest;
+
+       if (argc != 4)
+               format();
+
+       key = get_key_id(argv[1]);
+       dest = get_key_id(argv[3]);
+
+       if (keyctl_instantiate(key, argv[2], strlen(argv[2]), dest) < 0)
+               error("keyctl_instantiate");
+
+       return 0;
+
+} /* end act_keyctl_instantiate() */
+
+/*****************************************************************************/
+/*
+ * instantiate a key, reading from a pipe
+ */
+static int act_keyctl_pinstantiate(int argc, char *argv[])
+{
+       char *args[5];
+
+       if (argc != 3)
+               format();
+
+       args[0] = argv[0];
+       args[1] = argv[1];
+       args[2] = grab_stdin();
+       args[3] = argv[2];
+       args[4] = NULL;
+
+       return act_keyctl_instantiate(4, args);
+
+} /* end act_keyctl_pinstantiate() */
+
+/*****************************************************************************/
+/*
+ * negate a key that's under construction
+ */
+static int act_keyctl_negate(int argc, char *argv[])
+{
+       unsigned long timeout;
+       key_serial_t key, dest;
+       char *q;
+
+       if (argc != 4)
+               format();
+
+       key = get_key_id(argv[1]);
+
+       timeout = strtoul(argv[2], &q, 10);
+       if (*q) {
+               fprintf(stderr, "Unparsable timeout: '%s'\n", argv[2]);
+               exit(2);
+       }
+
+       dest = get_key_id(argv[3]);
+
+       if (keyctl_negate(key, timeout, dest) < 0)
+               error("keyctl_negate");
+
+       return 0;
+
+} /* end act_keyctl_negate() */
+
+/*****************************************************************************/
+/*
+ * set a key's timeout
+ */
+static int act_keyctl_timeout(int argc, char *argv[])
+{
+       unsigned long timeout;
+       key_serial_t key;
+       char *q;
+
+       if (argc != 3)
+               format();
+
+       key = get_key_id(argv[1]);
+
+       timeout = strtoul(argv[2], &q, 10);
+       if (*q) {
+               fprintf(stderr, "Unparsable timeout: '%s'\n", argv[2]);
+               exit(2);
+       }
+
+       if (keyctl_set_timeout(key, timeout) < 0)
+               error("keyctl_set_timeout");
+
+       return 0;
+
+} /* end act_keyctl_timeout() */
+
+/*****************************************************************************/
+/*
+ * get a key's security label
+ */
+static int act_keyctl_security(int argc, char *argv[])
+{
+       key_serial_t key;
+       char *buffer;
+       int ret;
+
+       if (argc != 2)
+               format();
+
+       key = get_key_id(argv[1]);
+
+       /* get key description */
+       ret = keyctl_get_security_alloc(key, &buffer);
+       if (ret < 0)
+               error("keyctl_getsecurity");
+
+       printf("%s\n", buffer);
+       return 0;
+}
+
+/*****************************************************************************/
+/*
+ * install a new session keyring on the parent process
+ */
+static int act_keyctl_new_session(int argc, char *argv[])
+{
+       key_serial_t keyring;
+
+       if (argc != 1)
+               format();
+
+       if (keyctl_join_session_keyring(NULL) < 0)
+               error("keyctl_join_session_keyring");
+
+       if (keyctl_session_to_parent() < 0)
+               error("keyctl_session_to_parent");
+
+       keyring = keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 0);
+       if (keyring < 0)
+               error("keyctl_get_keyring_ID");
+
+       /* print the resulting key ID */
+       printf("%d\n", keyring);
+       return 0;
+}
+
+/*****************************************************************************/
+/*
+ * reject a key that's under construction
+ */
+static int act_keyctl_reject(int argc, char *argv[])
+{
+       unsigned long timeout;
+       key_serial_t key, dest;
+       unsigned long rejerr;
+       char *q;
+
+       if (argc != 5)
+               format();
+
+       key = get_key_id(argv[1]);
+
+       timeout = strtoul(argv[2], &q, 10);
+       if (*q) {
+               fprintf(stderr, "Unparsable timeout: '%s'\n", argv[2]);
+               exit(2);
+       }
+
+       if (strcmp(argv[3], "rejected") == 0) {
+               rejerr = EKEYREJECTED;
+       } else if (strcmp(argv[3], "revoked") == 0) {
+               rejerr = EKEYREVOKED;
+       } else if (strcmp(argv[3], "expired") == 0) {
+               rejerr = EKEYEXPIRED;
+       } else {
+               rejerr = strtoul(argv[3], &q, 10);
+               if (*q) {
+                       fprintf(stderr, "Unparsable error: '%s'\n", argv[3]);
+                       exit(2);
+               }
+       }
+
+       dest = get_key_id(argv[4]);
+
+       if (keyctl_reject(key, timeout, rejerr, dest) < 0)
+               error("keyctl_negate");
+
+       return 0;
+}
+
+/*
+ * Attempt to unlink a key if we can't read it for reasons other than we don't
+ * have permission
+ */
+static int act_keyctl_reap_func(key_serial_t parent, key_serial_t key,
+                               char *desc, int desc_len, void *data)
+{
+       if (desc_len < 0 && errno != EACCES) {
+               if (verbose)
+                       printf("Reap %d", key);
+               if (keyctl_unlink(key, parent) < 0) {
+                       if (verbose)
+                               printf("... failed %m\n");
+                       return 0;
+               } else {
+                       if (verbose)
+                               printf("\n");
+                       return 1;
+               };
+       }
+       return 0;
+}
+
+/*
+ * Reap the dead keys from the session keyring tree
+ */
+static int act_keyctl_reap(int argc, char *argv[])
+{
+       int n;
+
+       if (argc > 1 && strcmp(argv[1], "-v") == 0) {
+               verbose = 1;
+               argc--;
+               argv++;
+       }
+
+       if (argc != 1)
+               format();
+
+       n = recursive_session_key_scan(act_keyctl_reap_func, NULL);
+       printf("%d keys reaped\n", n);
+       return 0;
+}
+
+struct purge_data {
+       const char      *type;
+       const char      *desc;
+       size_t          desc_len;
+       size_t          type_len;
+       char            prefix_match;
+       char            case_indep;
+};
+
+/*
+ * Attempt to unlink a key matching the type
+ */
+static int act_keyctl_purge_type_func(key_serial_t parent, key_serial_t key,
+                                     char *raw, int raw_len, void *data)
+{
+       const struct purge_data *purge = data;
+       char *p, *type;
+
+       if (parent == 0 || !raw)
+               return 0;
+
+       /* type is everything before the first semicolon */
+       type = raw;
+       p = memchr(raw, ';', raw_len);
+       if (!p)
+               return 0;
+       *p = 0;
+       if (strcmp(type, purge->type) != 0)
+               return 0;
+
+       return keyctl_unlink(key, parent) < 0 ? 0 : 1;
+}
+
+/*
+ * Attempt to unlink a key matching the type and description literally
+ */
+static int act_keyctl_purge_literal_func(key_serial_t parent, key_serial_t key,
+                                        char *raw, int raw_len, void *data)
+{
+       const struct purge_data *purge = data;
+       size_t tlen;
+       char *p, *type, *desc;
+
+       if (parent == 0 || !raw)
+               return 0;
+
+       /* type is everything before the first semicolon */
+       type = raw;
+       p = memchr(type, ';', raw_len);
+       if (!p)
+               return 0;
+
+       tlen = p - type;
+       if (tlen != purge->type_len)
+               return 0;
+       if (memcmp(type, purge->type, tlen) != 0)
+               return 0;
+
+       /* description is everything after the last semicolon */
+       p++;
+       desc = memrchr(p, ';', raw + raw_len - p);
+       if (!desc)
+               return 0;
+       desc++;
+
+       if (purge->prefix_match) {
+               if (raw_len - (desc - raw) < purge->desc_len)
+                       return 0;
+       } else {
+               if (raw_len - (desc - raw) != purge->desc_len)
+                       return 0;
+       }
+
+       if (purge->case_indep) {
+               if (strncasecmp(purge->desc, desc, purge->desc_len) != 0)
+                       return 0;
+       } else {
+               if (memcmp(purge->desc, desc, purge->desc_len) != 0)
+                       return 0;
+       }
+
+       printf("%*.*s '%s'\n", (int)tlen, (int)tlen, type, desc);
+
+       return keyctl_unlink(key, parent) < 0 ? 0 : 1;
+}
+
+/*
+ * Attempt to unlink a key matching the type and description literally
+ */
+static int act_keyctl_purge_search_func(key_serial_t parent, key_serial_t keyring,
+                                       char *raw, int raw_len, void *data)
+{
+       const struct purge_data *purge = data;
+       key_serial_t key;
+       int kcount = 0;
+
+       if (!raw || memcmp(raw, "keyring;", 8) != 0)
+               return 0;
+
+       for (;;) {
+               key = keyctl_search(keyring, purge->type, purge->desc, 0);
+               if (keyctl_unlink(key, keyring) < 0)
+                       return kcount;
+               kcount++;
+       }
+       return kcount;
+}
+
+/*
+ * Purge matching keys from a keyring
+ */
+static int act_keyctl_purge(int argc, char *argv[])
+{
+       recursive_key_scanner_t func;
+       struct purge_data purge = {
+               .prefix_match   = 0,
+               .case_indep     = 0,
+       };
+       int n = 0, search_mode = 0;
+
+       argc--;
+       argv++;
+       while (argc > 0 && argv[0][0] == '-') {
+               if (argv[0][1] == 's')
+                       search_mode = 1;
+               else if (argv[0][1] == 'p')
+                       purge.prefix_match = 1;
+               else if (argv[0][1] == 'i')
+                       purge.case_indep = 1;
+               else
+                       format();
+               argc--;
+               argv++;
+       }
+
+       if (argc < 1)
+               format();
+
+       purge.type      = argv[0];
+       purge.desc      = argv[1];
+       purge.type_len  = strlen(purge.type);
+       purge.desc_len  = purge.desc ? strlen(purge.desc) : 0;
+
+       if (search_mode == 1) {
+               if (argc != 2 || purge.prefix_match || purge.case_indep)
+                       format();
+               /* purge all keys of a specific type and description, according
+                * to the kernel's comparator */
+               func = act_keyctl_purge_search_func;
+       } else if (argc == 1) {
+               if (purge.prefix_match || purge.case_indep)
+                       format();
+               /* purge all keys of a specific type */
+               func = act_keyctl_purge_type_func;
+       } else if (argc == 2) {
+               /* purge all keys of a specific type with literally matching
+                * description */
+               func = act_keyctl_purge_literal_func;
+       } else {
+               format();
+       }
+
+       n = recursive_session_key_scan(func, &purge);
+       printf("purged %d keys\n", n);
+       return 0;
+}
+
+/*****************************************************************************/
+/*
+ * parse a key identifier
+ */
+static key_serial_t get_key_id(const char *arg)
+{
+       key_serial_t id;
+       char *end;
+
+       /* handle a special keyring name */
+       if (arg[0] == '@') {
+               if (strcmp(arg, "@t" ) == 0) return KEY_SPEC_THREAD_KEYRING;
+               if (strcmp(arg, "@p" ) == 0) return KEY_SPEC_PROCESS_KEYRING;
+               if (strcmp(arg, "@s" ) == 0) return KEY_SPEC_SESSION_KEYRING;
+               if (strcmp(arg, "@u" ) == 0) return KEY_SPEC_USER_KEYRING;
+               if (strcmp(arg, "@us") == 0) return KEY_SPEC_USER_SESSION_KEYRING;
+               if (strcmp(arg, "@g" ) == 0) return KEY_SPEC_GROUP_KEYRING;
+               if (strcmp(arg, "@a" ) == 0) return KEY_SPEC_REQKEY_AUTH_KEY;
+
+               fprintf(stderr, "Unknown special key: '%s'\n", arg);
+               exit(2);
+       }
+
+       /* handle a numeric key ID */
+       id = strtoul(arg, &end, 0);
+       if (*end) {
+               fprintf(stderr, "Unparsable key: '%s'\n", arg);
+               exit(2);
+       }
+
+       return id;
+
+} /* end get_key_id() */
+
+/*****************************************************************************/
+/*
+ * recursively display a key/keyring tree
+ */
+static int dump_key_tree_aux(key_serial_t key, int depth, int more)
+{
+       static char dumpindent[64];
+       key_serial_t *pk;
+       key_perm_t perm;
+       size_t ringlen, desclen;
+       void *payload;
+       char *desc, type[255], pretty_mask[9];
+       int uid, gid, ret, n, dpos, rdepth, kcount = 0;
+
+       if (depth > 8)
+               return 0;
+
+       /* find out how big this key's description is */
+       ret = keyctl_describe(key, NULL, 0);
+       if (ret < 0) {
+               printf("%d: key inaccessible (%m)\n", key);
+               return 0;
+       }
+       desclen = ret + 1;
+
+       desc = malloc(desclen);
+       if (!desc)
+               error("malloc");
+
+       /* read the description */
+       ret = keyctl_describe(key, desc, desclen);
+       if (ret < 0) {
+               printf("%d: key inaccessible (%m)\n", key);
+               free(desc);
+               return 0;
+       }
+
+       desclen = ret < desclen ? ret : desclen;
+
+       desc[desclen] = 0;
+
+       /* parse */
+       type[0] = 0;
+       uid = 0;
+       gid = 0;
+       perm = 0;
+
+       n = sscanf(desc, "%[^;];%d;%d;%x;%n",
+                  type, &uid, &gid, &perm, &dpos);
+
+       if (n != 4) {
+               fprintf(stderr, "Unparseable description obtained for key %d\n", key);
+               exit(3);
+       }
+
+       /* and print */
+       calc_perms(pretty_mask, perm, uid, gid);
+
+       printf("%9d %s  %5d %5d  %s%s%s: %s\n",
+              key,
+              pretty_mask,
+              uid, gid,
+              dumpindent,
+              depth > 0 ? "\\_ " : "",
+              type, desc + dpos);
+
+       /* if it's a keyring then we're going to want to recursively
+        * display it if we can */
+       if (strcmp(type, "keyring") == 0) {
+               /* find out how big the keyring is */
+               ret = keyctl_read(key, NULL, 0);
+               if (ret < 0)
+                       error("keyctl_read");
+               if (ret == 0)
+                       return 0;
+               ringlen = ret;
+
+               /* read its contents */
+               payload = malloc(ringlen);
+               if (!payload)
+                       error("malloc");
+
+               ret = keyctl_read(key, payload, ringlen);
+               if (ret < 0)
+                       error("keyctl_read");
+
+               ringlen = ret < ringlen ? ret : ringlen;
+               kcount = ringlen / sizeof(key_serial_t);
+
+               /* walk the keyring */
+               pk = payload;
+               do {
+                       key = *pk++;
+
+                       /* recurse into nexted keyrings */
+                       if (strcmp(type, "keyring") == 0) {
+                               if (depth == 0) {
+                                       rdepth = depth;
+                                       dumpindent[rdepth++] = ' ';
+                                       dumpindent[rdepth] = 0;
+                               }
+                               else {
+                                       rdepth = depth;
+                                       dumpindent[rdepth++] = ' ';
+                                       dumpindent[rdepth++] = ' ';
+                                       dumpindent[rdepth++] = ' ';
+                                       dumpindent[rdepth++] = ' ';
+                                       dumpindent[rdepth] = 0;
+                               }
+
+                               if (more)
+                                       dumpindent[depth + 0] = '|';
+
+                               kcount += dump_key_tree_aux(key,
+                                                           rdepth,
+                                                           ringlen - 4 >= sizeof(key_serial_t));
+                       }
+
+               } while (ringlen -= 4, ringlen >= sizeof(key_serial_t));
+
+               free(payload);
+       }
+
+       free(desc);
+       return kcount;
+
+} /* end dump_key_tree_aux() */
+
+/*****************************************************************************/
+/*
+ * recursively list a keyring's contents
+ */
+static int dump_key_tree(key_serial_t keyring, const char *name)
+{
+       printf("%s\n", name);
+       return dump_key_tree_aux(keyring, 0, 0);
+
+} /* end dump_key_tree() */
diff --git a/keyctl_chown.3 b/keyctl_chown.3
new file mode 100644 (file)
index 0000000..2492ec1
--- /dev/null
@@ -0,0 +1,88 @@
+.\"
+.\" Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+.\" Written by David Howells (dhowells@redhat.com)
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License
+.\" as published by the Free Software Foundation; either version
+.\" 2 of the License, or (at your option) any later version.
+.\"
+.TH KEYCTL_CHOWN 3 "4 May 2006" Linux "Linux Key Management Calls"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+keyctl_chown \- Change the ownership of a key
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SYNOPSIS
+.nf
+.B #include <keyutils.h>
+.sp
+.BI "long keyctl_chown(key_serial_t " key ", uid_t " uid ", gid_t " gid ");"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+.BR keyctl_chown ()
+changes the user and group ownership details of a key.
+.P
+A setting of
+.B -1
+on either
+.I uid
+or
+.I gid
+will cause that setting to be ignored.
+.P
+A process that does not have the
+.B SysAdmin
+capability may not change a key's UID or set the key's GID to a value that
+does not match the process's GID or one of its group list.
+.P
+The caller must have
+.B setattr
+permission on a key to be able change its ownership.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+On success
+.BR keyctl_chown ()
+returns
+.B 0 .
+On error, the value
+.B -1
+will be returned and errno will have been set to an appropriate error.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH ERRORS
+.TP
+.B ENOKEY
+The specified key does not exist.
+.TP
+.B EKEYEXPIRED
+The specified key has expired.
+.TP
+.B EKEYREVOKED
+The specified key has been revoked.
+.TP
+.B EDQUOT
+Changing the UID to the one specified would run that UID out of quota.
+.TP
+.B EACCES
+The key exists, but does not grant
+.B setattr
+permission to the calling process.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH LINKING
+This is a library function that can be found in
+.IR libkeyutils .
+When linking,
+.B -lkeyutils
+should be specified to the linker.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SEE ALSO
+.BR keyctl (1),
+.br
+.BR add_key (2),
+.br
+.BR keyctl (2),
+.br
+.BR request_key (2),
+.br
+.BR keyctl (3),
+.br
+.BR request-key (8)
diff --git a/keyctl_clear.3 b/keyctl_clear.3
new file mode 100644 (file)
index 0000000..87e543e
--- /dev/null
@@ -0,0 +1,73 @@
+.\"
+.\" Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+.\" Written by David Howells (dhowells@redhat.com)
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License
+.\" as published by the Free Software Foundation; either version
+.\" 2 of the License, or (at your option) any later version.
+.\"
+.TH KEYCTL_CLEAR 3 "4 May 2006" Linux "Linux Key Management Calls"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+keyctl_clear \- Clear a keyring
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SYNOPSIS
+.nf
+.B #include <keyutils.h>
+.sp
+.BI "long keyctl_clear(key_serial_t " keyring ");"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+.BR keyctl_clear ()
+clears the contents of a
+.IR keyring .
+.P
+The caller must have
+.B write
+permission on a keyring to be able clear it.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+On success
+.BR keyctl_clear ()
+returns
+.BR 0 .
+On error, the value
+.B -1
+will be returned and errno will have been set to an appropriate error.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH ERRORS
+.TP
+.B ENOKEY
+The keyring specified is invalid.
+.TP
+.B EKEYEXPIRED
+The keyring specified has expired.
+.TP
+.B EKEYREVOKED
+The keyring specified had been revoked.
+.TP
+.B EACCES
+The keyring exists, but is not
+.B writable
+by the calling process.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH LINKING
+This is a library function that can be found in
+.IR libkeyutils .
+When linking,
+.B -lkeyutils
+should be specified to the linker.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SEE ALSO
+.BR keyctl (1),
+.br
+.BR add_key (2),
+.br
+.BR keyctl (2),
+.br
+.BR request_key (2),
+.br
+.BR keyctl (3),
+.br
+.BR request-key (8)
diff --git a/keyctl_describe.3 b/keyctl_describe.3
new file mode 100644 (file)
index 0000000..e125ab8
--- /dev/null
@@ -0,0 +1,110 @@
+.\"
+.\" Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+.\" Written by David Howells (dhowells@redhat.com)
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License
+.\" as published by the Free Software Foundation; either version
+.\" 2 of the License, or (at your option) any later version.
+.\"
+.TH KEYCTL_DESCRIBE 3 "4 May 2006" Linux "Linux Key Management Calls"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+keyctl_describe \- Describe a key
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SYNOPSIS
+.nf
+.B #include <keyutils.h>
+.sp
+.BI "long keyctl_describe(key_serial_t " key ", char *" buffer ,
+.BI "size_t" buflen ");"
+.sp
+.BI "long keyctl_describe_alloc(key_serial_t " key ", char **" _buffer ");"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+.BR keyctl_describe ()
+describes the attributes of a key as a NUL-terminated string.
+.P
+The caller must have
+.B view
+permission on a key to be able to get a description of it.
+.P
+.I buffer
+and
+.I buflen
+specify the buffer into which the key description will be placed.  If the
+buffer is too small, the full size of the description will be returned, and no
+copy will take place.
+.P
+.BR keyctl_describe_alloc ()
+is similar to
+.BR keyctl_describe ()
+except that it allocates a buffer big enough to hold the description and
+places the description in it.  If successful, A pointer to the buffer is
+placed in
+.IR *_buffer .
+The caller must free the buffer.
+.P
+The description will be a string of format:
+.IP
+.B "\*(lq%s;%d;%d;%08x;%s\*(rq"
+.P
+where the arguments are: key type name, key UID, key GID, key permissions mask
+and key description.
+.P
+.B NOTE!
+The key description will not contain any semicolons, so that should be
+separated out by working backwards from the end of the string.  This permits
+extra information to be inserted before it by later versions of the kernel
+simply by inserting more semicolon-terminated substrings.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+On success
+.BR keyctl_describe ()
+returns the amount of data placed into the buffer.  If the buffer was too
+small, then the size of buffer required will be returned, but no data will be
+transferred.  On error, the value
+.B -1
+will be returned and errno will have been set to an appropriate error.
+.P
+On success
+.BR keyctl_describe_alloc ()
+returns the amount of data in the buffer, less the NUL terminator.  On error, the value
+.B -1
+will be returned and errno will have been set to an appropriate error.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH ERRORS
+.TP
+.B ENOKEY
+The key specified is invalid.
+.TP
+.B EKEYEXPIRED
+The key specified has expired.
+.TP
+.B EKEYREVOKED
+The key specified had been revoked.
+.TP
+.B EACCES
+The key exists, but is not
+.B viewable
+by the calling process.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH LINKING
+This is a library function that can be found in
+.IR libkeyutils .
+When linking,
+.B -lkeyutils
+should be specified to the linker.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SEE ALSO
+.BR keyctl (1),
+.br
+.BR add_key (2),
+.br
+.BR keyctl (2),
+.br
+.BR request_key (2),
+.br
+.BR keyctl (3),
+.br
+.BR request-key (8)
diff --git a/keyctl_get_keyring_ID.3 b/keyctl_get_keyring_ID.3
new file mode 100644 (file)
index 0000000..be9660d
--- /dev/null
@@ -0,0 +1,96 @@
+.\"
+.\" Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+.\" Written by David Howells (dhowells@redhat.com)
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License
+.\" as published by the Free Software Foundation; either version
+.\" 2 of the License, or (at your option) any later version.
+.\"
+.TH KEYCTL_GET_KEYRING_ID 3 "4 May 2006" Linux "Linux Key Management Calls"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+keyctl_get_keyring_ID \- Get the ID of a special keyring
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SYNOPSIS
+.nf
+.B #include <keyutils.h>
+.sp
+.BI "key_serial_t keyctl_get_keyring_ID(key_serial_t " key ","
+.BI " int " create ");"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+.BR keyctl_get_keyring_ID ()
+maps a special
+.I key
+or keyring ID to the serial number of the key actually representing that
+feature.  The serial number will be returned if that key exists.
+.P
+If the key or keyring does not yet exist, then if
+.I create
+is non-zero, the key or keyring will be created if it is appropriate to do so.
+.P
+The following special key IDs may be specified as
+.IR key :
+.TP
+.B KEY_SPEC_THREAD_KEYRING
+This specifies the caller's thread-specific keyring.
+.TP
+.B KEY_SPEC_PROCESS_KEYRING
+This specifies the caller's process-specific keyring.
+.TP
+.B KEY_SPEC_SESSION_KEYRING
+This specifies the caller's session-specific keyring.
+.TP
+.B KEY_SPEC_USER_KEYRING
+This specifies the caller's UID-specific keyring.
+.TP
+.B KEY_SPEC_USER_SESSION_KEYRING
+This specifies the caller's UID-session keyring.
+.TP
+.B KEY_SPEC_REQKEY_AUTH_KEY
+This specifies the authorisation key created by
+.BR request_key ()
+and passed to the process it spawns to generate a key.
+.P
+If a valid keyring ID is passed in, then this will simply be returned if the
+key exists; an error will be issued if it doesn't exist.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+On success
+.BR keyctl_get_keyring_ID ()
+returns the serial number of the key it found.  On error, the value
+.B -1
+will be returned and errno will have been set to an appropriate error.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH ERRORS
+.TP
+.B ENOKEY
+No matching key was found.
+.TP
+.B ENOMEM
+Insufficient memory to create a key.
+.TP
+.B EDQUOT
+The key quota for this user would be exceeded by creating this key or linking
+it to the keyring.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH LINKING
+This is a library function that can be found in
+.IR libkeyutils .
+When linking,
+.B -lkeyutils
+should be specified to the linker.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SEE ALSO
+.BR keyctl (1),
+.br
+.BR add_key (2),
+.br
+.BR keyctl (2),
+.br
+.BR request_key (2),
+.br
+.BR keyctl (3),
+.br
+.BR request-key (8)
diff --git a/keyctl_get_security.3 b/keyctl_get_security.3
new file mode 100644 (file)
index 0000000..f9a3c84
--- /dev/null
@@ -0,0 +1,100 @@
+.\"
+.\" Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+.\" Written by David Howells (dhowells@redhat.com)
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License
+.\" as published by the Free Software Foundation; either version
+.\" 2 of the License, or (at your option) any later version.
+.\"
+.TH KEYCTL_GET_SECURITY 3 "26 Feb 2010" Linux "Linux Key Management Calls"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+keyctl_get_security \- Retrieve a key's security context
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SYNOPSIS
+.nf
+.B #include <keyutils.h>
+.sp
+.BI "long keyctl_get_security(key_serial_t " key ", char *" buffer ,
+.BI "size_t " buflen ");"
+.sp
+.BI "long keyctl_get_security_alloc(key_serial_t " key ", char **" _buffer ");"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+.BR keyctl_get_security ()
+retrieves the security context of a key as a NUL-terminated string.  This will
+be rendered in a form appropriate to the LSM in force - for instance, with
+SELinux, it may look like
+.IP
+.B "unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023"
+.P
+The caller must have
+.B view
+permission on a key to be able to get its security context.
+.P
+.I buffer
+and
+.I buflen
+specify the buffer into which the string will be placed.  If the buffer is too
+small, the full size of the string will be returned, and no copy will take
+place.
+.P
+.BR keyctl_get_security_alloc ()
+is similar to
+.BR keyctl_get_security ()
+except that it allocates a buffer big enough to hold the string and copies the
+string into it.  If successful, A pointer to the buffer is placed in
+.IR *_buffer .
+The caller must free the buffer.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+On success
+.BR keyctl_get_security ()
+returns the amount of data placed into the buffer.  If the buffer was too
+small, then the size of buffer required will be returned, but no data will be
+transferred.  On error, the value
+.B -1
+will be returned and errno will have been set to an appropriate error.
+.P
+On success
+.BR keyctl_get_security_alloc ()
+returns the amount of data in the buffer, less the NUL terminator.  On error, the value
+.B -1
+will be returned and errno will have been set to an appropriate error.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH ERRORS
+.TP
+.B ENOKEY
+The key specified is invalid.
+.TP
+.B EKEYEXPIRED
+The key specified has expired.
+.TP
+.B EKEYREVOKED
+The key specified had been revoked.
+.TP
+.B EACCES
+The key exists, but is not
+.B viewable
+by the calling process.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH LINKING
+This is a library function that can be found in
+.IR libkeyutils .
+When linking,
+.B -lkeyutils
+should be specified to the linker.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SEE ALSO
+.BR keyctl (1),
+.br
+.BR add_key (2),
+.br
+.BR keyctl (2),
+.br
+.BR request_key (2),
+.br
+.BR keyctl (3),
+.br
+.BR request-key (8)
diff --git a/keyctl_instantiate.3 b/keyctl_instantiate.3
new file mode 100644 (file)
index 0000000..7da0b8c
--- /dev/null
@@ -0,0 +1,192 @@
+.\"
+.\" Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+.\" Written by David Howells (dhowells@redhat.com)
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License
+.\" as published by the Free Software Foundation; either version
+.\" 2 of the License, or (at your option) any later version.
+.\"
+.TH KEYCTL_INSTANTIATE 3 "4 May 2006" Linux "Linux Key Management Calls"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+keyctl_assume_authority \- Assume the authority to instantiate a key
+.br
+keyctl_instantiate \- Instantiate a key from flat data
+.br
+keyctl_instantiate_iov \- Instantiate a key from segmented data
+.br
+keyctl_reject \- Negatively instantiate a key specifying search error
+.br
+keyctl_negate \- Negatively instantiate a key
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SYNOPSIS
+.nf
+.B #include <keyutils.h>
+.sp
+.BI "long keyctl_assume_authority(key_serial_t " key ");"
+.sp
+.BI "long keyctl_instantiate(key_serial_t " key ", const void *" payload ,
+.BI "size_t " plen ", key_serial_t " keyring ");"
+.sp
+.BI "long keyctl_instantiate_iov(key_serial_t " key ,
+.BI "const struct iovec *" payload_iov ", unsigned " ioc ,
+.BI "key_serial_t " keyring ");"
+.sp
+.BI "long keyctl_negate(key_serial_t " key ", unsigned " timeout ,
+.BI "key_serial_t " keyring ");"
+.sp
+.BI "long keyctl_reject(key_serial_t " key ", unsigned " timeout ,
+.BI "unsigned " error ", key_serial_t " keyring ");"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+.BR keyctl_assume_authority ()
+assumes the authority for the calling thread to deal with and instantiate the
+specified uninstantiated
+.IR key .
+.P
+The calling thread must have the appopriate authorisation key resident in one
+of its keyrings for this to succeed, and that authority must not have been
+revoked.
+.P
+The authorising key is allocated by request_key() when it needs to invoke
+userspace to generate a key for the requesting process.  This is then attached
+to one of the keyrings of the userspace process to which the task of
+instantiating the key is given:
+.IP
+requester -> request_key() -> instantiator
+.P
+Calling this function modifies the way
+.BR request_key ()
+works when called thereafter by the calling (instantiator) thread; once the
+authority is assumed, the keyrings of the initial process are added to the
+search path, using the initial process's UID, GID, groups and security
+context.
+.P
+If a thread has multiple instantiations to deal with, it may call this
+function to change the authorisation key currently in effect.  Supplying a
+.B zero
+.I key
+de-assumes the currently assumed authority.
+.P
+.B NOTE!
+This is a per-thread setting and not a per-process setting so that a
+multithreaded process can be used to instantiate several keys at once.
+.P
+.BR keyctl_instantiate ()
+instantiates the payload of an uninstantiated key from the data specified.
+.I payload
+and
+.I plen
+specify the data for the new payload.
+.I payload
+may be NULL and
+.I plen
+may be zero if the key type permits that.  The key type may reject the data if
+it's in the wrong format or in some other way invalid.
+.P
+.BR keyctl_instantiate_iov ()
+is similar, but the data is passed in an array of iovec structs instead of in
+a flat buffer.
+.I payload_iov
+points to the base of the array and
+.I ioc
+indicates how many elements there are.
+.I payload_iov
+may be NULL or
+.I ioc
+may be zero to indicate that no data is being supplied.
+.P
+.BR keyctl_reject ()
+marks a key as negatively instantiated and sets the expiration timer on it.
+.I timeout
+specifies the lifetime of the key in seconds.
+.I error
+specifies the error to be returned when a search hits the key (this is
+typically
+.IR EKEYREJECTED ", " EKEYREVOKED " or " EKEYEXPIRED ")."
+Note that keyctl_reject() falls back to keyctl_negate() if the kernel does not
+support it.
+.P
+.BR keyctl_negate ()
+as
+.IR keyctl_reject ()
+with an error code of
+.IB ENOKEY .
+.P
+Only a key for which authority has been assumed may be instantiated or
+negatively instantiated, and once instantiated, the authorisation key will be
+revoked and the requesting process will be able to resume.
+.P
+The destination
+.IR keyring ,
+if given, is assumed to belong to the initial requester, and not the
+instantiating process.  Therefore, the special keyring IDs refer to the
+requesting process's keyrings, not the caller's, and the requester's UID,
+etc. will be used to access them.
+.P
+The destination keyring can be
+.B zero
+if no extra link is desired.
+.P
+The requester, not the caller, must have
+.B write
+permission on the destination for a link to be made there.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+On success
+.BR keyctl_instantiate ()
+returns
+.BR 0 .
+On error, the value
+.B -1
+will be returned and errno will have been set to an appropriate error.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH ERRORS
+.TP
+.B ENOKEY
+The key or keyring specified is invalid.
+.TP
+.B EKEYEXPIRED
+The keyring specified has expired.
+.TP
+.B EKEYREVOKED
+The key or keyring specified had been revoked, or the authorisation has been
+revoked.
+.TP
+.B EINVAL
+The payload data was invalid.
+.TP
+.B ENOMEM
+Insufficient memory to store the new payload or to expand the destination
+keyring.
+.TP
+.B EDQUOT
+The key quota for the key's user would be exceeded by increasing the size of
+the key to accommodate the new payload or the key quota for the keyring's user
+would be exceeded by expanding the destination keyring.
+.TP
+.B EACCES
+The key exists, but is not
+.B writable
+by the requester.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH LINKING
+This is a library function that can be found in
+.IR libkeyutils .
+When linking,
+.B -lkeyutils
+should be specified to the linker.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SEE ALSO
+.BR keyctl (1),
+.br
+.BR add_key (2),
+.br
+.BR keyctl (2),
+.br
+.BR request_key (2),
+.br
+.BR keyctl (3),
+.br
+.BR request-key (8)
diff --git a/keyctl_join_session_keyring.3 b/keyctl_join_session_keyring.3
new file mode 100644 (file)
index 0000000..ffbb805
--- /dev/null
@@ -0,0 +1,82 @@
+.\"
+.\" Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+.\" Written by David Howells (dhowells@redhat.com)
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License
+.\" as published by the Free Software Foundation; either version
+.\" 2 of the License, or (at your option) any later version.
+.\"
+.TH KEYCTL_JOIN_SESSION_KEYRING 3 "4 May 2006" Linux "Linux Key Management Calls"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+keyctl_join_session_keyring \- Join a different session keyring
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SYNOPSIS
+.nf
+.B #include <keyutils.h>
+.sp
+.BI "key_serial_t keyctl_join_session_keyring(const char *" name ");"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+.BR keyctl_join_session_keyring ()
+changes the session keyring to which a process is subscribed.
+.P
+If
+.I name
+is
+.B NULL
+then a new anonymous keyring will be created, and the process will be
+subscribed to that.
+.P
+If
+.I name
+points to a string, then if a keyring of that name is available, the process
+will attempt to subscribe to that keyring, giving an error if that is not
+permitted; otherwise a new keyring of that name is created and attached as the
+session keyring.
+.P
+To attach to an extant named keyring, the keyring must have
+.B search
+permission available to the calling process.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+On success
+.BR keyctl_join_session_keyring ()
+returns the serial number of the key it found or created.  On error, the value
+.B -1
+will be returned and errno will have been set to an appropriate error.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH ERRORS
+.TP
+.B ENOMEM
+Insufficient memory to create a key.
+.TP
+.B EDQUOT
+The key quota for this user would be exceeded by creating this key or linking
+it to the keyring.
+.TP
+.B EACCES
+The named keyring exists, but is not
+.B searchable
+by the calling process.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH LINKING
+This is a library function that can be found in
+.IR libkeyutils .
+When linking,
+.B -lkeyutils
+should be specified to the linker.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SEE ALSO
+.BR keyctl (1),
+.br
+.BR add_key (2),
+.br
+.BR keyctl (2),
+.br
+.BR request_key (2),
+.br
+.BR keyctl (3),
+.br
+.BR request-key (8)
diff --git a/keyctl_link.3 b/keyctl_link.3
new file mode 100644 (file)
index 0000000..f62549e
--- /dev/null
@@ -0,0 +1,108 @@
+.\"
+.\" Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+.\" Written by David Howells (dhowells@redhat.com)
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License
+.\" as published by the Free Software Foundation; either version
+.\" 2 of the License, or (at your option) any later version.
+.\"
+.TH KEYCTL_LINK 3 "4 May 2006" Linux "Linux Key Management Calls"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+keyctl_link \- Link a key to a keyring
+keyctl_unlink \- Unlink a key from a keyring
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SYNOPSIS
+.nf
+.B #include <keyutils.h>
+.sp
+.BI "long keyctl_link(key_serial_t " key ", key_serial_t " keyring ");"
+.sp
+.BI "long keyctl_unlink(key_serial_t " key ", key_serial_t " keyring ");"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+.BR keyctl_link ()
+creates a link from
+.I keyring
+to
+.IR key ,
+displacing any link to another key of the same type and description in that
+keyring if one exists.
+.P
+.BR keyctl_unlink ()
+removes the link from
+.I keyring
+to
+.I key
+if it exists.
+.P
+The caller must have
+.B write
+permission on a keyring to be able create or remove links in it.
+.P
+The caller must have
+.B link
+permission on a key to be able to create a link to it.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+On success
+.BR keyctl_link ()
+and
+.BR keyctl_unlink ()
+return
+.BR 0 .
+On error, the value
+.B -1
+will be returned and errno will have been set to an appropriate error.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH ERRORS
+.TP
+.B ENOKEY
+The key or the keyring specified are invalid.
+.TP
+.B EKEYEXPIRED
+The key or the keyring specified have expired.
+.TP
+.B EKEYREVOKED
+The key or the keyring specified have been revoked.
+.TP
+.B EACCES
+The keyring exists, but is not
+.B writable
+by the calling process.
+.P
+For
+.BR keyctl_link ()
+only:
+.TP
+.B ENOMEM
+Insufficient memory to expand the keyring
+.TP
+.B EDQUOT
+Expanding the keyring would exceed the keyring owner's quota.
+.TP
+.B EACCES
+The key exists, but is not
+.B linkable
+by the calling process.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH LINKING
+This is a library function that can be found in
+.IR libkeyutils .
+When linking,
+.B -lkeyutils
+should be specified to the linker.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SEE ALSO
+.BR keyctl (1),
+.br
+.BR add_key (2),
+.br
+.BR keyctl (2),
+.br
+.BR request_key (2),
+.br
+.BR keyctl (3),
+.br
+.BR request-key (8)
diff --git a/keyctl_read.3 b/keyctl_read.3
new file mode 100644 (file)
index 0000000..01905e5
--- /dev/null
@@ -0,0 +1,109 @@
+.\"
+.\" Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+.\" Written by David Howells (dhowells@redhat.com)
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License
+.\" as published by the Free Software Foundation; either version
+.\" 2 of the License, or (at your option) any later version.
+.\"
+.TH KEYCTL_READ 3 "4 May 2006" Linux "Linux Key Management Calls"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+keyctl_read \- Read a key
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SYNOPSIS
+.nf
+.B #include <keyutils.h>
+.sp
+.BI "long keyctl_read(key_serial_t " key ", char *" buffer ,
+.BI "size_t" buflen ");"
+.sp
+.BI "long keyctl_read_alloc(key_serial_t " key ", void **" _buffer ");"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+.BR keyctl_read ()
+reads the payload of a key if the key type supports it.
+.P
+The caller must have
+.B read
+permission on a key to be able to read it.
+.P
+.I buffer
+and
+.I buflen
+specify the buffer into which the payload data will be placed.  If the buffer
+is too small, the full size of the payload will be returned, and no copy will
+take place.
+.P
+.BR keyctl_read_alloc ()
+is similar to
+.BR keyctl_read ()
+except that it allocates a buffer big enough to hold the payload data and
+places the data in it.  If successful, A pointer to the buffer is placed in
+.IR *_buffer .
+The caller must free the buffer.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH READING KEYRINGS
+This call can be used to list the contents of a keyring.  The data is
+presented to the user as an array of
+.B key_serial_t
+values, each of which corresponds to a key to which the keyring holds a link.
+.P
+The size of the keyring will be sizeof(key_serial_t) multiplied by the number
+of keys.  The size of key_serial_t is invariant across different word sizes,
+though the byte-ordering is as appropriate for the kernel.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+On success
+.BR keyctl_read ()
+returns the amount of data placed into the buffer.  If the buffer was too
+small, then the size of buffer required will be returned, but no data will be
+transferred.  On error, the value
+.B -1
+will be returned and errno will have been set to an appropriate error.
+.P
+On success
+.BR keyctl_read_alloc ()
+returns the amount of data in the buffer.  On error, the value
+.B -1
+will be returned and errno will have been set to an appropriate error.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH ERRORS
+.TP
+.B ENOKEY
+The key specified is invalid.
+.TP
+.B EKEYEXPIRED
+The key specified has expired.
+.TP
+.B EKEYREVOKED
+The key specified had been revoked.
+.TP
+.B EACCES
+The key exists, but is not
+.B readable
+by the calling process.
+.TP
+.B EOPNOTSUPP
+The key type does not support reading of the payload data.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH LINKING
+This is a library function that can be found in
+.IR libkeyutils .
+When linking,
+.B -lkeyutils
+should be specified to the linker.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SEE ALSO
+.BR keyctl (1),
+.br
+.BR add_key (2),
+.br
+.BR keyctl (2),
+.br
+.BR request_key (2),
+.br
+.BR keyctl (3),
+.br
+.BR request-key (8)
diff --git a/keyctl_revoke.3 b/keyctl_revoke.3
new file mode 100644 (file)
index 0000000..212c776
--- /dev/null
@@ -0,0 +1,73 @@
+.\"
+.\" Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+.\" Written by David Howells (dhowells@redhat.com)
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License
+.\" as published by the Free Software Foundation; either version
+.\" 2 of the License, or (at your option) any later version.
+.\"
+.TH KEYCTL_REVOKE 3 "4 May 2006" Linux "Linux Key Management Calls"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+keyctl_revoke \- Revoke a key
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SYNOPSIS
+.nf
+.B #include <keyutils.h>
+.sp
+.BI "long keyctl_revoke(key_serial_t " key ");"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+.BR keyctl_revoke ()
+marks a key as being revoked.
+.P
+After this operation has been performed on a key, attempts to access it will
+meet with error
+.BR EKEYREVOKED .
+.P
+The caller must have
+.B write
+permission on a key to be able revoke it.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+On success
+.BR keyctl_revoke ()
+returns
+.BR 0 .
+On error, the value
+.B -1
+will be returned and errno will have been set to an appropriate error.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH ERRORS
+.TP
+.B ENOKEY
+The specified key does not exist.
+.TP
+.B EKEYREVOKED
+The key has already been revoked.
+.TP
+.B EACCES
+The named key exists, but is not
+.B writable
+by the calling process.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH LINKING
+This is a library function that can be found in
+.IR libkeyutils .
+When linking,
+.B -lkeyutils
+should be specified to the linker.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SEE ALSO
+.BR keyctl (1),
+.br
+.BR add_key (2),
+.br
+.BR keyctl (2),
+.br
+.BR request_key (2),
+.br
+.BR keyctl (3),
+.br
+.BR request-key (8)
diff --git a/keyctl_search.3 b/keyctl_search.3
new file mode 100644 (file)
index 0000000..368584c
--- /dev/null
@@ -0,0 +1,138 @@
+.\"
+.\" Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+.\" Written by David Howells (dhowells@redhat.com)
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License
+.\" as published by the Free Software Foundation; either version
+.\" 2 of the License, or (at your option) any later version.
+.\"
+.TH KEYCTL_SEARCH 3 "4 May 2006" Linux "Linux Key Management Calls"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+keyctl_search \- Search a keyring for a key
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SYNOPSIS
+.nf
+.B #include <keyutils.h>
+.sp
+.BI "long keyctl_search(key_serial_t " keyring ", const char *" type ,
+.BI "const char *" description ", key_serial_t " destination ");"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+.BR keyctl_search ()
+recursively searches the
+.I keyring
+for a key of the specified
+.I type
+and
+.IR description .
+.P
+If found, the key will be attached to the
+.I destination
+keyring (if given), and its serial number will be returned.
+.P
+The source keyring must grant
+.B search
+permission to the caller, and for a key to be found, it must also grant
+.B search
+permission to the caller.  Child keyrings will be only be recursively searched
+if they grant
+.B search
+permission to the caller as well.
+.P
+If the destination keyring is
+.BR zero ,
+no attempt will be made to forge a link to the key, and just the serial number
+will be returned.
+.P
+If the destination keyring is given, then the link may only be formed if the
+found key grants the caller
+.B link
+permission and the destination keyring grants the caller
+.B write
+permission.
+.P
+If the search is successful, and if the destination keyring already contains a
+link to a key that matches the specified
+.IR type " and " description ,
+then that link will be replaced by a link to the found key.
+.P
+The source keyring and destination keyring serial numbers may be those of
+valid keyrings to which the caller has appropriate permission, or they may be
+special keyring IDs:
+.TP
+.B KEY_SPEC_THREAD_KEYRING
+This specifies the caller's thread-specific keyring.
+.TP
+.B KEY_SPEC_PROCESS_KEYRING
+This specifies the caller's process-specific keyring.
+.TP
+.B KEY_SPEC_SESSION_KEYRING
+This specifies the caller's session-specific keyring.
+.TP
+.B KEY_SPEC_USER_KEYRING
+This specifies the caller's UID-specific keyring.
+.TP
+.B KEY_SPEC_USER_SESSION_KEYRING
+This specifies the caller's UID-session keyring.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+On success
+.BR keyctl_search ()
+returns the serial number of the key it found.  On error, the value
+.B -1
+will be returned and errno will have been set to an appropriate error.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH ERRORS
+.TP
+.B ENOKEY
+One of the keyrings doesn't exist, no key was found by the search, or the only
+key found by the search was a negative key.
+.TP
+.B ENOTDIR
+One of the keyrings is a valid key that isn't a keyring.
+.TP
+.B EKEYEXPIRED
+One of the keyrings has expired, or the only key found was expired.
+.TP
+.B EKEYREVOKED
+One of the keyrings has been revoked, or the only key found was revoked.
+.TP
+.B ENOMEM
+Insufficient memory to expand the destination keyring.
+.TP
+.B EDQUOT
+The key quota for this user would be exceeded by creating a link to the found
+key in the destination keyring.
+.TP
+.B EACCES
+The source keyring didn't grant
+.B search
+permission, the destination keyring didn't grant
+.B write
+permission or the found key didn't grant
+.B link
+permission to the caller.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH LINKING
+Although this is a Linux system call, it is not present in
+.I libc
+but can be found rather in
+.IR libkeyutils .
+When linking,
+.B -lkeyutils
+should be specified to the linker.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SEE ALSO
+.BR keyctl (1),
+.br
+.BR add_key (2),
+.br
+.BR keyctl (2),
+.br
+.BR request_key (2),
+.br
+.BR keyctl (3),
+.br
+.BR request-key (8)
diff --git a/keyctl_session_to_parent.3 b/keyctl_session_to_parent.3
new file mode 100644 (file)
index 0000000..a0da527
--- /dev/null
@@ -0,0 +1,75 @@
+.\"
+.\" Copyright (C) 2010 Red Hat, Inc. All Rights Reserved.
+.\" Written by David Howells (dhowells@redhat.com)
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License
+.\" as published by the Free Software Foundation; either version
+.\" 2 of the License, or (at your option) any later version.
+.\"
+.TH KEYCTL_SESSION_TO_PARENT 3 "26 Jun 2010" Linux "Linux Key Management Calls"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+keyctl_session_to_parent \- Set the parent process's session keyring
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SYNOPSIS
+.nf
+.B #include <keyutils.h>
+.sp
+.BI "long keyctl_session_to_parent();"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+.BR keyctl_session_to_parent ()
+changes the session keyring to which the calling process's parent subscribes
+to be the that of the calling process.
+.P
+The keyring must have
+.B link
+permission available to the calling process, the parent process must have the
+same UIDs/GIDs as the calling process, and the LSM must not reject the
+replacement.  Furthermore, this may not be used to affect init or a kernel
+thread.
+.P
+Note that the replacement will not take immediate effect upon the parent
+process, but will rather be deferred to the next time it returns to userspace
+from kernel space.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+On success
+.BR keyctl_session_to_parent ()
+returns 0.  On error, the value
+.B -1
+will be returned and errno will have been set to an appropriate error.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH ERRORS
+.TP
+.B ENOMEM
+Insufficient memory to create a key.
+.TP
+.B EPERM
+The credentials of the parent don't match those of the caller.
+.TP
+.B EACCES
+The named keyring exists, but is not
+.B linkable
+by the calling process.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH LINKING
+This is a library function that can be found in
+.IR libkeyutils .
+When linking,
+.B -lkeyutils
+should be specified to the linker.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SEE ALSO
+.BR keyctl (1),
+.br
+.BR add_key (2),
+.br
+.BR keyctl (2),
+.br
+.BR request_key (2),
+.br
+.BR keyctl (3),
+.br
+.BR request-key (8)
diff --git a/keyctl_set_reqkey_keyring.3 b/keyctl_set_reqkey_keyring.3
new file mode 100644 (file)
index 0000000..fc5946e
--- /dev/null
@@ -0,0 +1,98 @@
+.\"
+.\" Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+.\" Written by David Howells (dhowells@redhat.com)
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License
+.\" as published by the Free Software Foundation; either version
+.\" 2 of the License, or (at your option) any later version.
+.\"
+.TH KEYCTL_SET_REQKEY_KEYRING 3 "4 May 2006" Linux "Linux Key Management Calls"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+keyctl_set_reqkey_keyring \- Set the implicit destination keyring
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SYNOPSIS
+.nf
+.B #include <keyutils.h>
+.sp
+.BI "long keyctl_set_reqkey_keyring(int " reqkey_defl ");"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+.BR keyctl_set_reqkey_keyring ()
+sets the default destination for implicit key requests for the current thread
+and returns the old setting.
+.P
+After this operation has been issued, keys acquired by implicit key requests,
+such as might be performed by open() on an AFS or NFS filesystem, will be
+linked by default to the specified keyring by this function.
+.P
+The valid values of
+.I reqkey_defl
+are:
+.TP
+.B KEY_REQKEY_DEFL_NO_CHANGE
+This makes no change to the current setting.
+.TP
+.B KEY_REQKEY_DEFL_THREAD_KEYRING
+This makes the thread-specific keyring the default destination.
+.TP
+.B KEY_REQKEY_DEFL_PROCESS_KEYRING
+This makes the process-specific keyring the default destination.
+.TP
+.B KEY_REQKEY_DEFL_SESSION_KEYRING
+This makes the session keyring the default destination.
+.TP
+.B KEY_REQKEY_DEFL_USER_KEYRING
+This makes the UID-specific keyring the default destination.
+.TP
+.B KEY_REQKEY_DEFL_USER_SESSION_KEYRING
+This makes the UID-specific session keyring the default destination.
+.TP
+.B KEY_REQKEY_DEFL_DEFAULT
+This selects the default behaviour which is to use the thread-specific keyring
+if there is one, otherwise the process-specific keyring if there is one,
+otherwise the session keyring if there is one, otherwise the UID-specific
+session keyring.
+.P
+This setting is inherited across
+.BR fork ()
+and
+.BR exec ().
+
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+On success
+.BR keyctl_set_reqkey_keyring ()
+returns
+.BR 0 .
+On error, the value
+.B -1
+will be returned and errno will have been set to an appropriate error.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH ERRORS
+.TP
+.B EINVAL
+The value of
+.I reqkey_defl
+is invalid.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH LINKING
+This is a library function that can be found in
+.IR libkeyutils .
+When linking,
+.B -lkeyutils
+should be specified to the linker.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SEE ALSO
+.BR keyctl (1),
+.br
+.BR add_key (2),
+.br
+.BR keyctl (2),
+.br
+.BR request_key (2),
+.br
+.BR keyctl (3),
+.br
+.BR request-key (8)
diff --git a/keyctl_set_timeout.3 b/keyctl_set_timeout.3
new file mode 100644 (file)
index 0000000..6d6e774
--- /dev/null
@@ -0,0 +1,81 @@
+.\"
+.\" Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+.\" Written by David Howells (dhowells@redhat.com)
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License
+.\" as published by the Free Software Foundation; either version
+.\" 2 of the License, or (at your option) any later version.
+.\"
+.TH KEYCTL_SET_TIMEOUT 3 "4 May 2006" Linux "Linux Key Management Calls"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+keyctl_set_timeout \- Set the expiration timer on a key
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SYNOPSIS
+.nf
+.B #include <keyutils.h>
+.sp
+.BI "long keyctl_set_timeout(key_serial_t " key ", unsigned " timeout ");"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+.BR keyctl_set_timeout ()
+sets the expiration timer on a key to
+.I timeout
+seconds into the future.  Setting
+.I timeout
+to
+.B zero
+cancels the expiration, assuming the key hasn't already expired.
+.P
+When the key expires, further attempts to access it will be met with error
+.BR EKEYEXPIRED .
+.P
+The caller must have
+.B setattr
+permission on a key to be able change its permissions mask.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+On success
+.BR keyctl_set_timeout ()
+returns
+.B 0 .
+On error, the value
+.B -1
+will be returned and errno will have been set to an appropriate error.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH ERRORS
+.TP
+.B ENOKEY
+The specified key does not exist.
+.TP
+.B EKEYEXPIRED
+The specified key has already expired.
+.TP
+.B EKEYREVOKED
+The specified key has been revoked.
+.TP
+.B EACCES
+The named key exists, but does not grant
+.B setattr
+permission to the calling process.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH LINKING
+This is a library function that can be found in
+.IR libkeyutils .
+When linking,
+.B -lkeyutils
+should be specified to the linker.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SEE ALSO
+.BR keyctl (1),
+.br
+.BR add_key (2),
+.br
+.BR keyctl (2),
+.br
+.BR request_key (2),
+.br
+.BR keyctl (3),
+.br
+.BR request-key (8)
diff --git a/keyctl_setperm.3 b/keyctl_setperm.3
new file mode 100644 (file)
index 0000000..9bf90f5
--- /dev/null
@@ -0,0 +1,130 @@
+.\"
+.\" Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+.\" Written by David Howells (dhowells@redhat.com)
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License
+.\" as published by the Free Software Foundation; either version
+.\" 2 of the License, or (at your option) any later version.
+.\"
+.TH KEYCTL_SETPERM 3 "4 May 2006" Linux "Linux Key Management Calls"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+keyctl_setperm \- Change the permissions mask on a key
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SYNOPSIS
+.nf
+.B #include <keyutils.h>
+.sp
+.BI "long keyctl_setperm(key_serial_t " key ", key_perm_t " perm ");"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+.BR keyctl_setperm ()
+changes the permissions mask on a key.
+.P
+A process that does not have the
+.B SysAdmin
+capability may not change the permissions mask on a key that doesn't have the
+same UID as the caller.
+.P
+The caller must have
+.B setattr
+permission on a key to be able change its permissions mask.
+.P
+The permissions mask is a bitwise-OR of the following flags:
+.TP
+.B KEY_xxx_VIEW
+Grant permission to view the attributes of a key.
+.TP
+.B KEY_xxx_READ
+Grant permission to read the payload of a key or to list a keyring.
+.TP
+.B KEY_xxx_WRITE
+Grant permission to modify the payload of a key or to add or remove links
+to/from a keyring.
+.TP
+.B KEY_xxx_SEARCH
+Grant permission to find a key or to search a keyring.
+.TP
+.B KEY_xxx_LINK
+Grant permission to make links to a key.
+.TP
+.B KEY_xxx_SETATTR
+Grant permission to change the ownership and permissions attributes of a key.
+.TP
+.B KEY_xxx_ALL
+Grant all the above.
+.P
+The
+.RB ' xxx '
+in the above should be replaced by one of:
+.TP
+.B POS
+Grant the permission to a process that possesses the key (has it attached
+searchably to one of the process's keyrings).
+.TP
+.B USR
+Grant the permission to a process with the same UID as the key.
+.TP
+.B GRP
+Grant the permission to a process with the same GID as the key, or with a
+match for the key's GID amongst that process's Groups list.
+.TP
+.B OTH
+Grant the permission to any other process.
+.P
+Examples include:
+.BR KEY_POS_VIEW ", " KEY_USR_READ ", " KEY_GRP_SEARCH " and " KEY_OTH_ALL .
+.P
+User, group and other grants are exclusive: if a process qualifies in
+the 'user' category, it will not qualify in the 'groups' category; and if a
+process qualifies in either 'user' or 'groups' then it will not qualify in
+the 'other' category.
+.P
+Possessor grants are cumulative with the grants from the 'user', 'groups'
+and 'other' categories.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+On success
+.BR keyctl_setperm ()
+returns
+.B 0 .
+On error, the value
+.B -1
+will be returned and errno will have been set to an appropriate error.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH ERRORS
+.TP
+.B ENOKEY
+The specified key does not exist.
+.TP
+.B EKEYEXPIRED
+The specified key has expired.
+.TP
+.B EKEYREVOKED
+The specified key has been revoked.
+.TP
+.B EACCES
+The named key exists, but does not grant
+.B setattr
+permission to the calling process.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH LINKING
+This is a library function that can be found in
+.IR libkeyutils .
+When linking,
+.B -lkeyutils
+should be specified to the linker.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SEE ALSO
+.BR keyctl (1),
+.br
+.BR add_key (2),
+.br
+.BR keyctl (2),
+.br
+.BR request_key (2),
+.br
+.BR keyctl (3),
+.br
+.BR request-key (8)
diff --git a/keyctl_update.3 b/keyctl_update.3
new file mode 100644 (file)
index 0000000..dd95fe9
--- /dev/null
@@ -0,0 +1,96 @@
+.\"
+.\" Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+.\" Written by David Howells (dhowells@redhat.com)
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License
+.\" as published by the Free Software Foundation; either version
+.\" 2 of the License, or (at your option) any later version.
+.\"
+.TH KEYCTL_UPDATE 3 "4 May 2006" Linux "Linux Key Management Calls"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+keyctl_update \- Update a key
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SYNOPSIS
+.nf
+.B #include <keyutils.h>
+.sp
+.BI "long keyctl_update(key_serial_t " key ", const void *" payload ,
+.BI "size_t " plen ");"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+.BR keyctl_update ()
+updates the payload of a key if the key type permits it.
+.P
+The caller must have
+.B write
+permission on a key to be able update it.
+.P
+.I payload
+and
+.I plen
+specify the data for the new payload.
+.I payload
+may be NULL and
+.I plen
+may be zero if the key type permits that.  The key type may reject the data if
+it's in the wrong format or in some other way invalid.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+On success
+.BR keyctl_update ()
+returns
+.BR 0 .
+On error, the value
+.B -1
+will be returned and errno will have been set to an appropriate error.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH ERRORS
+.TP
+.B ENOKEY
+The key specified is invalid.
+.TP
+.B EKEYEXPIRED
+The key specified has expired.
+.TP
+.B EKEYREVOKED
+The key specified had been revoked.
+.TP
+.B EINVAL
+The payload data was invalid.
+.TP
+.B ENOMEM
+Insufficient memory to store the new payload.
+.TP
+.B EDQUOT
+The key quota for this user would be exceeded by increasing the size of the
+key to accommodate the new payload.
+.TP
+.B EACCES
+The key exists, but is not
+.B writable
+by the calling process.
+.TP
+.B EOPNOTSUPP
+The key type does not support the update operation on its keys.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH LINKING
+This is a library function that can be found in
+.IR libkeyutils .
+When linking,
+.B -lkeyutils
+should be specified to the linker.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SEE ALSO
+.BR keyctl (1),
+.br
+.BR add_key (2),
+.br
+.BR keyctl (2),
+.br
+.BR request_key (2),
+.br
+.BR keyctl (3),
+.br
+.BR request-key (8)
diff --git a/keyutils.c b/keyutils.c
new file mode 100644 (file)
index 0000000..d66b179
--- /dev/null
@@ -0,0 +1,608 @@
+/* keyutils.c: key utility library
+ *
+ * Copyright (C) 2005,2011 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <asm/unistd.h>
+#include "keyutils.h"
+
+#ifdef NO_GLIBC_KEYERR
+static int error_inited;
+static void (*libc_perror)(const char *msg);
+static char *(*libc_strerror_r)(int errnum, char *buf, size_t n);
+//static int (*libc_xpg_strerror_r)(int errnum, char *buf, size_t n);
+#define RTLD_NEXT      ((void *) -1L)
+#endif
+
+#define __weak __attribute__((weak))
+
+key_serial_t __weak add_key(const char *type,
+                           const char *description,
+                           const void *payload,
+                           size_t plen,
+                           key_serial_t ringid)
+{
+       return syscall(__NR_add_key,
+                      type, description, payload, plen, ringid);
+}
+
+key_serial_t __weak request_key(const char *type,
+                               const char *description,
+                               const char * callout_info,
+                               key_serial_t destringid)
+{
+       return syscall(__NR_request_key,
+                      type, description, callout_info, destringid);
+}
+
+static inline long __keyctl(int cmd,
+                           unsigned long arg2,
+                           unsigned long arg3,
+                           unsigned long arg4,
+                           unsigned long arg5)
+{
+       return syscall(__NR_keyctl,
+                      cmd, arg2, arg3, arg4, arg5);
+}
+
+long __weak keyctl(int cmd, ...)
+{
+       va_list va;
+       unsigned long arg2, arg3, arg4, arg5;
+
+       va_start(va, cmd);
+       arg2 = va_arg(va, unsigned long);
+       arg3 = va_arg(va, unsigned long);
+       arg4 = va_arg(va, unsigned long);
+       arg5 = va_arg(va, unsigned long);
+       va_end(va);
+
+       return __keyctl(cmd, arg2, arg3, arg4, arg5);
+}
+
+key_serial_t keyctl_get_keyring_ID(key_serial_t id, int create)
+{
+       return keyctl(KEYCTL_GET_KEYRING_ID, id, create);
+}
+
+key_serial_t keyctl_join_session_keyring(const char *name)
+{
+       return keyctl(KEYCTL_JOIN_SESSION_KEYRING, name);
+}
+
+long keyctl_update(key_serial_t id, const void *payload, size_t plen)
+{
+       return keyctl(KEYCTL_UPDATE, id, payload, plen);
+}
+
+long keyctl_revoke(key_serial_t id)
+{
+       return keyctl(KEYCTL_REVOKE, id);
+}
+
+long keyctl_chown(key_serial_t id, uid_t uid, gid_t gid)
+{
+       return keyctl(KEYCTL_CHOWN, id, uid, gid);
+}
+
+long keyctl_setperm(key_serial_t id, key_perm_t perm)
+{
+       return keyctl(KEYCTL_SETPERM, id, perm);
+}
+
+long keyctl_describe(key_serial_t id, char *buffer, size_t buflen)
+{
+       return keyctl(KEYCTL_DESCRIBE, id, buffer, buflen);
+}
+
+long keyctl_clear(key_serial_t ringid)
+{
+       return keyctl(KEYCTL_CLEAR, ringid);
+}
+
+long keyctl_link(key_serial_t id, key_serial_t ringid)
+{
+       return keyctl(KEYCTL_LINK, id, ringid);
+}
+
+long keyctl_unlink(key_serial_t id, key_serial_t ringid)
+{
+       return keyctl(KEYCTL_UNLINK, id, ringid);
+}
+
+long keyctl_search(key_serial_t ringid,
+                  const char *type,
+                  const char *description,
+                  key_serial_t destringid)
+{
+       return keyctl(KEYCTL_SEARCH, ringid, type, description, destringid);
+}
+
+long keyctl_read(key_serial_t id, char *buffer, size_t buflen)
+{
+       return keyctl(KEYCTL_READ, id, buffer, buflen);
+}
+
+long keyctl_instantiate(key_serial_t id,
+                       const void *payload,
+                       size_t plen,
+                       key_serial_t ringid)
+{
+       return keyctl(KEYCTL_INSTANTIATE, id, payload, plen, ringid);
+}
+
+long keyctl_negate(key_serial_t id, unsigned timeout, key_serial_t ringid)
+{
+       return keyctl(KEYCTL_NEGATE, id, timeout, ringid);
+}
+
+long keyctl_set_reqkey_keyring(int reqkey_defl)
+{
+       return keyctl(KEYCTL_SET_REQKEY_KEYRING, reqkey_defl);
+}
+
+long keyctl_set_timeout(key_serial_t id, unsigned timeout)
+{
+       return keyctl(KEYCTL_SET_TIMEOUT, id, timeout);
+}
+
+long keyctl_assume_authority(key_serial_t id)
+{
+       return keyctl(KEYCTL_ASSUME_AUTHORITY, id);
+}
+
+long keyctl_get_security(key_serial_t id, char *buffer, size_t buflen)
+{
+       return keyctl(KEYCTL_GET_SECURITY, id, buffer, buflen);
+}
+
+long keyctl_session_to_parent(void)
+{
+       return keyctl(KEYCTL_SESSION_TO_PARENT);
+}
+
+long keyctl_reject(key_serial_t id, unsigned timeout, unsigned error,
+                  key_serial_t ringid)
+{
+       long ret = keyctl(KEYCTL_REJECT, id, timeout, error, ringid);
+
+       /* fall back to keyctl_negate() if this op is not supported by this
+        * kernel version */
+       if (ret == -1 && errno == EOPNOTSUPP)
+               return keyctl_negate(id, timeout, ringid);
+       return ret;
+}
+
+long keyctl_instantiate_iov(key_serial_t id,
+                           const struct iovec *payload_iov,
+                           unsigned ioc,
+                           key_serial_t ringid)
+{
+       long ret = keyctl(KEYCTL_INSTANTIATE_IOV, id, payload_iov, ioc, ringid);
+
+       /* fall back to keyctl_instantiate() if this op is not supported by
+        * this kernel version */
+       if (ret == -1 && errno == EOPNOTSUPP) {
+               unsigned loop;
+               size_t bsize = 0, seg;
+               void *buf, *p;
+
+               if (!payload_iov || !ioc)
+                       return keyctl_instantiate(id, NULL, 0, ringid);
+               for (loop = 0; loop < ioc; loop++)
+                       bsize += payload_iov[loop].iov_len;
+               if (bsize == 0)
+                       return keyctl_instantiate(id, NULL, 0, ringid);
+               p = buf = malloc(bsize);
+               if (!buf)
+                       return -1;
+               for (loop = 0; loop < ioc; loop++) {
+                       seg = payload_iov[loop].iov_len;
+                       p = memcpy(p, payload_iov[loop].iov_base, seg) + seg;
+               }
+               ret = keyctl_instantiate(id, buf, bsize, ringid);
+               free(buf);
+       }
+       return ret;
+}
+
+/*****************************************************************************/
+/*
+ * fetch key description into an allocated buffer
+ * - resulting string is NUL terminated
+ * - returns count not including NUL
+ */
+int keyctl_describe_alloc(key_serial_t id, char **_buffer)
+{
+       char *buf;
+       long buflen, ret;
+
+       ret = keyctl_describe(id, NULL, 0);
+       if (ret < 0)
+               return -1;
+
+       buflen = ret;
+       buf = malloc(buflen);
+       if (!buf)
+               return -1;
+
+       for (;;) {
+               ret = keyctl_describe(id, buf, buflen);
+               if (ret < 0)
+                       return -1;
+
+               if (buflen >= ret)
+                       break;
+
+               buflen = ret;
+               buf = realloc(buf, buflen);
+               if (!buf)
+                       return -1;
+       }
+
+       *_buffer = buf;
+       return buflen - 1;
+
+} /* end keyctl_describe_alloc() */
+
+/*****************************************************************************/
+/*
+ * fetch key contents into an allocated buffer
+ * - resulting buffer has an extra NUL added to the end
+ * - returns count (not including extraneous NUL)
+ */
+int keyctl_read_alloc(key_serial_t id, void **_buffer)
+{
+       void *buf;
+       long buflen, ret;
+
+       ret = keyctl_read(id, NULL, 0);
+       if (ret < 0)
+               return -1;
+
+       buflen = ret;
+       buf = malloc(buflen + 1);
+       if (!buf)
+               return -1;
+
+       for (;;) {
+               ret = keyctl_read(id, buf, buflen);
+               if (ret < 0)
+                       return -1;
+
+               if (buflen >= ret)
+                       break;
+
+               buflen = ret;
+               buf = realloc(buf, buflen + 1);
+               if (!buf)
+                       return -1;
+       }
+
+       ((unsigned char *) buf)[buflen] = 0;
+       *_buffer = buf;
+       return buflen;
+
+} /* end keyctl_read_alloc() */
+
+/*****************************************************************************/
+/*
+ * fetch key security label into an allocated buffer
+ * - resulting string is NUL terminated
+ * - returns count not including NUL
+ */
+int keyctl_get_security_alloc(key_serial_t id, char **_buffer)
+{
+       char *buf;
+       long buflen, ret;
+
+       ret = keyctl_get_security(id, NULL, 0);
+       if (ret < 0)
+               return -1;
+
+       buflen = ret;
+       buf = malloc(buflen);
+       if (!buf)
+               return -1;
+
+       for (;;) {
+               ret = keyctl_get_security(id, buf, buflen);
+               if (ret < 0)
+                       return -1;
+
+               if (buflen >= ret)
+                       break;
+
+               buflen = ret;
+               buf = realloc(buf, buflen);
+               if (!buf)
+                       return -1;
+       }
+
+       *_buffer = buf;
+       return buflen - 1;
+}
+
+/*
+ * Depth-first recursively apply a function over a keyring tree
+ */
+static int recursive_key_scan_aux(key_serial_t parent, key_serial_t key,
+                                 int depth, recursive_key_scanner_t func,
+                                 void *data)
+{
+       key_serial_t *pk;
+       key_perm_t perm;
+       size_t ringlen;
+       void *ring;
+       char *desc, type[255];
+       int desc_len, uid, gid, ret, n, kcount = 0;
+
+       if (depth > 800)
+               return 0;
+
+       /* read the key description */
+       desc = NULL;
+       desc_len = keyctl_describe_alloc(key, &desc);
+       if (desc_len < 0)
+               goto do_this_key;
+
+       /* parse */
+       type[0] = 0;
+
+       n = sscanf(desc, "%[^;];%d;%d;%x;", type, &uid, &gid, &perm);
+       if (n != 4) {
+               free(desc);
+               desc = NULL;
+               errno = -EINVAL;
+               desc_len = -1;
+               goto do_this_key;
+       }
+
+       /* if it's a keyring then we're going to want to recursively search it
+        * if we can */
+       if (strcmp(type, "keyring") == 0) {
+               /* read the keyring's contents */
+               ret = keyctl_read_alloc(key, &ring);
+               if (ret < 0)
+                       goto do_this_key;
+
+               ringlen = ret;
+
+               /* walk the keyring */
+               pk = ring;
+               for (ringlen = ret;
+                    ringlen >= sizeof(key_serial_t);
+                    ringlen -= sizeof(key_serial_t)
+                    )
+                       kcount += recursive_key_scan_aux(key, *pk++, depth + 1,
+                                                        func, data);
+
+               free(ring);
+       }
+
+do_this_key:
+       kcount += func(parent, key, desc, desc_len, data);
+       free(desc);
+       return kcount;
+}
+
+/*
+ * Depth-first apply a function over a keyring tree
+ */
+int recursive_key_scan(key_serial_t key, recursive_key_scanner_t func, void *data)
+{
+       return recursive_key_scan_aux(0, key, 0, func, data);
+}
+
+/*
+ * Depth-first apply a function over session keyring tree
+ */
+int recursive_session_key_scan(recursive_key_scanner_t func, void *data)
+{
+       key_serial_t session =
+               keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 0);
+       if (session > 0)
+               return recursive_key_scan(session, func, data);
+       return 0;
+}
+
+#ifdef NO_GLIBC_KEYERR
+/*****************************************************************************/
+/*
+ * initialise error handling
+ */
+static void error_init(void)
+{
+       char *err;
+
+       error_inited = 1;
+
+       dlerror();
+
+       libc_perror = dlsym(RTLD_NEXT,"perror");
+       if (!libc_perror) {
+               fprintf(stderr, "Failed to look up next perror\n");
+               err = dlerror();
+               if (err)
+                       fprintf(stderr, "%s\n", err);
+               abort();
+       }
+
+       //fprintf(stderr, "next perror at %p\n", libc_perror);
+
+       libc_strerror_r = dlsym(RTLD_NEXT,"strerror_r");
+       if (!libc_strerror_r) {
+               fprintf(stderr, "Failed to look up next strerror_r\n");
+               err = dlerror();
+               if (err)
+                       fprintf(stderr, "%s\n", err);
+               abort();
+       }
+
+       //fprintf(stderr, "next strerror_r at %p\n", libc_strerror_r);
+
+#if 0
+       libc_xpg_strerror_r = dlsym(RTLD_NEXT,"xpg_strerror_r");
+       if (!libc_xpg_strerror_r) {
+               fprintf(stderr, "Failed to look up next xpg_strerror_r\n");
+               err = dlerror();
+               if (err)
+                       fprintf(stderr, "%s\n", err);
+               abort();
+       }
+
+       //fprintf(stderr, "next xpg_strerror_r at %p\n", libc_xpg_strerror_r);
+#endif
+
+} /* end error_init() */
+
+/*****************************************************************************/
+/*
+ * overload glibc's strerror_r() with a version that knows about key errors
+ */
+char *strerror_r(int errnum, char *buf, size_t n)
+{
+       const char *errstr;
+       int len;
+
+       printf("hello\n");
+
+       if (!error_inited)
+               error_init();
+
+       switch (errnum) {
+       case ENOKEY:
+               errstr = "Requested key not available";
+               break;
+
+       case EKEYEXPIRED:
+               errstr = "Key has expired";
+               break;
+
+       case EKEYREVOKED:
+               errstr = "Key has been revoked";
+               break;
+
+       case EKEYREJECTED:
+               errstr = "Key was rejected by service";
+               break;
+
+       default:
+               return libc_strerror_r(errnum, buf, n);
+       }
+
+       len = strlen(errstr) + 1;
+       if (n > len) {
+               errno = ERANGE;
+               if (n > 0) {
+                       memcpy(buf, errstr, n - 1);
+                       buf[n - 1] = 0;
+               }
+               return NULL;
+       }
+       else {
+               memcpy(buf, errstr, len);
+               return buf;
+       }
+
+} /* end strerror_r() */
+
+#if 0
+/*****************************************************************************/
+/*
+ * overload glibc's strerror_r() with a version that knows about key errors
+ */
+int xpg_strerror_r(int errnum, char *buf, size_t n)
+{
+       const char *errstr;
+       int len;
+
+       if (!error_inited)
+               error_init();
+
+       switch (errnum) {
+       case ENOKEY:
+               errstr = "Requested key not available";
+               break;
+
+       case EKEYEXPIRED:
+               errstr = "Key has expired";
+               break;
+
+       case EKEYREVOKED:
+               errstr = "Key has been revoked";
+               break;
+
+       case EKEYREJECTED:
+               errstr = "Key was rejected by service";
+               break;
+
+       default:
+               return libc_xpg_strerror_r(errnum, buf, n);
+       }
+
+       len = strlen(errstr) + 1;
+       if (n > len) {
+               errno = ERANGE;
+               if (n > 0) {
+                       memcpy(buf, errstr, n - 1);
+                       buf[n - 1] = 0;
+               }
+               return -1;
+       }
+       else {
+               memcpy(buf, errstr, len);
+               return 0;
+       }
+
+} /* end xpg_strerror_r() */
+#endif
+
+/*****************************************************************************/
+/*
+ *
+ */
+void perror(const char *msg)
+{
+       if (!error_inited)
+               error_init();
+
+       switch (errno) {
+       case ENOKEY:
+               fprintf(stderr, "%s: Requested key not available\n", msg);
+               return;
+
+       case EKEYEXPIRED:
+               fprintf(stderr, "%s: Key has expired\n", msg);
+               return;
+
+       case EKEYREVOKED:
+               fprintf(stderr, "%s: Key has been revoked\n", msg);
+               return;
+
+       case EKEYREJECTED:
+               fprintf(stderr, "%s: Key was rejected by service\n", msg);
+               return;
+
+       default:
+               libc_perror(msg);
+               return;
+       }
+
+} /* end perror() */
+#endif
diff --git a/keyutils.h b/keyutils.h
new file mode 100644 (file)
index 0000000..05517d9
--- /dev/null
@@ -0,0 +1,161 @@
+/* keyutils.h: key utility library interface
+ *
+ * Copyright (C) 2005,2011 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef KEYUTILS_H
+#define KEYUTILS_H
+
+#include <stdint.h>
+
+/* key serial number */
+typedef int32_t key_serial_t;
+
+/* special process keyring shortcut IDs */
+#define KEY_SPEC_THREAD_KEYRING                -1      /* - key ID for thread-specific keyring */
+#define KEY_SPEC_PROCESS_KEYRING       -2      /* - key ID for process-specific keyring */
+#define KEY_SPEC_SESSION_KEYRING       -3      /* - key ID for session-specific keyring */
+#define KEY_SPEC_USER_KEYRING          -4      /* - key ID for UID-specific keyring */
+#define KEY_SPEC_USER_SESSION_KEYRING  -5      /* - key ID for UID-session keyring */
+#define KEY_SPEC_GROUP_KEYRING         -6      /* - key ID for GID-specific keyring */
+#define KEY_SPEC_REQKEY_AUTH_KEY       -7      /* - key ID for assumed request_key auth key */
+
+/* request-key default keyrings */
+#define KEY_REQKEY_DEFL_NO_CHANGE              -1
+#define KEY_REQKEY_DEFL_DEFAULT                        0
+#define KEY_REQKEY_DEFL_THREAD_KEYRING         1
+#define KEY_REQKEY_DEFL_PROCESS_KEYRING                2
+#define KEY_REQKEY_DEFL_SESSION_KEYRING                3
+#define KEY_REQKEY_DEFL_USER_KEYRING           4
+#define KEY_REQKEY_DEFL_USER_SESSION_KEYRING   5
+#define KEY_REQKEY_DEFL_GROUP_KEYRING          6
+
+/* key handle permissions mask */
+typedef uint32_t key_perm_t;
+
+#define KEY_POS_VIEW   0x01000000      /* possessor can view a key's attributes */
+#define KEY_POS_READ   0x02000000      /* possessor can read key payload / view keyring */
+#define KEY_POS_WRITE  0x04000000      /* possessor can update key payload / add link to keyring */
+#define KEY_POS_SEARCH 0x08000000      /* possessor can find a key in search / search a keyring */
+#define KEY_POS_LINK   0x10000000      /* possessor can create a link to a key/keyring */
+#define KEY_POS_SETATTR        0x20000000      /* possessor can set key attributes */
+#define KEY_POS_ALL    0x3f000000
+
+#define KEY_USR_VIEW   0x00010000      /* user permissions... */
+#define KEY_USR_READ   0x00020000
+#define KEY_USR_WRITE  0x00040000
+#define KEY_USR_SEARCH 0x00080000
+#define KEY_USR_LINK   0x00100000
+#define KEY_USR_SETATTR        0x00200000
+#define KEY_USR_ALL    0x003f0000
+
+#define KEY_GRP_VIEW   0x00000100      /* group permissions... */
+#define KEY_GRP_READ   0x00000200
+#define KEY_GRP_WRITE  0x00000400
+#define KEY_GRP_SEARCH 0x00000800
+#define KEY_GRP_LINK   0x00001000
+#define KEY_GRP_SETATTR        0x00002000
+#define KEY_GRP_ALL    0x00003f00
+
+#define KEY_OTH_VIEW   0x00000001      /* third party permissions... */
+#define KEY_OTH_READ   0x00000002
+#define KEY_OTH_WRITE  0x00000004
+#define KEY_OTH_SEARCH 0x00000008
+#define KEY_OTH_LINK   0x00000010
+#define KEY_OTH_SETATTR        0x00000010
+#define KEY_OTH_ALL    0x0000003f
+
+/* keyctl commands */
+#define KEYCTL_GET_KEYRING_ID          0       /* ask for a keyring's ID */
+#define KEYCTL_JOIN_SESSION_KEYRING    1       /* join or start named session keyring */
+#define KEYCTL_UPDATE                  2       /* update a key */
+#define KEYCTL_REVOKE                  3       /* revoke a key */
+#define KEYCTL_CHOWN                   4       /* set ownership of a key */
+#define KEYCTL_SETPERM                 5       /* set perms on a key */
+#define KEYCTL_DESCRIBE                        6       /* describe a key */
+#define KEYCTL_CLEAR                   7       /* clear contents of a keyring */
+#define KEYCTL_LINK                    8       /* link a key into a keyring */
+#define KEYCTL_UNLINK                  9       /* unlink a key from a keyring */
+#define KEYCTL_SEARCH                  10      /* search for a key in a keyring */
+#define KEYCTL_READ                    11      /* read a key or keyring's contents */
+#define KEYCTL_INSTANTIATE             12      /* instantiate a partially constructed key */
+#define KEYCTL_NEGATE                  13      /* negate a partially constructed key */
+#define KEYCTL_SET_REQKEY_KEYRING      14      /* set default request-key keyring */
+#define KEYCTL_SET_TIMEOUT             15      /* set timeout on a key */
+#define KEYCTL_ASSUME_AUTHORITY                16      /* assume authority to instantiate key */
+#define KEYCTL_GET_SECURITY            17      /* get key security label */
+#define KEYCTL_SESSION_TO_PARENT       18      /* set my session keyring on my parent process */
+#define KEYCTL_REJECT                  19      /* reject a partially constructed key */
+#define KEYCTL_INSTANTIATE_IOV         20      /* instantiate a partially constructed key */
+
+/*
+ * syscall wrappers
+ */
+extern key_serial_t add_key(const char *type,
+                           const char *description,
+                           const void *payload,
+                           size_t plen,
+                           key_serial_t ringid);
+
+extern key_serial_t request_key(const char *type,
+                               const char *description,
+                               const char *callout_info,
+                               key_serial_t destringid);
+
+extern long keyctl(int cmd, ...);
+
+/*
+ * keyctl function wrappers
+ */
+extern key_serial_t keyctl_get_keyring_ID(key_serial_t id, int create);
+extern key_serial_t keyctl_join_session_keyring(const char *name);
+extern long keyctl_update(key_serial_t id, const void *payload, size_t plen);
+extern long keyctl_revoke(key_serial_t id);
+extern long keyctl_chown(key_serial_t id, uid_t uid, gid_t gid);
+extern long keyctl_setperm(key_serial_t id, key_perm_t perm);
+extern long keyctl_describe(key_serial_t id, char *buffer, size_t buflen);
+extern long keyctl_clear(key_serial_t ringid);
+extern long keyctl_link(key_serial_t id, key_serial_t ringid);
+extern long keyctl_unlink(key_serial_t id, key_serial_t ringid);
+extern long keyctl_search(key_serial_t ringid,
+                         const char *type,
+                         const char *description,
+                         key_serial_t destringid);
+extern long keyctl_read(key_serial_t id, char *buffer, size_t buflen);
+extern long keyctl_instantiate(key_serial_t id,
+                              const void *payload,
+                              size_t plen,
+                              key_serial_t ringid);
+extern long keyctl_negate(key_serial_t id, unsigned timeout, key_serial_t ringid);
+extern long keyctl_set_reqkey_keyring(int reqkey_defl);
+extern long keyctl_set_timeout(key_serial_t key, unsigned timeout);
+extern long keyctl_assume_authority(key_serial_t key);
+extern long keyctl_get_security(key_serial_t key, char *buffer, size_t buflen);
+extern long keyctl_session_to_parent(void);
+extern long keyctl_reject(key_serial_t id, unsigned timeout, unsigned error,
+                         key_serial_t ringid);
+struct iovec;
+extern long keyctl_instantiate_iov(key_serial_t id,
+                                  const struct iovec *payload_iov,
+                                  unsigned ioc,
+                                  key_serial_t ringid);
+
+/*
+ * utilities
+ */
+extern int keyctl_describe_alloc(key_serial_t id, char **_buffer);
+extern int keyctl_read_alloc(key_serial_t id, void **_buffer);
+extern int keyctl_get_security_alloc(key_serial_t id, char **_buffer);
+
+typedef int (*recursive_key_scanner_t)(key_serial_t parent, key_serial_t key,
+                                      char *desc, int desc_len, void *data);
+extern int recursive_key_scan(key_serial_t key, recursive_key_scanner_t func, void *data);
+extern int recursive_session_key_scan(recursive_key_scanner_t func, void *data);
+
+#endif /* KEYUTILS_H */
diff --git a/keyutils.spec b/keyutils.spec
new file mode 100644 (file)
index 0000000..82e6b0d
--- /dev/null
@@ -0,0 +1,218 @@
+%define vermajor 1
+%define verminor 5.3
+%define version %{vermajor}.%{verminor}
+%define libdir /%{_lib}
+%define usrlibdir %{_prefix}/%{_lib}
+%define libapivermajor 1
+%define libapiversion %{libapivermajor}.4
+
+Summary: Linux Key Management Utilities
+Name: keyutils
+Version: %{version}
+Release: 1%{?dist}
+License: GPLv2+ and LGPLv2+
+Group: System Environment/Base
+ExclusiveOS: Linux
+Url: http://people.redhat.com/~dhowells/keyutils/
+
+Source0: http://people.redhat.com/~dhowells/keyutils/keyutils-%{version}.tar.bz2
+
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+BuildRequires: glibc-kernheaders >= 2.4-9.1.92
+Requires: keyutils-libs == %{version}-%{release}
+
+%description
+Utilities to control the kernel key management facility and to provide
+a mechanism by which the kernel call back to user space to get a key
+instantiated.
+
+%package libs
+Summary: Key utilities library
+Group: System Environment/Base
+
+%description libs
+This package provides a wrapper library for the key management facility system
+calls.
+
+%package libs-devel
+Summary: Development package for building Linux key management utilities
+Group: System Environment/Base
+Requires: keyutils-libs == %{version}-%{release}
+
+%description libs-devel
+This package provides headers and libraries for building key utilities.
+
+%prep
+%setup -q
+
+%build
+make \
+       NO_ARLIB=1 \
+       LIBDIR=%{libdir} \
+       USRLIBDIR=%{usrlibdir} \
+       RELEASE=.%{release} \
+       NO_GLIBC_KEYERR=1 \
+       CFLAGS="-Wall $RPM_OPT_FLAGS -Werror"
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make \
+       NO_ARLIB=1 \
+       DESTDIR=$RPM_BUILD_ROOT \
+       LIBDIR=%{libdir} \
+       USRLIBDIR=%{usrlibdir} \
+       install
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post libs -p /sbin/ldconfig
+%postun libs -p /sbin/ldconfig
+
+%files
+%defattr(-,root,root,-)
+%doc README LICENCE.GPL
+/sbin/*
+/bin/*
+/usr/share/keyutils
+%{_mandir}/man1/*
+%{_mandir}/man5/*
+%{_mandir}/man8/*
+%config(noreplace) /etc/*
+
+%files libs
+%defattr(-,root,root,-)
+%doc LICENCE.LGPL
+%{libdir}/libkeyutils.so.%{libapiversion}
+%{libdir}/libkeyutils.so.%{libapivermajor}
+
+%files libs-devel
+%defattr(-,root,root,-)
+%{usrlibdir}/libkeyutils.so
+%{_includedir}/*
+%{_mandir}/man3/*
+
+%changelog
+* Thu Aug 11 2011 David Howells  <dhowells@redhat.com> - 1.5.3-1
+- Make the keyutils rpm depend on the same keyutils-libs rpm version.
+
+* Tue Jul 26 2011 David Howells  <dhowells@redhat.com> - 1.5.2-1
+- Use correct format spec for printing pointer subtraction results.
+
+* Tue Jul 19 2011 David Howells  <dhowells@redhat.com> - 1.5.1-1
+- Fix unread variables.
+- Licence file update.
+
+* Thu Mar 10 2011 David Howells  <dhowells@redhat.com> - 1.5-1
+- Disable RPATH setting in Makefile.
+- Add -I. to build to get this keyutils.h.
+- Make CFLAGS override on make command line work right.
+- Make specfile UTF-8.
+- Support KEYCTL_REJECT.
+- Support KEYCTL_INSTANTIATE_IOV.
+- Add AFSDB DNS lookup program from Wang Lei.
+- Generalise DNS lookup program.
+- Add recursive scan utility function.
+- Add bad key reap command to keyctl.
+- Add multi-unlink variant to keyctl unlink command.
+- Add multi key purger command to keyctl.
+- Handle multi-line commands in keyctl command table.
+- Move the package to version to 1.5.
+
+* Tue Mar 1 2011 David Howells  <dhowells@redhat.com> - 1.4-4
+- Make build guess at default libdirs and word size.
+- Make program build depend on library in Makefile.
+- Don't include $(DESTDIR) in MAN* macros.
+- Remove NO_GLIBC_KEYSYS as it is obsolete.
+- Have Makefile extract version info from specfile and version script.
+- Provide RPM build rule in Makefile.
+- Provide distclean rule in Makefile.
+
+* Fri Dec 17 2010 Diego Elio Pettenò <flameeyes@hosting.flameeyes.eu> - 1.4-3
+- Fix local linking and RPATH.
+
+* Thu Jun 10 2010 David Howells  <dhowells@redhat.com> - 1.4-2
+- Fix prototypes in manual pages (some char* should be void*).
+- Rename the keyctl_security.3 manpage to keyctl_get_security.3.
+
+* Fri Mar 19 2010 David Howells  <dhowells@redhat.com> - 1.4-1
+- Fix the library naming wrt the version.
+- Move the package to version to 1.4.
+
+* Fri Mar 19 2010 David Howells  <dhowells@redhat.com> - 1.3-3
+- Fix spelling mistakes in manpages.
+- Add an index manpage for all the keyctl functions.
+
+* Thu Mar 11 2010 David Howells  <dhowells@redhat.com> - 1.3-2
+- Fix rpmlint warnings.
+
+* Fri Feb 26 2010 David Howells <dhowells@redhat.com> - 1.3-1
+- Fix compiler warnings in request-key.
+- Expose the kernel function to get a key's security context.
+- Expose the kernel function to set a processes keyring onto its parent.
+- Move libkeyutils library version to 1.3.
+
+* Tue Aug 22 2006 David Howells <dhowells@redhat.com> - 1.2-1
+- Remove syscall manual pages (section 2) to man-pages package [BZ 203582]
+- Don't write to serial port in debugging script
+
+* Mon Jun 5 2006 David Howells <dhowells@redhat.com> - 1.1-4
+- Call ldconfig during (un)installation.
+
+* Fri May 5 2006 David Howells <dhowells@redhat.com> - 1.1-3
+- Don't include the release number in the shared library filename
+- Don't build static library
+
+* Fri May 5 2006 David Howells <dhowells@redhat.com> - 1.1-2
+- More bug fixes from Fedora reviewer.
+
+* Thu May 4 2006 David Howells <dhowells@redhat.com> - 1.1-1
+- Fix rpmlint errors
+
+* Mon Dec 5 2005 David Howells <dhowells@redhat.com> - 1.0-2
+- Add build dependency on glibc-kernheaders with key management syscall numbers
+
+* Tue Nov 29 2005 David Howells <dhowells@redhat.com> - 1.0-1
+- Add data pipe-in facility for keyctl request2
+
+* Mon Nov 28 2005 David Howells <dhowells@redhat.com> - 1.0-1
+- Rename library and header file "keyutil" -> "keyutils" for consistency
+- Fix shared library version naming to same way as glibc.
+- Add versioning for shared library symbols
+- Create new keyutils-libs package and install library and main symlink there
+- Install base library symlink in /usr/lib and place in devel package
+- Added a keyutils archive library
+- Shorten displayed key permissions list to just those we actually have
+
+* Thu Nov 24 2005 David Howells <dhowells@redhat.com> - 0.3-4
+- Add data pipe-in facilities for keyctl add, update and instantiate
+
+* Fri Nov 18 2005 David Howells <dhowells@redhat.com> - 0.3-3
+- Added stdint.h inclusion in keyutils.h
+- Made request-key.c use request_key() rather than keyctl_search()
+- Added piping facility to request-key
+
+* Thu Nov 17 2005 David Howells <dhowells@redhat.com> - 0.3-2
+- Added timeout keyctl option
+- request_key auth keys must now be assumed
+- Fix keyctl argument ordering for debug negate line in request-key.conf
+
+* Thu Jul 28 2005 David Howells <dhowells@redhat.com> - 0.3-1
+- Must invoke initialisation from perror() override in libkeyutils
+- Minor UI changes
+
+* Wed Jul 20 2005 David Howells <dhowells@redhat.com> - 0.2-2
+- Bump version to permit building in main repositories.
+
+* Mon Jul 12 2005 David Howells <dhowells@redhat.com> - 0.2-1
+- Don't attempt to define the error codes in the header file.
+- Pass the release ID through to the makefile to affect the shared library name.
+
+* Mon Jul 12 2005 David Howells <dhowells@redhat.com> - 0.1-3
+- Build in the perror() override to get the key error strings displayed.
+
+* Mon Jul 12 2005 David Howells <dhowells@redhat.com> - 0.1-2
+- Need a defattr directive after each files directive.
+
+* Mon Jul 12 2005 David Howells <dhowells@redhat.com> - 0.1-1
+- Package creation.
diff --git a/recursive_key_scan.3 b/recursive_key_scan.3
new file mode 100644 (file)
index 0000000..c07be85
--- /dev/null
@@ -0,0 +1,87 @@
+.\"
+.\" Copyright (C) 2011 Red Hat, Inc. All Rights Reserved.
+.\" Written by David Howells (dhowells@redhat.com)
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public Licence
+.\" as published by the Free Software Foundation; either version
+.\" 2 of the Licence, or (at your option) any later version.
+.\"
+.TH RECURSIVE_KEY_SCAN 3 "10 Mar 2011" Linux "Linux Key Utility Calls"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+recursive_key_scan \- Apply a function to all keys in a keyring tree
+.br
+recursive_session_key_scan \- Apply a function to all keys in the session keyring tree
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SYNOPSIS
+.nf
+.B #include <keyutils.h>
+.sp
+.BI "typedef int (*" recursive_key_scanner_t ")(key_serial_t " parent ,
+.BI "    key_serial_t " key ", char *" desc ", int " desc_len ", void *" data ");"
+.sp
+.BI "long recursive_key_scan(key_serial_t " keyring ,
+.BI "    recursive_key_scanner_t " func ", void *" data ");"
+.br
+.BI "long recursive_session_key_scan(recursive_key_scanner_t " func ,
+.BI "    void *" data ");"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+.BR recursive_key_scan ()
+performs a depth-first recursive scan of the specified
+.I keyring
+tree and applies
+.I func
+to every link found in the accessible keyrings in that tree.
+.I data
+is passed to each invocation of func.
+.P
+The return values of
+.I func
+are summed and returned as the overall return value.  Errors are ignored.
+Inaccessible keyrings are not scanned, but links to them are still passed to
+func.
+.P
+.BR recursive_session_key_scan ()
+works exactly like
+.IR recursive_key_scan ()
+with the caller's session keyring specified as the starting keyring.
+.P
+The callback function is called for each link found in all the keyrings in the
+nominated tree and so may be called multiple times for a particular key if that
+key has multiple links to it.
+.P
+The callback function is passed the following parameters:
+.TP
+.B parent
+The keyring containing the link or 0 for the initial key.
+.TP
+.BR key
+The key to which the link points.
+.TP
+.BR desc " and " desc_len
+A pointer to the raw description and its length as retrieved with
+.IR keyctl_describe_alloc ().
+These will be NULL and -1 respectively if the description couldn't be
+retrieved and errno will retain the error from
+.IR keyctl_describe_alloc ().
+.TP
+.B data
+The data passed to the scanner function.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+These functions return the sum of the results of the callback functions they
+invoke.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH ERRORS
+Ignored.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH LINKING
+When linking,
+.B -lkeyutils
+should be specified to the linker.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SEE ALSO
+.BR keyctl (3),
+.BR keyctl_describe_alloc (3)
diff --git a/request-key-debug.sh b/request-key-debug.sh
new file mode 100755 (executable)
index 0000000..83af01d
--- /dev/null
@@ -0,0 +1,33 @@
+#!/bin/sh
+###############################################################################
+#
+# Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
+# Written by David Howells (dhowells@redhat.com)
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+###############################################################################
+#
+# Request key debugging
+#
+# Call: request-key-debug.sh <keyid> <desc> <callout> <session-keyring>
+#
+
+echo RQDebug keyid: $1
+echo RQDebug desc: $2
+echo RQDebug callout: $3
+echo RQDebug session keyring: $4
+
+if [ "$3" != "neg" ]
+then
+    keyctl instantiate $1 "Debug $3" $4 || exit 1
+else
+    cat /proc/keys
+    echo keyctl negate $1 30 $4
+    keyctl negate $1 30 $4
+fi
+
+exit 0
diff --git a/request-key.8 b/request-key.8
new file mode 100644 (file)
index 0000000..00b6ebb
--- /dev/null
@@ -0,0 +1,29 @@
+.\"
+.\" Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+.\" Written by David Howells (dhowells@redhat.com)
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License
+.\" as published by the Free Software Foundation; either version
+.\" 2 of the License, or (at your option) any later version.
+.\"
+.TH REQUEST-KEY 8 "17 Nov 2005" Linux "Linux Key Management Utilities"
+.SH NAME
+request-key - Handle key instantiation callback requests from the kernel
+.SH SYNOPSIS
+\fB/sbin/request-key \fR<op> <key> <uid> <gid> <threadring> <processring>
+       <sessionring> [<info>]
+.SH DESCRIPTION
+This program is invoked by the kernel when the kernel is asked for a key that
+it doesn't have immediately available. The kernel creates a partially set up
+key and then calls out to this program to instantiate it. It is not intended
+to be called directly.
+.SH ERRORS
+All errors will be logged to the syslog.
+.SH FILES
+.ul
+/etc/request-key.conf
+.ul 0
+Instantiation handler configuration file.
+.SH SEE ALSO
+\fBkeyctl\fR(1), \fBrequest-key.conf\fR(5)
diff --git a/request-key.c b/request-key.c
new file mode 100644 (file)
index 0000000..4d07129
--- /dev/null
@@ -0,0 +1,849 @@
+/* request-key.c: hand a key request off to the appropriate process
+ *
+ * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * /sbin/request-key <op> <key> <uid> <gid> <threadring> <processring> <sessionring> [<info>]
+ *
+ * Searches the specified session ring for a key indicating the command to run:
+ *     type:   "user"
+ *     desc:   "request-key:<op>"
+ *     data:   command name, eg: "/home/dhowells/request-key-create.sh"
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <signal.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/select.h>
+#include <sys/wait.h>
+#include "keyutils.h"
+
+
+static int xdebug;
+static int xnolog;
+static char *xkey;
+static char *xuid;
+static char *xgid;
+static char *xthread_keyring;
+static char *xprocess_keyring;
+static char *xsession_keyring;
+static int confline;
+static int norecurse;
+
+static void lookup_action(char *op,
+                         key_serial_t key,
+                         char *ktype,
+                         char *kdesc,
+                         char *callout_info)
+       __attribute__((noreturn));
+
+static void execute_program(char *op,
+                           key_serial_t key,
+                           char *ktype,
+                           char *kdesc,
+                           char *callout_info,
+                           char *cmdline)
+       __attribute__((noreturn));
+
+static void pipe_to_program(char *op,
+                           key_serial_t key,
+                           char *ktype,
+                           char *kdesc,
+                           char *callout_info,
+                           char *prog,
+                           char **argv)
+       __attribute__((noreturn));
+
+static int match(const char *pattern, int plen, const char *datum, int dlen);
+
+static void debug(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
+static void debug(const char *fmt, ...)
+{
+       va_list va;
+
+       if (xdebug) {
+               va_start(va, fmt);
+               vfprintf(stderr, fmt, va);
+               va_end(va);
+
+               if (!xnolog) {
+                       openlog("request-key", 0, LOG_AUTHPRIV);
+
+                       va_start(va, fmt);
+                       vsyslog(LOG_DEBUG, fmt, va);
+                       va_end(va);
+
+                       closelog();
+               }
+       }
+}
+
+static void error(const char *fmt, ...) __attribute__((noreturn, format(printf, 1, 2)));
+static void error(const char *fmt, ...)
+{
+       va_list va;
+
+       if (xdebug) {
+               va_start(va, fmt);
+               vfprintf(stderr, fmt, va);
+               va_end(va);
+       }
+
+       if (!xnolog) {
+               openlog("request-key", 0, LOG_AUTHPRIV);
+
+               va_start(va, fmt);
+               vsyslog(LOG_ERR, fmt, va);
+               va_end(va);
+
+               closelog();
+       }
+
+       exit(1);
+}
+
+static void oops(int x)
+{
+       error("Died on signal %d", x);
+}
+
+/*****************************************************************************/
+/*
+ *
+ */
+int main(int argc, char *argv[])
+{
+       key_serial_t key;
+       char *ktype, *kdesc, *buf, *callout_info;
+       int ret, ntype, dpos, n, fd;
+
+       signal(SIGSEGV, oops);
+       signal(SIGBUS, oops);
+       signal(SIGPIPE, SIG_IGN);
+
+       for (;;) {
+               if (argc > 1 && strcmp(argv[1], "-d") == 0) {
+                       xdebug++;
+                       argv++;
+                       argc--;
+               }
+               else if (argc > 1 && strcmp(argv[1], "-n") == 0) {
+                       xnolog = 1;
+                       argv++;
+                       argc--;
+               }
+               else
+                       break;
+       }
+
+       if (argc != 8 && argc != 9)
+               error("Unexpected argument count: %d\n", argc);
+
+       fd = open("/dev/null", O_RDWR);
+       if (fd < 0)
+               error("open");
+       if (fd > 2) {
+               close(fd);
+       }
+       else if (fd < 2) {
+               ret = dup(fd);
+               if (ret < 0)
+                       error("dup failed: %m\n");
+
+               if (ret < 2 && dup(fd) < 0)
+                       error("dup failed: %m\n");
+       }
+
+       xkey = argv[2];
+       xuid = argv[3];
+       xgid = argv[4];
+       xthread_keyring = argv[5];
+       xprocess_keyring = argv[6];
+       xsession_keyring = argv[7];
+
+       key = atoi(xkey);
+
+       /* assume authority over the key
+        * - older kernel doesn't support this function
+        */
+       ret = keyctl_assume_authority(key);
+       if (ret < 0 && !(argc == 9 || errno == EOPNOTSUPP))
+               error("Failed to assume authority over key %d (%m)\n", key);
+
+       /* ask the kernel to describe the key to us */
+       if (xdebug < 2) {
+               ret = keyctl_describe_alloc(key, &buf);
+               if (ret < 0)
+                       goto inaccessible;
+       }
+       else {
+               buf = strdup("user;0;0;1f0000;debug:1234");
+       }
+
+       /* extract the type and description from the key */
+       debug("Key descriptor: \"%s\"\n", buf);
+       ntype = -1;
+       dpos = -1;
+
+       n = sscanf(buf, "%*[^;]%n;%*d;%*d;%x;%n", &ntype, &n, &dpos);
+       if (n != 1)
+               error("Failed to parse key description\n");
+
+       ktype = buf;
+       ktype[ntype] = 0;
+       kdesc = buf + dpos;
+
+       debug("Key type: %s\n", ktype);
+       debug("Key desc: %s\n", kdesc);
+
+       /* get hold of the callout info */
+       callout_info = argv[8];
+
+       if (!callout_info) {
+               void *tmp;
+
+               if (keyctl_read_alloc(KEY_SPEC_REQKEY_AUTH_KEY, &tmp) < 0)
+                       error("Failed to retrieve callout info (%m)\n");
+
+               callout_info = tmp;
+       }
+
+       debug("CALLOUT: '%s'\n", callout_info);
+
+       /* determine the action to perform */
+       lookup_action(argv[1],          /* op */
+                     key,              /* ID of key under construction */
+                     ktype,            /* key type */
+                     kdesc,            /* key description */
+                     callout_info      /* call out information */
+                     );
+
+inaccessible:
+       error("Key %d is inaccessible (%m)\n", key);
+
+} /* end main() */
+
+/*****************************************************************************/
+/*
+ * determine the action to perform
+ */
+static void lookup_action(char *op,
+                         key_serial_t key,
+                         char *ktype,
+                         char *kdesc,
+                         char *callout_info)
+{
+       char buf[4096 + 2], *p, *q;
+       FILE *conf;
+       int len, oplen, ktlen, kdlen, cilen;
+
+       oplen = strlen(op);
+       ktlen = strlen(ktype);
+       kdlen = strlen(kdesc);
+       cilen = strlen(callout_info);
+
+       /* search the config file for a command to run */
+       conf = fopen(xdebug < 2 ? "/etc/request-key.conf" : "request-key.conf", "r");
+       if (!conf)
+               error("Cannot open /etc/request-key.conf: %m\n");
+
+       for (confline = 1;; confline++) {
+               /* read the file line-by-line */
+               if (!fgets(buf, sizeof(buf), conf)) {
+                       if (feof(conf))
+                               error("Cannot find command to construct key %d\n", key);
+                       error("Error reading /etc/request-key.conf\n");
+               }
+
+               len = strlen(buf);
+               if (len >= sizeof(buf) - 2)
+                       error("/etc/request-key.conf:%d: Line too long\n", confline);
+
+               /* ignore blank lines and comments */
+               if (len == 1 || buf[0] == '#' || isspace(buf[0]))
+                       continue;
+
+               buf[--len] = 0;
+               p = buf;
+
+               /* attempt to match the op */
+               q = p;
+               while (*p && !isspace(*p)) p++;
+               if (!*p)
+                       goto syntax_error;
+               *p = 0;
+
+               if (!match(q, p - q, op, oplen))
+                       continue;
+
+               p++;
+
+               /* attempt to match the type */
+               while (isspace(*p)) p++;
+               if (!*p)
+                       goto syntax_error;
+
+               q = p;
+               while (*p && !isspace(*p)) p++;
+               if (!*p)
+                       goto syntax_error;
+               *p = 0;
+
+               if (!match(q, p - q, ktype, ktlen))
+                       continue;
+
+               p++;
+
+               /* attempt to match the description */
+               while (isspace(*p)) p++;
+               if (!*p)
+                       goto syntax_error;
+
+               q = p;
+               while (*p && !isspace(*p)) p++;
+               if (!*p)
+                       goto syntax_error;
+               *p = 0;
+
+               if (!match(q, p - q, kdesc, kdlen))
+                       continue;
+
+               p++;
+
+               /* attempt to match the callout info */
+               while (isspace(*p)) p++;
+               if (!*p)
+                       goto syntax_error;
+
+               q = p;
+               while (*p && !isspace(*p)) p++;
+               if (!*p)
+                       goto syntax_error;
+               *p = 0;
+
+               if (!match(q, p - q, callout_info, cilen))
+                       continue;
+
+               p++;
+
+               debug("Line %d matches\n", confline);
+
+               /* we've got an action */
+               while (isspace(*p)) p++;
+               if (!*p)
+                       goto syntax_error;
+
+               fclose(conf);
+
+               execute_program(op, key, ktype, kdesc, callout_info, p);
+       }
+
+       error("/etc/request-key.conf: No matching action\n");
+
+syntax_error:
+       error("/etc/request-key.conf:%d: Syntax error\n", confline);
+
+} /* end lookup_action() */
+
+/*****************************************************************************/
+/*
+ * attempt to match a datum to a pattern
+ * - one asterisk is allowed anywhere in the pattern to indicate a wildcard
+ * - returns true if matched, false if not
+ */
+static int match(const char *pattern, int plen, const char *datum, int dlen)
+{
+       const char *asterisk;
+       int n;
+
+       debug("match(%*.*s,%*.*s)\n", plen, plen, pattern, dlen, dlen, datum);
+
+       asterisk = memchr(pattern, '*', plen);
+       if (!asterisk) {
+               /* exact match only if no wildcard */
+               if (plen == dlen && memcmp(pattern, datum, dlen) == 0)
+                       goto yes;
+               goto no;
+       }
+
+       /* the datum mustn't be shorter than the pattern without the asterisk */
+       if (dlen < plen - 1)
+               goto no;
+
+       n = asterisk - pattern;
+       if (n == 0) {
+               /* wildcard at beginning of pattern */
+               pattern++;
+               if (!*pattern)
+                       goto yes; /* "*" matches everything */
+
+               /* match the end of the datum */
+               plen--;
+               if (memcmp(pattern, datum + (dlen - plen), plen) == 0)
+                       goto yes;
+               goto no;
+       }
+
+       /* need to match beginning of datum for "abc*" and "abc*def" */
+       if (memcmp(pattern, datum, n) != 0)
+               goto no;
+
+       if (!asterisk[1])
+               goto yes; /* "abc*" matches */
+
+       /* match the end of the datum */
+       asterisk++;
+       n = plen - n - 1;
+       if (memcmp(pattern, datum + (dlen - n), n) == 0)
+               goto yes;
+
+no:
+       debug(" = no\n");
+       return 0;
+
+yes:
+       debug(" = yes\n");
+       return 1;
+
+} /* end match() */
+
+/*****************************************************************************/
+/*
+ * execute a program to deal with a key
+ */
+static void execute_program(char *op,
+                           key_serial_t key,
+                           char *ktype,
+                           char *kdesc,
+                           char *callout_info,
+                           char *cmdline)
+{
+       char *argv[256];
+       char *prog, *p, *q;
+       int argc, pipeit;
+
+       debug("execute_program('%s','%s')\n", callout_info, cmdline);
+
+       /* if the commandline begins with a bar, then we pipe the callout data into it and read
+        * back the payload data
+        */
+       pipeit = 0;
+
+       if (cmdline[0] == '|') {
+               pipeit = 1;
+               cmdline++;
+       }
+
+       /* extract the path to the program to run */
+       prog = p = cmdline;
+       while (*p && !isspace(*p)) p++;
+//     if (!*p)
+//             error("/etc/request-key.conf:%d: No command path\n", confline);
+//     *p++ = 0;
+       if (*p)
+               *p++ = 0;
+
+       argv[0] = strrchr(prog, '/') + 1;
+
+       /* extract the arguments */
+       for (argc = 1; p; argc++) {
+               while (isspace(*p)) p++;
+               if (!*p)
+                       break;
+
+               if (argc >= 254)
+                       error("/etc/request-key.conf:%d: Too many arguments\n", confline);
+               argv[argc] = q = p;
+
+               while (*p && !isspace(*p)) p++;
+
+               if (*p)
+                       *p++ = 0;
+               else
+                       p = NULL;
+
+               debug("argv[%d]: '%s'\n", argc, argv[argc]);
+
+               if (*q != '%')
+                       continue;
+
+               /* it's a macro */
+               q++;
+               if (!*q)
+                       error("/etc/request-key.conf:%d: Missing macro name\n", confline);
+
+               if (*q == '%') {
+                       /* it's actually an anti-macro escape "%%..." -> "%..." */
+                       argv[argc]++;
+                       continue;
+               }
+
+               /* single character macros */
+               if (!q[1]) {
+                       switch (*q) {
+                       case 'o': argv[argc] = op;                      continue;
+                       case 'k': argv[argc] = xkey;                    continue;
+                       case 't': argv[argc] = ktype;                   continue;
+                       case 'd': argv[argc] = kdesc;                   continue;
+                       case 'c': argv[argc] = callout_info;            continue;
+                       case 'u': argv[argc] = xuid;                    continue;
+                       case 'g': argv[argc] = xgid;                    continue;
+                       case 'T': argv[argc] = xthread_keyring;         continue;
+                       case 'P': argv[argc] = xprocess_keyring;        continue;
+                       case 'S': argv[argc] = xsession_keyring;        continue;
+                       default:
+                               error("/etc/request-key.conf:%d: Unsupported macro\n", confline);
+                       }
+               }
+
+               /* keysub macro */
+               if (*q == '{') {
+                       key_serial_t keysub;
+                       void *tmp;
+                       char *ksdesc, *end, *subdata;
+                       int ret, loop;
+
+                       /* extract type and description */
+                       q++;
+                       ksdesc = strchr(q, ':');
+                       if (!ksdesc)
+                               error("/etc/request-key.conf:%d: Keysub macro lacks ':'\n",
+                                     confline);
+                       *ksdesc++ = 0;
+                       end = strchr(ksdesc, '}');
+                       if (!end)
+                               error("/etc/request-key.conf:%d: Unterminated keysub macro\n",
+                                     confline);
+
+                       *end++ = 0;
+                       if (*end)
+                               error("/etc/request-key.conf:%d:"
+                                     " Keysub macro has trailing rubbish\n",
+                                     confline);
+
+                       debug("Keysub: %s key \"%s\"\n", q, ksdesc);
+
+                       if (!q[0])
+                               error("/etc/request-key.conf:%d: Keysub type empty\n", confline);
+
+                       if (!ksdesc[0])
+                               error("/etc/request-key.conf:%d: Keysub description empty\n",
+                                     confline);
+
+                       /* look up the key in the requestor's keyrings, but fail immediately if the
+                        * key is not found rather than invoking /sbin/request-key again
+                        */
+                       keysub = request_key(q, ksdesc, NULL, 0);
+                       if (keysub < 0)
+                               error("/etc/request-key.conf:%d:"
+                                     " Keysub key not found: %m\n",
+                                     confline);
+
+                       ret = keyctl_read_alloc(keysub, &tmp);
+                       if (ret < 0)
+                               error("/etc/request-key.conf:%d:"
+                                     " Can't read keysub %d data: %m\n",
+                                     confline, keysub);
+                       subdata = tmp;
+
+                       for (loop = 0; loop < ret; loop++)
+                               if (!isprint(subdata[loop]))
+                                       error("/etc/request-key.conf:%d:"
+                                             " keysub %d data not printable ('%02hhx')\n",
+                                             confline, keysub, subdata[loop]);
+
+                       argv[argc] = subdata;
+                       continue;
+               }
+       }
+
+       if (argc == 0)
+               error("/etc/request-key.conf:%d: No arguments\n", confline);
+
+       argv[argc] = NULL;
+
+       if (xdebug) {
+               char **ap;
+
+               debug("%s %s\n", pipeit ? "PipeThru" : "Run", prog);
+               for (ap = argv; *ap; ap++)
+                       debug("- argv[%td] = \"%s\"\n", ap - argv, *ap);
+       }
+
+       /* become the same UID/GID as the key requesting process */
+       //setgid(atoi(xuid));
+       //setuid(atoi(xgid));
+
+       /* if the last argument is a single bar, we spawn off the program dangling on the end of
+        * three pipes and read the key material from the program, otherwise we just exec
+        */
+       if (pipeit)
+               pipe_to_program(op, key, ktype, kdesc, callout_info, prog, argv);
+
+       /* attempt to execute the command */
+       execv(prog, argv);
+
+       error("/etc/request-key.conf:%d: Failed to execute '%s': %m\n", confline, prog);
+
+} /* end execute_program() */
+
+/*****************************************************************************/
+/*
+ * pipe the callout information to the specified program and retrieve the payload data over another
+ * pipe
+ */
+static void pipe_to_program(char *op,
+                           key_serial_t key,
+                           char *ktype,
+                           char *kdesc,
+                           char *callout_info,
+                           char *prog,
+                           char **argv)
+{
+       char errbuf[512], payload[32768 + 1], *pp, *pc, *pe;
+       int ipi[2], opi[2], epi[2], childpid;
+       int ifl, ofl, efl, npay, ninfo, espace, tmp;
+
+       debug("pipe_to_program(%s -> %s)", callout_info, prog);
+
+       if (pipe(ipi) < 0 || pipe(opi) < 0 || pipe(epi) < 0)
+               error("pipe failed: %m");
+
+       childpid = fork();
+       if (childpid == -1)
+               error("fork failed: %m");
+
+       if (childpid == 0) {
+               /* child process */
+               if (dup2(ipi[0], 0) < 0 ||
+                   dup2(opi[1], 1) < 0 ||
+                   dup2(epi[1], 2) < 0)
+                       error("dup2 failed: %m");
+               close(ipi[0]);
+               close(ipi[1]);
+               close(opi[0]);
+               close(opi[1]);
+               close(epi[0]);
+               close(epi[1]);
+
+               execv(prog, argv);
+               error("/etc/request-key.conf:%d: Failed to execute '%s': %m\n", confline, prog);
+       }
+
+       /* parent process */
+       close(ipi[0]);
+       close(opi[1]);
+       close(epi[1]);
+
+#define TOSTDIN ipi[1]
+#define FROMSTDOUT opi[0]
+#define FROMSTDERR epi[0]
+
+       ifl = fcntl(TOSTDIN, F_GETFL);
+       ofl = fcntl(FROMSTDOUT, F_GETFL);
+       efl = fcntl(FROMSTDERR, F_GETFL);
+       if (ifl < 0 || ofl < 0 || efl < 0)
+               error("fcntl/F_GETFL failed: %m");
+
+       ifl |= O_NONBLOCK;
+       ofl |= O_NONBLOCK;
+       efl |= O_NONBLOCK;
+
+       if (fcntl(TOSTDIN, F_SETFL, ifl) < 0 ||
+           fcntl(FROMSTDOUT, F_SETFL, ofl) < 0 ||
+           fcntl(FROMSTDERR, F_SETFL, efl) < 0)
+               error("fcntl/F_SETFL failed: %m");
+
+       ninfo = strlen(callout_info);
+       pc = callout_info;
+
+       npay = sizeof(payload);
+       pp = payload;
+
+       espace = sizeof(errbuf);
+       pe = errbuf;
+
+       do {
+               fd_set rfds, wfds;
+
+               FD_ZERO(&rfds);
+               FD_ZERO(&wfds);
+
+               if (TOSTDIN != -1) {
+                       if (ninfo > 0) {
+                               FD_SET(TOSTDIN, &wfds);
+                       }
+                       else {
+                               close(TOSTDIN);
+                               TOSTDIN = -1;
+                               continue;
+                       }
+               }
+
+               if (FROMSTDOUT != -1)
+                       FD_SET(FROMSTDOUT, &rfds);
+
+               if (FROMSTDERR != -1)
+                       FD_SET(FROMSTDERR, &rfds);
+
+               tmp = TOSTDIN > FROMSTDOUT ? TOSTDIN : FROMSTDOUT;
+               tmp = tmp > FROMSTDERR ? tmp : FROMSTDERR;
+               tmp++;
+
+               debug("select r=%d,%d w=%d m=%d\n", FROMSTDOUT, FROMSTDERR, TOSTDIN, tmp);
+
+               tmp = select(tmp, &rfds, &wfds, NULL, NULL);
+               if (tmp < 0)
+                       error("select failed: %m\n");
+
+               if (TOSTDIN != -1 && FD_ISSET(TOSTDIN, &wfds)) {
+                       tmp = write(TOSTDIN, pc, ninfo);
+                       if (tmp < 0) {
+                               if (errno != EPIPE)
+                                       error("write failed: %m\n");
+
+                               debug("EPIPE");
+                               ninfo = 0;
+                       }
+                       else {
+                               debug("wrote %d\n", tmp);
+
+                               pc += tmp;
+                               ninfo -= tmp;
+                       }
+               }
+
+               if (FROMSTDOUT != -1 && FD_ISSET(FROMSTDOUT, &rfds)) {
+                       tmp = read(FROMSTDOUT, pp, npay);
+                       if (tmp < 0)
+                               error("read failed: %m\n");
+
+                       debug("read %d\n", tmp);
+
+                       if (tmp == 0) {
+                               close(FROMSTDOUT);
+                               FROMSTDOUT = -1;
+                       }
+                       else {
+                               pp += tmp;
+                               npay -= tmp;
+
+                               if (npay == 0)
+                                       error("Too much data read from query program\n");
+                       }
+               }
+
+               if (FROMSTDERR != -1 && FD_ISSET(FROMSTDERR, &rfds)) {
+                       char *nl;
+
+                       tmp = read(FROMSTDERR, pe, espace);
+                       if (tmp < 0)
+                               error("read failed: %m\n");
+
+                       debug("read err %d\n", tmp);
+
+                       if (tmp == 0) {
+                               close(FROMSTDERR);
+                               FROMSTDERR = -1;
+                               continue;
+                       }
+
+                       pe += tmp;
+                       espace -= tmp;
+
+                       while ((nl = memchr(errbuf, '\n', pe - errbuf))) {
+                               int n, rest;
+
+                               nl++;
+                               n = nl - errbuf;
+
+                               if (xdebug)
+                                       fprintf(stderr, "Child: %*.*s", n, n, errbuf);
+
+                               if (!xnolog) {
+                                       openlog("request-key", 0, LOG_AUTHPRIV);
+                                       syslog(LOG_ERR, "Child: %*.*s", n, n, errbuf);
+                                       closelog();
+                               }
+
+                               rest = pe - nl;
+                               if (rest > 0) {
+                                       memmove(errbuf, nl, rest);
+                                       pe -= n;
+                                       espace += n;
+                               }
+                               else {
+                                       pe = errbuf;
+                                       espace = sizeof(errbuf);
+                               }
+                       }
+
+                       if (espace == 0) {
+                               int n = sizeof(errbuf);
+
+                               if (xdebug)
+                                       fprintf(stderr, "Child: %*.*s", n, n, errbuf);
+
+                               if (!xnolog) {
+                                       openlog("request-key", 0, LOG_AUTHPRIV);
+                                       syslog(LOG_ERR, "Child: %*.*s", n, n, errbuf);
+                                       closelog();
+                               }
+
+                               pe = errbuf;
+                               espace = sizeof(errbuf);
+                       }
+               }
+
+       } while (TOSTDIN != -1 || FROMSTDOUT != -1 || FROMSTDERR != -1);
+
+       /* wait for the program to exit */
+       if (waitpid(childpid, &tmp, 0) != childpid)
+               error("wait for child failed: %m\n");
+
+       /* if the process exited non-zero or died on a signal, then we call back in to ourself to
+        * decide on negation
+        * - this is not exactly beautiful but the quickest way of having configurable negation
+        *   settings
+        */
+       if (WIFEXITED(tmp) && WEXITSTATUS(tmp) != 0) {
+               if (norecurse)
+                       error("child exited %d\n", WEXITSTATUS(tmp));
+
+               norecurse = 1;
+               debug("child exited %d\n", WEXITSTATUS(tmp));
+               lookup_action("negate", key, ktype, kdesc, callout_info);
+       }
+
+       if (WIFSIGNALED(tmp)) {
+               if (norecurse)
+                       error("child died on signal %d\n", WTERMSIG(tmp));
+
+               norecurse = 1;
+               debug("child died on signal %d\n", WTERMSIG(tmp));
+               lookup_action("negate", key, ktype, kdesc, callout_info);
+       }
+
+       /* attempt to instantiate the key */
+       debug("instantiate with %td bytes\n", pp - payload);
+
+       if (keyctl_instantiate(key, payload, pp - payload, 0) < 0)
+               error("instantiate key failed: %m\n");
+
+       debug("instantiation successful\n");
+       exit(0);
+
+} /* end pipe_to_program() */
diff --git a/request-key.conf b/request-key.conf
new file mode 100644 (file)
index 0000000..ff16a95
--- /dev/null
@@ -0,0 +1,41 @@
+###############################################################################
+#
+# Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
+# Written by David Howells (dhowells@redhat.com)
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version
+# 2 of the License, or (at your option) any later version.
+#
+###############################################################################
+
+
+###############################################################################
+#
+# We can run programs or scripts
+# - Macro substitutions in arguments:
+#      %%...   %...
+#      %o      operation name
+#      %k      ID of key being operated upon
+#      %t      type of key being operated upon
+#      %d      description of key being operated upon
+#      %c      callout info
+#      %u      UID of requestor
+#      %g      GID of requestor
+#      %T      thread keyring of requestor (may be 0)
+#      %P      process keyring of requestor (may be 0)
+#      %S      session keyring of requestor (may be the user's default session)
+#
+################################################################################
+
+#OP    TYPE    DESCRIPTION     CALLOUT INFO    PROGRAM ARG1 ARG2 ARG3 ...
+#======        ======= =============== =============== ===============================
+create  dns_resolver *         *               /sbin/key.dns_resolver %k
+create user    debug:*         negate          /bin/keyctl negate %k 30 %S
+create  user    debug:*         rejected        /bin/keyctl reject %k 30 %c %S
+create  user    debug:*         expired         /bin/keyctl reject %k 30 %c %S
+create  user    debug:*         revoked         /bin/keyctl reject %k 30 %c %S
+create user    debug:loop:*    *               |/bin/cat
+create user    debug:*         *               /usr/share/keyutils/request-key-debug.sh %k %d %c %S
+negate *       *               *               /bin/keyctl negate %k 30 %S
diff --git a/request-key.conf.5 b/request-key.conf.5
new file mode 100644 (file)
index 0000000..eb22c9e
--- /dev/null
@@ -0,0 +1,132 @@
+.\" -*- nroff -*-
+.\" Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
+.\" Written by David Howells (dhowells@redhat.com)
+.\"
+.\" This program is free software; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License
+.\" as published by the Free Software Foundation; either version
+.\" 2 of the License, or (at your option) any later version.
+.\"
+.TH REQUEST-KEY.CONF 5 "11 July 2005" Linux "Linux Key Management Utilities"
+.SH NAME
+request-key.conf - Instantiation handler configuration file
+.SH DESCRIPTION
+.P
+This file is used by the /sbin/request-key program to determine which program
+it should run to instantiate a key.
+.P
+request-key works scans through the file a line at a time until it finds a
+match, which it will then use. If it doesn't find a match, it'll return an
+error and the kernel will automatically negate the key.
+.P
+Any blank line or line beginning with a hash mark '#' is considered to be a
+comment and ignored.
+.P
+All other lines are assumed to be command lines with a number of white space
+separated fields:
+.P
+<op> <type> <description> <callout-info> <prog> <arg1> <arg2> ...
+.P
+The first four fields are used to match the parameters passed to request-key by
+the kernel. \fIop\fR is the operation type; currently the only supported
+operation is "create".
+.P
+\fItype\fR, \fIdescription\fR and \fIcallout-info\fR match the three parameters
+passed to \fBkeyctl request2\fR or the \fBrequest_key()\fR system call. Each of
+these may contain one or more asterisk '*' characters as wildcards anywhere
+within the string.
+.P
+Should a match be made, the program specified by <prog> will be exec'd. This
+must have a fully qualified path name. argv[0] will be set from the part of the
+program name that follows the last slash '/' character.
+.P
+If the program name is prefixed with a pipe bar character '|', then the program
+will be forked and exec'd attached to three pipes. The callout information will
+be piped to it on it's stdin and the intended payload data will be retrieved
+from its stdout. Anything sent to stderr will be posted in syslog. If the
+program exits 0, then /sbin/request-key will attempt to instantiate the key
+with the data read from stdout. If it fails in any other way, then request-key
+will attempt to execute the appropriate 'negate' operation command.
+.P
+The program arguments can be substituted with various macros. Only complete
+argument substitution is supported - macro substitutions can't be embedded. All
+macros begin with a percent character '%'. An argument beginning with two
+percent characters will have one of them discarded.
+.P
+The following macros are supported:
+.P
+.RS
+%o    Operation type
+.br
+%k    Key ID
+.br
+%t    Key type
+.br
+%d    Key description
+.br
+%c    Callout information
+.br
+%u    Key UID
+.br
+%g    Key GID
+.br
+%T    Requestor's thread keyring
+.br
+%P    Requestor's process keyring
+.br
+%S    Requestor's session keyring
+.RE
+.P
+There's another macro substitution too that permits the interpolation of the
+contents of a key:
+.P
+.RS
+%{<type>:<description>}
+.RE
+.P
+This performs a lookup for a key of the given type and description on the
+requestor's keyrings, and if found, substitutes the contents for the macro. If
+not found an error will be logged and the key under construction will be
+negated.
+.SH EXAMPLE
+.P
+A basic file will be installed in the /etc. This will contain two debugging
+lines that can be used to test the installation:
+.P
+.RS
+create user debug:* negate /bin/keyctl negate %k 30 %S
+.br
+create user debug:loop:* * |/bin/cat
+.br
+create user debug:* * /usr/share/keyutils/request-key-debug.sh %k %d %c %S
+.br
+negate * * * /bin/keyctl negate %k 30 %S
+.RE
+.P
+This is set up so that something like:
+.P
+.RS
+keyctl request2 user debug:xxxx negate
+.RE
+.P
+will create a negative user-defined key, something like:
+.P
+.RS
+keyctl request2 user debug:yyyy spoon
+.RE
+.P
+will create an instantiated user-defined key with "Debug spoon" as the payload,
+and something like:
+.P
+.RS
+keyctl request2 user debug:loop:zzzz abcdefghijkl
+.RE
+.P
+will create an instantiated user-defined key with the callout information as
+the payload.
+.SH FILES
+.ul
+/etc/request-key.conf
+.ul 0
+.SH SEE ALSO
+\fBkeyctl\fR(1), \fBrequest-key.conf\fR(5)
diff --git a/version.lds b/version.lds
new file mode 100644 (file)
index 0000000..5b89b47
--- /dev/null
@@ -0,0 +1,53 @@
+KEYUTILS_0.3 {
+
+       /* primary syscalls; may be overridden by glibc */
+       add_key;
+       request_key;
+       keyctl;
+
+       /* management functions */
+       keyctl_chown;
+       keyctl_clear;
+       keyctl_describe;
+       keyctl_describe_alloc;
+       keyctl_get_keyring_ID;
+       keyctl_instantiate;
+       keyctl_join_session_keyring;
+       keyctl_link;
+       keyctl_negate;
+       keyctl_read;
+       keyctl_read_alloc;
+       keyctl_revoke;
+       keyctl_search;
+       keyctl_setperm;
+       keyctl_set_reqkey_keyring;
+       keyctl_unlink;
+       keyctl_update;
+        
+};
+
+KEYUTILS_1.0 {
+       /* management functions */
+       keyctl_assume_authority;
+       keyctl_set_timeout;
+
+} KEYUTILS_0.3;
+
+KEYUTILS_1.3 {
+       /* management functions */
+       keyctl_get_security;
+       keyctl_get_security_alloc;
+       keyctl_session_to_parent;
+
+} KEYUTILS_1.0;
+
+KEYUTILS_1.4 {
+       /* management functions */
+       keyctl_reject;
+       keyctl_instantiate_iov;
+
+       /* utility functions */
+       recursive_key_scan;
+       recursive_session_key_scan;
+
+} KEYUTILS_1.3;