Import initial pam_krb5_migrate release (0.0.1). pam-krb5-migrate-0.0.1
authorJelmer Vernooij <jelmer@samba.org>
Mon, 13 Nov 2006 20:17:12 +0000 (21:17 +0100)
committerJelmer Vernooij <jelmer@samba.org>
Mon, 13 Nov 2006 20:17:12 +0000 (21:17 +0100)
COPYING [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
login.pam [new file with mode: 0644]
pam_krb5_migrate.c [new file with mode: 0644]
pam_krb5_migrate.h [new file with mode: 0644]

diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..a43ea21
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, 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/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..5a7cb81
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,77 @@
+BUILDING AND INSTALLATION
+
+There are two different ways to build pam_krb5_migrate.  The first mode
+generates a module which will update a Kerberos database on the local
+machine; the second mode generates a module which updates against a remote
+KDC using the Kerberos5 kadmin protocol.
+
+Ideally, I would like to combine both sets of functionality in a single
+binary; however, the client and server kadmin libraries export the same
+API, and ld doesn't like using two different functions of the same name.
+:)  If anybody knows of a good, portable way to do this, let me know.
+
+The default is to use the kadmin protocol to talk to the KDC remotely.  If
+you need the local option, edit the Makefile and uncomment the LIBS and
+KLOCAL lines near the top, commenting out the settings for the remote
+option.
+
+At a later date, you will be able to control this using a configure
+script.  Alternatively, if people think that it would be useful, I may
+have it build both types of module under different names.  This is an
+alpha release, and I'm always open to suggestion.
+
+After editing the makefile, run 'make all install' to build the module and
+install it in /lib/security/.
+
+
+SETTING UP THE PAM_KRB5_MIGRATE MODULE
+
+If you do not already have a KDC, you will need to set up a Kerberos
+database for your realm.  See the Kerberos V5 Installation Guide for
+details.
+
+If you will be updating against a live database from a machine other than
+the KDC, or if you intend to run the migration module on more than one
+machine at a time, you will need to use kadmin (or kadmin.local) to create
+a special Kerberos principal called pam_migrate/<hostname>, where
+<hostname> is the full domain name (FQDN) of the host where you're
+deploying the pam module.
+
+% kadmin.local
+Authenticating as principal admin/admin@REALM with password.
+kadmin.local:  addprinc -randkey pam_migrate/hostname@REALM
+WARNING: no policy specified for pam_migrate/hostname@REALM; defaulting to no policy
+Principal "pam_migrate/hostname@REALM" created.
+
+Then extract the key for this principal to a keytab for use on the host:
+
+kadmin.local:   ktadd -k /var/kerberos/krb5kdc/hostname.keytab pam/migrate/hostname
+Entry for principal pam_migrate/hostname with kvno 4, encryption type DES cbc mode with CRC-32 added to keytab
+WRFILE:/var/kerberos/krb5kdc/hostname.keytab.
+Entry for principal pam_migrate/hostname with kvno 4, encryption type Triple DES cbc mode raw added to keytab
+WRFILE:/var/kerberos/krb5kdc/hostname.keytab.
+
+
+This principal should *only* have permission to add principals to the
+database and should have no other permissions.  To give the principal
+permission to add to the database, add this line to the top of your
+kadm5.acl file:
+
+pam_migrate/hostname@REALM             a
+
+You can also give all principals of the form pam_migrate/<hostname>
+permission to add by using the line
+
+pam_migrate/*@REALM                    a
+
+You will then need to copy your new keytab (securely!) to the appropriate
+machine and install it as /etc/security/pam_krb5.keytab.  Like all
+keytabs, this file should be readable only by root and should be treated
+with the utmost care when transferring it to the destination host.
+*Anyone with access to this keytab will be able to create new Kerberos
+principals in your realm.*
+
+If you plan to add principals to a local database, you won't need to do
+any of the above.  So long as the pam module has access to write to the
+database (generally only if the calling application runs as root), you
+will be able to edit without authentication.
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..9095ac1
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,29 @@
+CC = gcc
+CFLAGS += -I/usr/kerberos/include
+LDFLAGS += -Bsymbolic -x -shared
+
+# Uncomment these lines to build the module with local db support.
+#KLOCAL = -DKADMIN_LOCAL
+#LIBS   = -lkadm5srv
+
+# Uncomment these lines to build the module with remote kadmin support.
+KLOCAL =
+LIBS   = -lkadm5clnt
+
+LIBS  += -lgssrpc -lgssapi_krb5 -lkdb5 -lkrb5 -lk5crypto
+LIBS  += -ldyn -lcom_err -lpam -ldl -lc
+
+all: pam_krb5_migrate.so
+
+pam_krb5_migrate.so: pam_krb5_migrate.o
+       $(LD) -Bsymbolic -x -shared -o pam_krb5_migrate.so \
+         pam_krb5_migrate.o -L/usr/kerberos/lib $(LIBS)
+
+pam_krb5_migrate.o: pam_krb5_migrate.c
+       $(CC) -o $@ -c $< $(KLOCAL) $(CFLAGS)
+
+install: all
+       install -m755 -o root pam_krb5_migrate.so /lib/security/
+
+clean:
+       -rm *.o *.so
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..ba2f44f
--- /dev/null
+++ b/README
@@ -0,0 +1,25 @@
+pam_krb5_migrate is a stackable authentication module that takes a username
+and password from an earlier module in the stack, and attempts to
+transparently add them to a Kerberos realm using the Kerberos 5 kadmin
+service.
+The module can be used to ease the administrative burdens of migrating a
+large installed userbase from pre-existing authentication methods to a
+Kerberos-based setup.
+
+The most current version of this module can always be found at
+ftp://ftp.netexpress.net/pub/pam/
+
+For sample usage in a module stack, see the enclosed login.pam file.
+
+The following options are recognized by the module:
+
+debug                 turn debug logging on
+keytab=<file>         use alternate keytab for authentication
+                         (default is /etc/security/pam_krb5.keytab)
+principal=<name>      use the key for <name> instead of the default
+                         pam_migrate/<hostname> key
+realm=<REALM>         update the database for a realm other than the
+                         default realm.
+
+Please send questions and comments (and especially bugfixes) to Steve
+Langasek <vorlon@netexpress.net>
diff --git a/login.pam b/login.pam
new file mode 100644 (file)
index 0000000..2a9d11d
--- /dev/null
+++ b/login.pam
@@ -0,0 +1,14 @@
+#%PAM-1.0
+# Sample login configuration file for Linux-PAM, using krb5_migrate
+# For equivalent Solaris config, put the service name at the beginning
+# of the line and add to /etc/pam.conf.
+auth       required         /lib/security/pam_securetty.so
+auth       required         /lib/security/pam_nologin.so
+auth       sufficient       /lib/security/pam_krb5.so
+auth       requisite        /lib/security/pam_unix.so
+auth       optional         /lib/security/pam_krb5_migrate.so
+account    required         /lib/security/pam_unix.so
+password   required         /lib/security/pam_cracklib.so
+password   required         /lib/security/pam_unix.so shadow nullok use_authtok
+password   optional         /lib/security/pam_krb5.so use_authtok use_first_pass
+session    required         /lib/security/pam_unix.so
diff --git a/pam_krb5_migrate.c b/pam_krb5_migrate.c
new file mode 100644 (file)
index 0000000..c99be1c
--- /dev/null
@@ -0,0 +1,466 @@
+/*
+   Kerberos 5 migration module
+   Version 0.0.1.
+   PAM authentication module to transparently add passwords to a Kerberos 5
+   database.
+
+   Copyright (C) Steve Langasek 2000
+
+   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.
+*/
+
+/*
+ * TODO:
+ * nullok, nonull options.  One may not want to add a principal
+ * to a kerberos db with a null password.
+ */
+
+/* indicate the following groups are defined */
+#define PAM_SM_AUTH
+
+#include "pam_krb5_migrate.h"
+
+#define DEFAULT_KEYTAB "/etc/security/pam_krb5.keytab"
+
+
+/* Cleanup function for pam data. */
+static void _cleanup(pam_handle_t * pamh, void *x, int error_status)
+{
+    if(x)
+        free(x);
+    x = NULL;
+}
+
+
+/* syslogging function for errors and other information */
+static void _log_err(int err, pam_handle_t *pamh, const char *format, ...)
+{
+    char *service = NULL;
+    char logname[1024];
+    va_list args;
+
+    pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
+    if (service) {
+        snprintf(logname, sizeof(logname) - 1, "%s(pam_krb5_migrate)",
+service);
+    } else {
+        snprintf(logname, sizeof(logname) - 1, "pam_krb5_migrate");
+    }
+
+    va_start(args, format);
+    openlog(logname, LOG_CONS | LOG_PID, LOG_AUTH);
+    vsyslog(err, format, args);
+    va_end(args);
+    closelog();
+}
+
+
+/*
+ * Safe duplication of character strings, leaving
+ * no evidence for later stack analysis.
+ */
+static char * _xstrdup(pam_handle_t *pamh, const char *x)
+{
+    register char *new = NULL;
+
+    if (x != NULL) {
+        register int i;
+
+        for (i = 0; x[i]; ++i); /* length of string */
+        if ((new = malloc(++i)) == NULL) {
+            i = 0;
+            _log_err(LOG_CRIT, pamh, "out of memory in _xstrdup");
+        } else {
+            while (i-- > 0) {
+                new[i] = x[i];
+            }
+        }
+        x = NULL;
+    }
+    return new;                 /* return the duplicate or NULL on error */
+}
+
+
+/* this is a front-end for module-application conversations */
+
+static int converse(pam_handle_t * pamh, int debug, int nargs,
+                     struct pam_message **message,
+                     struct pam_response **response)
+{
+    int retval;
+    struct pam_conv *conv;
+    retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv);
+    if (retval == PAM_SUCCESS) {
+        retval = conv->conv(nargs, (const struct pam_message **) message
+                            , response, conv->appdata_ptr);
+        if (retval != PAM_SUCCESS && debug) {
+            _log_err(LOG_DEBUG, pamh, "conversation failure [%s]",
+                     pam_strerror(pamh, retval));
+        }
+    } else {
+        _log_err(LOG_ERR, pamh,
+                 "couldn't obtain coversation function [%s]",
+                 pam_strerror(pamh, retval));
+    }
+    return retval;                             /* propagate error status */
+}
+
+
+static int make_remark(pam_handle_t * pamh, int debug,
+                        int type, const char *text)
+{
+    struct pam_message *pmsg[1], msg[1];
+    struct pam_response *resp;
+    pmsg[0] = &msg[0];
+    msg[0].msg = text;
+    msg[0].msg_style = type;
+    resp = NULL;
+    return converse(pamh, debug, 1, pmsg, &resp);
+    return PAM_SUCCESS;
+}
+
+
+/*
+ * pam_sm_authenticate() takes an authentication token and stores
+ * it to a Kerberos database using the kadmin API.
+ *
+ */
+int pam_sm_authenticate(pam_handle_t *pamh, int flags,
+                        int argc, const char **argv)
+{
+    int retval, *ret_data = NULL;
+
+    int debug = 0, quiet = flags & PAM_SILENT;
+    int local = 1, remote = 1;
+    char *def_realm = NULL;
+    char *cp;
+    char *name = NULL, *pass = NULL;
+    const char *lname = NULL;
+    char *princstr = NULL, *keytab_name = NULL;
+    kadm5_ret_t kret;
+    krb5_context context;
+    krb5_principal princ;
+    kadm5_principal_ent_rec newprinc;
+    kadm5_config_params params;
+    kadm5_policy_ent_rec defpol;
+    long mask = 0;
+    void *handle = NULL;
+
+
+    /* Get a few bytes so we can pass our return value to pam_sm_setcred(). */
+    ret_data = malloc(sizeof(int));
+
+    /* Initialize the params struct for kadmin. */
+    memset((char *) &params, 0, sizeof(params));
+
+    if (kret = krb5_init_context(&context)) {
+        _log_err(LOG_ERR, pamh, "%s while initializing krb5 library",
+                 error_message(kret));
+       retval = PAM_SYSTEM_ERR;
+        goto cleanup;
+    }
+
+    while (argc--) {
+        if (!strncmp(*argv, "debug", 5)) {
+            debug = 1;
+#ifndef KADMIN_LOCAL
+        } else if (!strncmp(*argv, "keytab=", 7)) {
+            keytab_name = _xstrdup(pamh, *argv+7);
+            if (keytab_name == NULL) {
+                retval = PAM_BUF_ERR;
+                goto cleanup;
+            }
+#else
+        } else if (!strncmp(*argv, "keytab=", 7)) {
+            _log_err(LOG_NOTICE, pamh,
+                     "module compiled with local database support,"
+                     "ignoring option %s",
+                     *argv);
+#endif
+        } else if (!strncmp(*argv, "principal=", 10)) {
+            princstr = _xstrdup(pamh, *argv+10);
+            if (princstr == NULL) {
+                retval = PAM_BUF_ERR;
+                goto cleanup;
+            }
+        } else if (!strncmp(*argv, "realm=", 6)) {
+            def_realm = _xstrdup(pamh, *argv+6);
+            if (def_realm == NULL) {
+                retval = PAM_BUF_ERR;
+                goto cleanup;
+            }
+        } else {
+            _log_err(LOG_ERR, pamh, "unrecognized option [%s]", *argv);
+            retval = PAM_SYSTEM_ERR;
+            goto cleanup;
+        }
+        ++argv;
+    }
+
+    /* Even if connected locally, we need a realm so we can properly build
+       principal names. */
+    if (def_realm == NULL && krb5_get_default_realm(context, &def_realm))
+    {
+        _log_err(LOG_ERR, pamh, "unable to get default realm");
+        if(!quiet) {
+            make_remark(pamh, debug, PAM_ERROR_MSG,
+                        "unable to get default Kerberos realm");
+        }
+        retval = PAM_SYSTEM_ERR;
+        goto cleanup;
+    }
+
+    params.mask |= KADM5_CONFIG_REALM;
+    params.realm = def_realm;
+
+
+    /*
+     * If no principal name is specified, the principal name is
+     * pam_migrate/hostname.
+     */
+
+    if (princstr == NULL) {
+        /* We want a principal using the service name (pam_migrate) and
+           the hostname. */
+        if (kret = krb5_sname_to_principal(context, NULL,
+                                           "pam_migrate", KRB5_NT_SRV_HST,
+                                           &princ))
+        {
+            _log_err(LOG_ERR, pamh, "%s creating host service principal",
+                     error_message(kret));
+             retval = PAM_SYSTEM_ERR;
+             goto cleanup;
+        }
+
+        /* Can we extract a string from the result? */
+        if (kret = krb5_unparse_name(context, princ, &princstr)) {
+            _log_err(LOG_ERR, pamh, "%s while canonicalizing principal name",
+                     error_message(kret));
+             krb5_free_principal(context, princ);
+             retval = PAM_SYSTEM_ERR;
+             goto cleanup;
+        }
+
+        /* Done with it either way */
+        krb5_free_principal(context, princ);
+    }
+
+    /*
+     * Initialize the kadm5 connection.  Either we're running in local
+     * mode, in which case anything goes; or we need a keytab.
+     */
+#ifndef KADMIN_LOCAL
+    /* Get default keytab if none was provided. */
+    if (!keytab_name) {
+        keytab_name = _xstrdup(pamh, "/etc/security/pam_krb5.keytab");
+        if (keytab_name == NULL) {
+            retval = PAM_BUF_ERR;
+            goto cleanup;
+        }
+    }
+
+    if (debug) {
+        _log_err(LOG_DEBUG, pamh,
+                 "Authenticating as principal %s with keytab %s.\n",
+                 princstr, keytab_name);
+    }
+#endif
+
+    kret = kadm5_init_with_skey(princstr, keytab_name,
+                                    KADM5_ADMIN_SERVICE,
+                                    &params,
+                                    KADM5_STRUCT_VERSION,
+                                    KADM5_API_VERSION_2,
+                                    &handle);
+    free(princstr);
+    princstr = NULL;
+
+    if (kret) {
+        _log_err(LOG_ERR, pamh, 
+                 "%s while initializing kadmin interface",
+                 error_message(kret));
+        retval = PAM_SYSTEM_ERR;
+        goto cleanup;
+    }
+
+
+    /* Everything is in order.  Get our username and our realm,
+       and add the principal. */
+
+    /* get the username */
+    retval = pam_get_user(pamh, &lname, "Username: ");
+    if (retval != PAM_SUCCESS) {
+        if (debug) {
+            _log_err(LOG_DEBUG, pamh, "could not identify user");
+        }
+        goto cleanup;
+    }
+    if (debug) {
+        _log_err(LOG_DEBUG, pamh, "username [%s] obtained", lname);
+    }
+
+    name = malloc(strlen(lname) + strlen(def_realm) + 2);
+    if (name == NULL) {
+        _log_err(LOG_CRIT, pamh, "no memory for principal name");
+        retval = PAM_BUF_ERR;
+        goto cleanup;
+    }
+
+    strncpy(name, lname, strlen(lname) + 1);
+
+    /* Make sure we're dealing with a valid username. */
+    if ((cp = strchr(name, '@'))) {
+        *cp = '\0';
+    }
+    if ((cp = strchr(name, '/'))) {
+        *cp = '\0';
+    }
+
+    /* Tack on the @REALM portion of the principal name. */
+    strncat(name, "@", 2);
+    strncat(name, def_realm, strlen(def_realm) + 1);
+
+    /* Get the authtok; if we don't have one, silently fail. */
+    retval = pam_get_item(pamh, PAM_AUTHTOK,
+                          (const void **)&pass);
+
+    if (retval != PAM_SUCCESS)
+    {
+       _log_err(LOG_ALERT, pamh,
+                "pam_get_item returned error to pam_sm_authenticate");
+       retval = PAM_AUTHTOK_RECOVER_ERR;
+        goto cleanup;
+    } else if (pass == NULL) {
+       retval = PAM_AUTHTOK_RECOVER_ERR;
+        goto cleanup;
+    }
+
+    /* Zero all fields in request structure */
+    memset(&newprinc, 0, sizeof(newprinc));
+    newprinc.attributes = 0;
+
+    kret = krb5_parse_name(context, name, &newprinc.principal);
+    if (kret) {
+        _log_err(LOG_ERR, pamh, "%s while setting up principal \"%s\"",
+                 error_message(kret), name);
+        krb5_free_principal(context, newprinc.principal);
+        retval = PAM_SYSTEM_ERR;
+        goto cleanup;
+    }
+
+    if (!kadm5_get_policy(handle, "default", &defpol)) {
+        if (debug) {
+            _log_err(LOG_DEBUG, pamh,
+                     "no policy specified for %s; assigning \"default\"",
+                     name);
+        }
+        newprinc.policy = "default";
+        mask |= KADM5_POLICY;
+        (void) kadm5_free_policy_ent(handle, &defpol);
+    } else {
+        if (debug) {
+            _log_err(LOG_DEBUG, pamh,
+                     "no policy specified for %s; defaulting to no policy",
+                     name);
+        }
+    }
+    mask &= ~KADM5_POLICY_CLR;
+
+    mask |= KADM5_PRINCIPAL;
+    kret = kadm5_create_principal(handle, &newprinc, mask, pass);
+
+    /* TODO: some errors are more noteworthy than others. */
+    if (kret && kret != KADM5_DUP) { // No need to log that the
+                                     // principal is already there.
+        if (!quiet)
+           make_remark(pamh, debug, PAM_ERROR_MSG, error_message(kret));
+        _log_err(LOG_NOTICE, pamh, "%s creating principal \"%s\"",
+                 error_message(kret), name);
+        krb5_free_principal(context, newprinc.principal);
+        retval = PAM_IGNORE;
+        goto cleanup;
+    } else if (kret && debug) {
+        _log_err(LOG_DEBUG, pamh, "principal %s already exists, continuing",
+                 name);
+    }
+
+    krb5_free_principal(context, newprinc.principal);
+    if (debug && !kret) {
+        _log_err(LOG_NOTICE, pamh, "Principal \"%s\" created", name);
+    }
+
+    /* return PAM_IGNORE, so that we don't
+       affect the authentication stack. */
+    retval = PAM_IGNORE;
+
+cleanup:
+
+    kadm5_destroy(&handle);
+    krb5_free_context(context);
+    if (princstr)
+        free(princstr);
+    if (def_realm)
+        free(def_realm);
+    if (keytab_name)
+        free(keytab_name);
+    if (name)
+        free(name);
+    if (ret_data) {
+        *ret_data = retval;
+        pam_set_data(pamh, "krb5_migrate_return",
+                     (void *) ret_data, _cleanup);
+    }
+    return retval;
+}
+
+/*
+ * pam_sm_setcred: stub function.  We have no credentials to set,
+ * so we just return a value to match pam_sm_authenticate.
+ */
+
+int pam_sm_setcred(pam_handle_t *pamh, int flags,
+                   int argc, const char **argv)
+{
+    int retval, *pretval = NULL;
+
+    retval = PAM_SUCCESS;
+
+    /* Retrieve the previous return value. */
+    pam_get_data(pamh, "krb5_migrate_return", (const void **) &pretval);
+
+    /* Copy the return value to local memory. */
+    if(pretval) {
+        retval = *pretval;
+    }
+
+    /* Trigger the cleanup function. */
+    pam_set_data(pamh, "krb5_migrate_return", NULL, NULL);
+
+    return retval;
+}
+
+
+/* static module data */
+#ifdef PAM_STATIC
+struct pam_module _pam_krb5_migrate_auth_modstruct = {
+     "pam_krb5_migrate",
+     pam_sm_authenticate,
+     pam_sm_setcred,
+     NULL,
+     NULL,
+     NULL,
+     NULL
+};
+#endif
diff --git a/pam_krb5_migrate.h b/pam_krb5_migrate.h
new file mode 100644 (file)
index 0000000..a6a0113
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+   Kerberos 5 migration module
+   Version 0.0.1.
+   PAM authentication module to transparently add passwords to a Kerberos 5
+   database.
+
+   Copyright (C) Steve Langasek 2000
+
+   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.
+*/
+
+#ifndef _PAM_KRB5_MIGRATE_H
+#define _PAM_KRB5_MIGRATE_H
+
+#include <stdio.h>
+#include <string.h>
+#include <krb5.h>
+#include <kadm5/admin.h>
+
+#ifndef LINUX
+
+/* This is only used in the Sun implementation. */
+#include <security/pam_appl.h>
+
+#endif  /* LINUX */
+
+#include <security/pam_modules.h>
+
+#ifndef False
+#define False (0)
+#endif
+
+#ifndef True
+#define True (1)
+#endif
+
+
+#endif /* _PAM_KRB5_MIGRATE_H */