summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorcvs2svn <cvs2svn@FreeBSD.org>2001-05-20 23:12:14 +0000
committercvs2svn <cvs2svn@FreeBSD.org>2001-05-20 23:12:14 +0000
commita2a591a7dd99355b9b940cc797be071bdb19a86b (patch)
tree411c5c7d58fd94211c4c3ec10232e5d4d3eb0bc1 /lib
parentfd24c73a2c496aaf5c7e251e75dbc5d17fcd2514 (diff)
Notes
Diffstat (limited to 'lib')
-rw-r--r--lib/libc/gen/getprogname.392
-rw-r--r--lib/libc/gen/getprogname.c13
-rw-r--r--lib/libc/gen/setprogname.c13
-rw-r--r--lib/libc/stdlib/hcreate.c184
-rw-r--r--lib/libc/string/wmemchr.3145
-rw-r--r--lib/libc_r/test/join_leak_d.c108
-rw-r--r--lib/libc_r/test/join_leak_d.exp2
-rw-r--r--lib/libpam/modules/pam_krb5/COPYRIGHT195
-rw-r--r--lib/libpam/modules/pam_krb5/README72
-rw-r--r--lib/libpam/modules/pam_krb5/TODO16
-rw-r--r--lib/libpam/modules/pam_krb5/compat_heimdal.c141
-rw-r--r--lib/libpam/modules/pam_krb5/pam_krb5.8191
-rw-r--r--lib/libpam/modules/pam_krb5/pam_krb5.h23
-rw-r--r--lib/libpam/modules/pam_krb5/pam_krb5_acct.c83
-rw-r--r--lib/libpam/modules/pam_krb5/pam_krb5_auth.c505
-rw-r--r--lib/libpam/modules/pam_krb5/pam_krb5_pass.c200
-rw-r--r--lib/libpam/modules/pam_krb5/pam_krb5_sess.c28
-rw-r--r--lib/libpam/modules/pam_krb5/support.c185
18 files changed, 2196 insertions, 0 deletions
diff --git a/lib/libc/gen/getprogname.3 b/lib/libc/gen/getprogname.3
new file mode 100644
index 000000000000..74225956f5d7
--- /dev/null
+++ b/lib/libc/gen/getprogname.3
@@ -0,0 +1,92 @@
+.\"
+.\" Copyright (c) 2001 Christopher G. Demetriou
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed for the
+.\" NetBSD Project. See http://www.netbsd.org/ for
+.\" information about NetBSD.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 1, 2001
+.Dt GETPROGNAME 3
+.Os
+.Sh NAME
+.Nm getprogname ,
+.Nm setprogname
+.Nd get or set the program name
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.Fd #include <stdlib.h>
+.Ft const char *
+.Fn getprogname "void"
+.Ft void
+.Fn setprogname "const char *progname"
+.Sh DESCRIPTION
+The
+.Fn getprogname
+and
+.Fn setprogname
+functions manipulate the name of the current program.
+They are used by error-reporting routines to produce
+consistent output.
+.Pp
+The
+.Fn getprogname
+function returns the name of the program.
+If the name has not been set yet, it will return
+.Dv NULL .
+.Pp
+The
+.Fn setprogname
+function sets the name of the program.
+Since a pointer to the given string is kept as the program name,
+it should not be modified for the rest of the program's lifetime.
+.Pp
+In
+.Fx ,
+the name of the program is set by the start-up code that is run before
+.Fn main ;
+thus,
+running
+.Fn setprogname
+is not necessary.
+Programs that desire maximum portability should still call it;
+on another operating system,
+these functions may be implemented in a portability library.
+Calling
+.Fn setprogname
+allows the aforementioned library to learn the program name without
+modifications to the start-up code.
+.Sh SEE ALSO
+.Xr err 3 ,
+.Xr setproctitle 3
+.Sh HISTORY
+These functions first appeared in
+.Nx 1.6 ,
+and made their way into
+.Fx 5.0 .
diff --git a/lib/libc/gen/getprogname.c b/lib/libc/gen/getprogname.c
new file mode 100644
index 000000000000..54f721ab665c
--- /dev/null
+++ b/lib/libc/gen/getprogname.c
@@ -0,0 +1,13 @@
+#if defined(LIBC_RCS) && !defined(lint)
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* LIBC_RCS and not lint */
+
+extern const char *__progname;
+
+const char *
+getprogname(void)
+{
+
+ return (__progname);
+}
diff --git a/lib/libc/gen/setprogname.c b/lib/libc/gen/setprogname.c
new file mode 100644
index 000000000000..6c56013ef7c4
--- /dev/null
+++ b/lib/libc/gen/setprogname.c
@@ -0,0 +1,13 @@
+#if defined(LIBC_RCS) && !defined(lint)
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* LIBC_RCS and not lint */
+
+extern const char *__progname;
+
+void
+setprogname(const char *progname)
+{
+
+ __progname = progname;
+}
diff --git a/lib/libc/stdlib/hcreate.c b/lib/libc/stdlib/hcreate.c
new file mode 100644
index 000000000000..ecc24310ae4b
--- /dev/null
+++ b/lib/libc/stdlib/hcreate.c
@@ -0,0 +1,184 @@
+/* $NetBSD: hcreate.c,v 1.2 2001/02/19 21:26:04 ross Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Copyright (c) 2001 Christopher G. Demetriou
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the
+ * NetBSD Project. See http://www.netbsd.org/ for
+ * information about NetBSD.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * <<Id: LICENSE,v 1.2 2000/06/14 15:57:33 cgd Exp>>
+ */
+
+/*
+ * hcreate() / hsearch() / hdestroy()
+ *
+ * SysV/XPG4 hash table functions.
+ *
+ * Implementation done based on NetBSD manual page and Solaris manual page,
+ * plus my own personal experience about how they're supposed to work.
+ *
+ * I tried to look at Knuth (as cited by the Solaris manual page), but
+ * nobody had a copy in the office, so...
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: hcreate.c,v 1.2 2001/02/19 21:26:04 ross Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <errno.h>
+#include <search.h>
+#include <stdlib.h>
+#include <string.h>
+#include "namespace.h"
+
+/*
+ * DO NOT MAKE THIS STRUCTURE LARGER THAN 32 BYTES (4 ptrs on 64-bit
+ * ptr machine) without adjusting MAX_BUCKETS_LG2 below.
+ */
+struct internal_entry {
+ SLIST_ENTRY(internal_entry) link;
+ ENTRY ent;
+};
+SLIST_HEAD(internal_head, internal_entry);
+
+#define MIN_BUCKETS_LG2 4
+#define MIN_BUCKETS (1 << MIN_BUCKETS_LG2)
+
+/*
+ * max * sizeof internal_entry must fit into size_t.
+ * assumes internal_entry is <= 32 (2^5) bytes.
+ */
+#define MAX_BUCKETS_LG2 (sizeof (size_t) * 8 - 1 - 5)
+#define MAX_BUCKETS ((size_t)1 << MAX_BUCKETS_LG2)
+
+/* Default hash function, from db/hash/hash_func.c */
+extern u_int32_t (*__default_hash)(const void *, size_t);
+
+static struct internal_head *htable;
+static size_t htablesize;
+
+int
+hcreate(size_t nel)
+{
+ size_t idx;
+ unsigned int p2;
+
+ /* Make sure this this isn't called when a table already exists. */
+ if (htable != NULL) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ /* If nel is too small, make it min sized. */
+ if (nel < MIN_BUCKETS)
+ nel = MIN_BUCKETS;
+
+ /* If it's too large, cap it. */
+ if (nel > MAX_BUCKETS)
+ nel = MAX_BUCKETS;
+
+ /* If it's is not a power of two in size, round up. */
+ if ((nel & (nel - 1)) != 0) {
+ for (p2 = 0; nel != 0; p2++)
+ nel >>= 1;
+ nel = 1 << p2;
+ }
+
+ /* Allocate the table. */
+ htablesize = nel;
+ htable = malloc(htablesize * sizeof htable[0]);
+ if (htable == NULL) {
+ errno = ENOMEM;
+ return 0;
+ }
+
+ /* Initialize it. */
+ for (idx = 0; idx < htablesize; idx++)
+ SLIST_INIT(&htable[idx]);
+
+ return 1;
+}
+
+void
+hdestroy(void)
+{
+ struct internal_entry *ie;
+ size_t idx;
+
+ if (htable == NULL)
+ return;
+
+ for (idx = 0; idx < htablesize; idx++) {
+ while (!SLIST_EMPTY(&htable[idx])) {
+ ie = SLIST_FIRST(&htable[idx]);
+ SLIST_REMOVE_HEAD(&htable[idx], link);
+ free(ie->ent.key);
+ free(ie);
+ }
+ }
+ free(htable);
+ htable = NULL;
+}
+
+ENTRY *
+hsearch(ENTRY item, ACTION action)
+{
+ struct internal_head *head;
+ struct internal_entry *ie;
+ uint32_t hashval;
+ size_t len;
+
+ len = strlen(item.key);
+ hashval = (*__default_hash)(item.key, len);
+
+ head = &htable[hashval & (htablesize - 1)];
+ ie = SLIST_FIRST(head);
+ while (ie != NULL) {
+ if (strcmp(ie->ent.key, item.key) == 0)
+ break;
+ ie = SLIST_NEXT(ie, link);
+ }
+
+ if (ie != NULL)
+ return &ie->ent;
+ else if (action == FIND)
+ return NULL;
+
+ ie = malloc(sizeof *ie);
+ if (ie == NULL)
+ return NULL;
+ ie->ent.key = item.key;
+ ie->ent.data = item.data;
+
+ SLIST_INSERT_HEAD(head, ie, link);
+ return &ie->ent;
+}
diff --git a/lib/libc/string/wmemchr.3 b/lib/libc/string/wmemchr.3
new file mode 100644
index 000000000000..ff82e73a3564
--- /dev/null
+++ b/lib/libc/string/wmemchr.3
@@ -0,0 +1,145 @@
+.\" $NetBSD: wmemchr.3,v 1.4 2001/01/02 11:26:23 itojun Exp $
+.\"
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Chris Torek and the American National Standards Committee X3,
+.\" on Information Processing Systems.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)strcpy.3 8.1 (Berkeley) 6/4/93
+.\"
+.\" $FreeBSD$
+.\"
+.Dd December 22, 2000
+.Dt WMEMCHR 3
+.Os
+.Sh NAME
+.Nm wmemchr ,
+.Nm wmemcmp ,
+.Nm wmemcpy ,
+.Nm wmemmove ,
+.Nm wmemset ,
+.Nm wcscat ,
+.Nm wcschr ,
+.Nm wcscmp ,
+.Nm wcscpy ,
+.Nm wcscspn ,
+.Nm wcslcat ,
+.Nm wcslcpy ,
+.Nm wcslen ,
+.Nm wcsncat ,
+.Nm wcsncmp ,
+.Nm wcsncpy ,
+.Nm wcspbrk ,
+.Nm wcsrchr ,
+.Nm wcsspn ,
+.Nm wcsstr
+.Nd wide character string manipulation operations
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.Fd #include <wchar.h>
+.Ft wchar_t *
+.Fn wmemchr "const wchar_t *s" "wchar_t c" "size_t n"
+.Ft int
+.Fn wmemcmp "const wchar_t *s1" "const wchar_t *s2" "size_t n"
+.Ft wchar_t *
+.Fn wmemcpy "wchar_t * restrict s1" "const wchar_t * restrict s2" "size_t n"
+.Ft wchar_t *
+.Fn wmemmove "wchar_t *s1" "const wchar_t *s2" "size_t n"
+.Ft wchar_t *
+.Fn wmemset "wchar_t *s" "wchar_t c" "size_t n"
+.Ft wchar_t *
+.Fn wcscat "wchar_t * restrict s1" "const wchar_t * restrict s2"
+.Ft wchar_t *
+.Fn wcschr "const wchar_t *s" "wchar_t c"
+.Ft int
+.Fn wcscmp "const wchar_t *s1" "const wchar_t *s2"
+.Ft wchar_t *
+.Fn wcscpy "wchar_t * restrict s1" "const wchar_t * restrict s2"
+.Ft size_t
+.Fn wcscspn "const wchar_t *s1" "const wchar_t *s2"
+.Ft size_t
+.Fn wcslcat "wchar_t *s1" "const wchar_t *s2" "size_t n"
+.Ft size_t
+.Fn wcslcpy "wchar_t *s1" "const wchar_t *s2" "size_t n"
+.Ft size_t
+.Fn wcslen "const wchar_t *s"
+.Ft wchar_t *
+.Fn wcsncat "wchar_t * restrict s1" "const wchar_t * restrict s2" "size_t n"
+.Ft int
+.Fn wcsncmp "const wchar_t *s1" "const wchar_t * s2" "size_t n"
+.Ft wchar_t *
+.Fn wcsncpy "wchar_t * restrict s1" "const wchar_t * restrict s2" "size_t n"
+.Ft wchar_t *
+.Fn wcspbrk "const wchar_t *s1" "const wchar_t *s2"
+.Ft wchar_t *
+.Fn wcsrchr "const wchar_t *s" "wchar_t c"
+.Ft size_t
+.Fn wcsspn "const wchar_t *s1" "const wchar_t *s2"
+.Ft wchar_t *
+.Fn wcsstr "const wchar_t *s1" "const wchar_t *s2"
+.Sh DESCRIPTION
+The functions implement string manipulation operations over wide character
+strings.
+For a detailed description, refer to documents for the respective single-byte
+counterpart, such as
+.Xr memchr 3 .
+.Sh SEE ALSO
+.Xr memchr 3 ,
+.Xr memcmp 3 ,
+.Xr memcpy 3 ,
+.Xr memmove 3 ,
+.Xr memset 3 ,
+.Xr strcat 3 ,
+.Xr strchr 3 ,
+.Xr strcmp 3 ,
+.Xr strcpy 3 ,
+.Xr strcspn 3 ,
+.Xr strlcat 3 ,
+.Xr strlcpy 3 ,
+.Xr strlen 3 ,
+.Xr strncat 3 ,
+.Xr strncmp 3 ,
+.Xr strncpy 3 ,
+.Xr strpbrk 3 ,
+.Xr strrchr 3 ,
+.Xr strspn 3 ,
+.Xr strstr 3
+.Sh STANDARDS
+These functions conform to
+.St -isoC-99 ,
+with the exception of
+.Fn wcslcat
+and
+.Fn wcslcpy ,
+which are extensions.
diff --git a/lib/libc_r/test/join_leak_d.c b/lib/libc_r/test/join_leak_d.c
new file mode 100644
index 000000000000..6532ca5bfc74
--- /dev/null
+++ b/lib/libc_r/test/join_leak_d.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2001 Jason Evans <jasone@freebsd.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ *
+ * Test for leaked joined threads.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+
+#define NITERATIONS 16384
+#define MAXGROWTH 16384
+
+void *
+thread_entry(void *a_arg)
+{
+ return NULL;
+}
+
+int
+main(void)
+{
+ pthread_t thread;
+ int i, error;
+ char *brk, *nbrk;
+ unsigned growth;
+
+ fprintf(stderr, "Test begin\n");
+
+ /* Get an initial brk value. */
+ brk = sbrk(0);
+
+ /* Create threads and join them, one at a time. */
+ for (i = 0; i < NITERATIONS; i++) {
+ if ((error = pthread_create(&thread, NULL, thread_entry, NULL))
+ != 0) {
+ fprintf(stderr, "Error in pthread_create(): %s\n",
+ strerror(error));
+ exit(1);
+ }
+ if ((error = pthread_join(thread, NULL)) != 0) {
+ fprintf(stderr, "Error in pthread_join(): %s\n",
+ strerror(error));
+ exit(1);
+ }
+ }
+
+ /* Get a final brk value. */
+ nbrk = sbrk(0);
+
+ /*
+ * Check that the amount of heap space allocated is below an acceptable
+ * threshold. We could just compare brk and nbrk, but the test could
+ * conceivably break if the internals of the threads library changes.
+ */
+ if (nbrk > brk) {
+ /* Heap grows up. */
+ growth = nbrk - brk;
+ } else if (nbrk <= brk) {
+ /* Heap grows down, or no growth. */
+ growth = brk - nbrk;
+ }
+
+ if (growth > MAXGROWTH) {
+ fprintf(stderr, "Heap growth exceeded maximum (%u > %u)\n",
+ growth, MAXGROWTH);
+ }
+#if (0)
+ else {
+ fprintf(stderr, "Heap growth acceptable (%u <= %u)\n",
+ growth, MAXGROWTH);
+ }
+#endif
+
+ fprintf(stderr, "Test end\n");
+ return 0;
+}
diff --git a/lib/libc_r/test/join_leak_d.exp b/lib/libc_r/test/join_leak_d.exp
new file mode 100644
index 000000000000..369a88dd2404
--- /dev/null
+++ b/lib/libc_r/test/join_leak_d.exp
@@ -0,0 +1,2 @@
+Test begin
+Test end
diff --git a/lib/libpam/modules/pam_krb5/COPYRIGHT b/lib/libpam/modules/pam_krb5/COPYRIGHT
new file mode 100644
index 000000000000..42fb642c7230
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/COPYRIGHT
@@ -0,0 +1,195 @@
+pam_krb5:
+
+$FreeBSD$
+
+Copyright (c) Frank Cusack, 1999-2000.
+fcusack@fcusack.com
+All rights reserved
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, and the entire permission notice in its entirety,
+ including the disclaimer of warranties.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ALTERNATIVELY, this product may be distributed under the terms of
+the GNU Public License, in which case the provisions of the GPL are
+required INSTEAD OF the above restrictions. (This clause is
+necessary due to a potential bad interaction between the GPL and
+the restrictions contained in a BSD-style copyright.)
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+---------------------------------------------------------------------------
+
+This software may contain code from Naomaru Itoi:
+
+PAM-kerberos5 module Copyright notice.
+Naomaru Itoi <itoi@eecs.umich.edu>, June 24, 1997.
+
+----------------------------------------------------------------------------
+COPYRIGHT (c) 1997
+THE REGENTS OF THE UNIVERSITY OF MICHIGAN
+ALL RIGHTS RESERVED
+
+PERMISSION IS GRANTED TO USE, COPY, CREATE DERIVATIVE WORKS AND REDISTRIBUTE
+THIS SOFTWARE AND SUCH DERIVATIVE WORKS FOR ANY PURPOSE, SO LONG AS THE NAME
+OF THE UNIVERSITY OF MICHIGAN IS NOT USED IN ANY ADVERTISING OR PUBLICITY
+PERTAINING TO THE USE OR DISTRIBUTION OF THIS SOFTWARE WITHOUT SPECIFIC,
+WRITTEN PRIOR AUTHORIZATION. IF THE ABOVE COPYRIGHT NOTICE OR ANY OTHER
+IDENTIFICATION OF THE UNIVERSITY OF MICHIGAN IS INCLUDED IN ANY COPY OF ANY
+PORTION OF THIS SOFTWARE, THEN THE DISCLAIMER BELOW MUST ALSO BE INCLUDED.
+
+THE SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE UNIVERSITY OF
+MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND WITHOUT WARRANTY BY THE
+UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
+WITHOUT LIMITATION THE IMPLIED WARRANTIES OF MERCHANTABITILY AND FITNESS FOR A
+PARTICULAR PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE
+LIABLE FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
+CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING OUT OF OR IN
+CONNECTION WITH THE USE OF THE SOFTWARE, EVEN IF IT HAS BEEN OR IS HEREAFTER
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+PAM-kerberos5 module is written based on PAM-kerberos4 module
+by Derrick J. Brashear and kerberos5-1.0pl1 by M.I.T. kerberos team.
+Permission to use, copy, modify, distribute this software is hereby
+granted, as long as it is granted by Derrick J. Brashear and
+M.I.T. kerberos team. Followings are their copyright information.
+----------------------------------------------------------------------------
+
+This software may contain code from Derrick J. Brashear:
+
+
+Copyright (c) Derrick J. Brashear, 1996. All rights reserved
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, and the entire permission notice in its entirety,
+ including the disclaimer of warranties.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ALTERNATIVELY, this product may be distributed under the terms of
+the GNU Public License, in which case the provisions of the GPL are
+required INSTEAD OF the above restrictions. (This clause is
+necessary due to a potential bad interaction between the GPL and
+the restrictions contained in a BSD-style copyright.)
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------------
+
+This software may contain code from MIT Kerberos 5:
+
+Copyright Notice and Legal Administrivia
+----------------------------------------
+
+Copyright (C) 1996 by the Massachusetts Institute of Technology.
+
+All rights reserved.
+
+Export of this software from the United States of America may require
+a specific license from the United States Government. It is the
+responsibility of any person or organization contemplating export to
+obtain such a license before exporting.
+
+WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+distribute this software and its documentation for any purpose and
+without fee is hereby granted, provided that the above copyright
+notice appear in all copies and that both that copyright notice and
+this permission notice appear in supporting documentation, and that
+the name of M.I.T. not be used in advertising or publicity pertaining
+to distribution of the software without specific, written prior
+permission. M.I.T. makes no representations about the suitability of
+this software for any purpose. It is provided "as is" without express
+or implied warranty.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+Individual source code files are copyright MIT, Cygnus Support,
+OpenVision, Oracle, Sun Soft, and others.
+
+Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira,
+and Zephyr are trademarks of the Massachusetts Institute of Technology
+(MIT). No commercial use of these trademarks may be made without
+prior written permission of MIT.
+
+"Commercial use" means use of a name in a product or other for-profit
+manner. It does NOT prevent a commercial firm from referring to the
+MIT trademarks in order to convey information (although in doing so,
+recognition of their trademark status should be given).
+
+The following copyright and permission notice applies to the
+OpenVision Kerberos Administration system located in kadmin/create,
+kadmin/dbutil, kadmin/passwd, kadmin/server, lib/kadm5, and portions
+of lib/rpc:
+
+ Copyright, OpenVision Technologies, Inc., 1996, All Rights Reserved
+
+ WARNING: Retrieving the OpenVision Kerberos Administration system
+ source code, as described below, indicates your acceptance of the
+ following terms. If you do not agree to the following terms, do not
+ retrieve the OpenVision Kerberos administration system.
+
+ You may freely use and distribute the Source Code and Object Code
+ compiled from it, with or without modification, but this Source
+ Code is provided to you "AS IS" EXCLUSIVE OF ANY WARRANTY,
+ INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY OR
+ FITNESS FOR A PARTICULAR PURPOSE, OR ANY OTHER WARRANTY, WHETHER
+ EXPRESS OR IMPLIED. IN NO EVENT WILL OPENVISION HAVE ANY LIABILITY
+ FOR ANY LOST PROFITS, LOSS OF DATA OR COSTS OF PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES, OR FOR ANY SPECIAL, INDIRECT, OR
+ CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, INCLUDING,
+ WITHOUT LIMITATION, THOSE RESULTING FROM THE USE OF THE SOURCE
+ CODE, OR THE FAILURE OF THE SOURCE CODE TO PERFORM, OR FOR ANY
+ OTHER REASON.
+
+ OpenVision retains all copyrights in the donated Source Code. OpenVision
+ also retains copyright to derivative works of the Source Code, whether
+ created by OpenVision or by a third party. The OpenVision copyright
+ notice must be preserved if derivative works are made based on the
+ donated Source Code.
+
+ OpenVision Technologies, Inc. has donated this Kerberos
+ Administration system to MIT for inclusion in the standard
+ Kerberos 5 distribution. This donation underscores our
+ commitment to continuing Kerberos technology development
+ and our gratitude for the valuable work which has been
+ performed by MIT and the Kerberos community.
+
+
diff --git a/lib/libpam/modules/pam_krb5/README b/lib/libpam/modules/pam_krb5/README
new file mode 100644
index 000000000000..ee97421bfa9d
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/README
@@ -0,0 +1,72 @@
+$FreeBSD$
+
+This is the README for pam_krb5, a PAM module which support Kerberos 5
+authentication.
+
+This software is Copyright (c) 1999-2000 Frank Cusack.
+All Rights Reserved.
+
+See the COPYRIGHT file, included with this distribution, for copyright
+and redistribution information.
+
+Author:
+Frank Cusack
+<fcusack@fcusack.com>
+
+
+I. Kerberos notes
+
+This PAM module requires the MIT 1.1+ release of Kerberos, or the Cygnus
+CNS distribution. It has not been tested against heimdal or any other
+Kerberos distributions.
+
+Unlike other PAM Kerberos 5 modules out there, this one does not
+use any private Kerberos interfaces. Thus, you need only the
+header files and libraries that are part of the Kerberos distribution.
+
+
+II. OS notes
+
+This software has been tested against Solaris 2.6. It should compile
+against Linux (distributions?) with minimal (if any) changes. Reports
+of OS [in]compatibilities are welcomed.
+
+dtlogin on Solaris doesn't support xrealm logins (probably a good thing).
+
+III. PAM notes/open issues
+
+auth module:
+When is pam_sm_setcred() ever called with flags other than PAM_ESTABLISH_CRED
+or PAM_DELETE_CRED?
+
+acct module:
+I believe this to be complete.
+
+session module:
+This is complete (both functions just return success).
+
+passwd module:
+When is pam_sm_chauthtok() ever called with flags other than
+PAM_UPDATE_AUTHTOK?
+
+
+IV. Usage
+
+Simply change /etc/pam.conf to include this module. Make sure to include
+the acct category whenever you use the auth category, or .k5login will
+not get checked.
+
+You probably want to make this module "sufficient", before your unix
+(or other) module(s).
+
+
+V. Acknowledgements
+
+Thanks to Naomaru Itoi <itoi@eecs.umich.edu>,
+Curtis King <curtis.king@cul.ca>, and Derrick Brashear <shadow@dementia.org>,
+all of whom have written and made available Kerberos 4/5 modules.
+Although no code in this module is directly from these author's modules,
+(except the get_user_info() routine in support.c; derived from whichever
+of these authors originally wrote the first module the other 2 copied from),
+it was extremely helpful to look over their code which aided in my design.
+
diff --git a/lib/libpam/modules/pam_krb5/TODO b/lib/libpam/modules/pam_krb5/TODO
new file mode 100644
index 000000000000..1f0939f256c8
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/TODO
@@ -0,0 +1,16 @@
+$FreeBSD$
+
+Things for 1.1, in no particular order:
+
+Check against Solaris 7, Solaris 8 beta. Check SEAM compatibility.
+Check against Linux (Redhat, others?).
+Check against HPUX.
+Fix PAM flags checking.
+Add more debugging for successful calls.
+Move "entry" debugging up.
+Check bounds on str* calls. [paranoia]
+
+Get defaults from krb5.conf?
+** Allow no-xrealm, this module typically used for local login **
+** Add notes about runtime text relocation on Solaris **
+
diff --git a/lib/libpam/modules/pam_krb5/compat_heimdal.c b/lib/libpam/modules/pam_krb5/compat_heimdal.c
new file mode 100644
index 000000000000..fb4e1025e6ef
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/compat_heimdal.c
@@ -0,0 +1,141 @@
+/*
+ * compat_heimdal.c
+ *
+ * Heimdal compatability layer.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <krb5.h>
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include "pam_krb5.h"
+
+const char *
+compat_princ_component(krb5_context context, krb5_principal princ, int n)
+{
+ return princ->name.name_string.val[n];
+}
+
+void
+compat_free_data_contents(krb5_context context, krb5_data *data)
+{
+ krb5_xfree(data->data);
+}
+
+krb5_error_code
+compat_cc_next_cred(krb5_context context, const krb5_ccache id,
+ krb5_cc_cursor *cursor, krb5_creds *creds)
+{
+ return krb5_cc_next_cred(context, id, creds, cursor);
+}
+
+
+static krb5_error_code
+heimdal_pam_prompter(krb5_context context, void *data, const char *banner, int
+ num_prompts, krb5_prompt prompts[])
+{
+ int pam_prompts = num_prompts;
+ int pamret, i;
+
+ struct pam_message *msg;
+ struct pam_response *resp = NULL;
+ struct pam_conv *conv;
+ pam_handle_t *pamh = (pam_handle_t *) data;
+
+ if ((pamret = pam_get_item(pamh, PAM_CONV, (const void **) &conv)) != 0)
+ return KRB5KRB_ERR_GENERIC;
+
+ if (banner)
+ pam_prompts++;
+
+ msg = calloc(sizeof(struct pam_message) * pam_prompts, 1);
+ if (!msg)
+ return ENOMEM;
+
+ /* Now use pam_prompts as an index */
+ pam_prompts = 0;
+
+ if (banner) {
+ msg[pam_prompts].msg = malloc(strlen(banner) + 1);
+ if (!msg[pam_prompts].msg)
+ goto cleanup;
+ strcpy((char *) msg[pam_prompts].msg, banner);
+ msg[pam_prompts].msg_style = PAM_TEXT_INFO;
+ pam_prompts++;
+ }
+
+ for (i = 0; i < num_prompts; i++) {
+ msg[pam_prompts].msg = malloc(strlen(prompts[i].prompt) + 3);
+ if (!msg[pam_prompts].msg)
+ goto cleanup;
+ sprintf((char *) msg[pam_prompts].msg, "%s: ", prompts[i].prompt);
+ msg[pam_prompts].msg_style = prompts[i].hidden ? PAM_PROMPT_ECHO_OFF
+ : PAM_PROMPT_ECHO_ON;
+ pam_prompts++;
+ }
+
+ if ((pamret = conv->conv(pam_prompts, (const struct pam_message **) &msg,
+ &resp, conv->appdata_ptr)) != 0)
+ goto cleanup;
+
+ if (!resp)
+ goto cleanup;
+
+ /* Reuse pam_prompts as a starting index */
+ pam_prompts = 0;
+ if (banner)
+ pam_prompts++;
+
+ for (i = 0; i < num_prompts; i++, pam_prompts++) {
+ register int len;
+ if (!resp[pam_prompts].resp) {
+ pamret = PAM_AUTH_ERR;
+ goto cleanup;
+ }
+ len = strlen(resp[pam_prompts].resp); /* Help out the compiler */
+ if (len > prompts[i].reply->length) {
+ pamret = PAM_AUTH_ERR;
+ goto cleanup;
+ }
+ memcpy(prompts[i].reply->data, resp[pam_prompts].resp, len);
+ prompts[i].reply->length = len;
+ }
+
+cleanup:
+ /* pam_prompts is correct at this point */
+
+ for (i = 0; i < pam_prompts; i++) {
+ if (msg[i].msg)
+ free((char *) msg[i].msg);
+ }
+ free(msg);
+
+ if (resp) {
+ for (i = 0; i < pam_prompts; i++) {
+ /*
+ * Note that PAM is underspecified wrt free()'ing resp[i].resp.
+ * It's not clear if I should free it, or if the application
+ * has to. Therefore most (all?) apps won't free() it, and I
+ * can't either, as I am not sure it was malloc()'d. All PAM
+ * implementations I've seen leak memory here. Not so bad, IFF
+ * you fork/exec for each PAM authentication (as is typical).
+ */
+#if 0
+ if (resp[i].resp)
+ free(resp[i].resp);
+#endif /* 0 */
+ }
+ /* This does not lose resp[i].resp if the application saved a copy. */
+ free(resp);
+ }
+
+ return (pamret ? KRB5KRB_ERR_GENERIC : 0);
+}
+
+krb5_prompter_fct pam_prompter = heimdal_pam_prompter;
diff --git a/lib/libpam/modules/pam_krb5/pam_krb5.8 b/lib/libpam/modules/pam_krb5/pam_krb5.8
new file mode 100644
index 000000000000..7ef121170fb2
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/pam_krb5.8
@@ -0,0 +1,191 @@
+.\"
+.\" $Id: pam_krb5.5,v 1.5 2000/01/05 00:59:56 fcusack Exp $
+.\" $FreeBSD$
+.TH pam_krb5 8 "15 Jan 1999"
+.SH NAME
+pam_krb5 \- Kerberos 5 PAM module
+.SH SYNOPSIS
+.LP
+.B /usr/lib/pam_krb5.so
+.LP
+.SH DESCRIPTION
+.IX "pam_krb5" "" "\fLpam_krb5\fP \(em Kerberos 5 PAM module"
+.PP
+The Kerberos 5 service module for PAM, typically
+.BR /usr/lib/pam_krb5.so ,
+provides functionality for three PAM categories:
+authentication,
+account management,
+and password management.
+It also provides null functions for session management.
+The
+.B pam_krb5.so
+module is a shared object
+that can be dynamically loaded to provide
+the necessary functionality upon demand.
+Its path is specified in the
+.SM PAM
+configuration file.
+.SH Kerberos 5 Authentication Module
+The Kerberos 5 authentication component
+provides functions to verify the identity of a user.
+(\f3pam_sm_authenticate(\|)\f1)
+and to set user specific credentials
+(\f3pam_sm_setcred(\|)\f1).
+.B pam_sm_authenticate(\|)
+converts the supplied username into a Kerberos principal,
+by appending the default local realm name.
+It also supports usernames with explicit realm names.
+If a realm name is supplied, then upon a sucessful return, it
+changes the username by mapping the principal name into a local username
+(calling \f3krb5_aname_to_localname()\f1). This typically just means
+the realm name is stripped.
+.LP
+It prompts the user for a password and obtains a new Kerberos TGT for
+the principal. The TGT is verified by obtaining a service
+ticket for the local host.
+.LP
+When prompting for the current password, the authentication
+module will use the prompt "Password for <principal>: ".
+.LP
+The
+.B pam_sm_setcred(\|)
+function stores the newly acquired credentials in a credentials cache,
+and sets the environment variable
+.B KRB5CCNAME
+appropriately.
+The credentials cache should be destroyed by the user at logout with
+.BR kdestroy (1) .
+.LP
+The following options may be passed to the authentication module:
+.TP 15
+.B debug
+.BR syslog (3)
+debugging information at
+.SB LOG_DEBUG
+level.
+.TP
+.B use_first_pass
+If the authentication module is not the first in the stack,
+and a previous module obtained the user's password, that password is
+used to authenticate the user. If this fails, the authentication
+module returns failure without prompting the user for a password.
+This option has no effect if the authentication module is
+the first in the stack, or if no previous modules obtained the
+user's password.
+.TP
+.B try_first_pass
+This option is similar to the
+.B use_first_pass
+option, except that if the previously obtained password fails, the
+user is prompted for another password.
+.TP
+.B forwardable
+Obtain forwardable Kerberos credentials for the user.
+.TP
+.B no_ccache
+Do not save the obtained credentials in a credentials cache. This is a
+useful option if the authentication module is used for services such
+as ftp or pop, where the user would not be able to destroy them. [This
+is not a recommendation to use the module for those services.]
+.TP
+.B ccache=<name>
+Use <name> as the credentials cache. <name> must be in the form
+.IR type:residual .
+The special tokens
+.BR %u ,
+to designate the decimal uid of the user;
+and
+.BR %p ,
+to designate the current process id; can be used in <name>.
+.SH Kerberos 5 Account Management Module
+The Kerberos 5 account management component
+provides a function to perform account management,
+.BR pam_sm_acct_mgmt(\|) .
+The function verifies that the authenticated principal is allowed
+to login to the local user account by calling
+.B krb5_kuserok()
+(which checks the user's \&.k5login file).
+.SH Kerberos 5 Password Management Module
+The Kerberos 5 password management component
+provides a function to change passwords
+(\f3pam_sm_chauthtok(\|)\f1). The username supplied (the
+user running the
+.BR passwd (1)
+command, or the username given as an argument) is mapped into
+a Kerberos principal name, using the same technique as in
+the authentication module. Note that if a realm name was
+explicitly supplied during authentication, but not during
+a password change, the mapping
+done by the password management module may not result in the
+same principal as was used for authentication.
+.LP
+Unlike when
+changing a unix password, the password management module will
+allow any user to change any principal's password (if the user knows
+the principal's old password, of course). Also unlike unix, root
+is always prompted for the principal's old password.
+.LP
+The password management module uses the same heuristics as
+.BR kpasswd (1)
+to determine how to contact the Kerberos password server.
+.LP
+The following options may be passed to the password management
+module:
+.TP 15
+.B debug
+.BR syslog (3)
+debugging information at
+.SB LOG_DEBUG
+level.
+.TP
+.B use_first_pass
+If the password management module is not the first in the stack,
+and a previous module obtained the user's old password, that password is
+used to authenticate the user. If this fails, the password
+management
+module returns failure without prompting the user for the old password.
+If successful, the new password entered to the previous module is also
+used as the new Kerberos password. If the new password fails,
+the password management module returns failure without
+prompting the user for a new password.
+.TP
+.B try_first_pass
+This option is similar to the
+.B use_first_pass
+option, except that if the previously obtained old or new passwords fail,
+the user is prompted for them.
+.SH Kerberos 5 Session Management Module
+The Kerberos 5 session management component
+provides functions to initiate
+(\f3pam_sm_open_session(\|)\f1)
+and terminate
+(\f3pam_sm_close_session(\|)\f1)
+sessions. Since session management is not defined under Kerberos 5,
+both of these functions simply return success. They are provided
+only because of the naming conventions for PAM modules.
+.SH ENVIRONMENT
+.TP "\w'.SM KRB5CCNAME\ \ 'u"
+.SM KRB5CCNAME
+Location of the credentials cache.
+.SH FILES
+.TP "\w'/tmp/krb5cc_[uid]\ \ 'u"
+/tmp/krb5cc_[uid]
+default credentials cache ([uid] is the decimal UID of the user).
+.TP
+~/\&.k5login
+file containing Kerberos principals that are allowed access.
+.SH SEE ALSO
+.BR kdestroy (1),
+.BR passwd (1),
+.BR pam (8),
+.BR syslog (3),
+.BR pam.conf (5).
+.SH NOTES
+Applications should not call
+.B pam_authenticate()
+more than once between calls to
+.B pam_start()
+and
+.B pam_end()
+when using the Kerberos 5 PAM module.
diff --git a/lib/libpam/modules/pam_krb5/pam_krb5.h b/lib/libpam/modules/pam_krb5/pam_krb5.h
new file mode 100644
index 000000000000..ff0237321bdd
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/pam_krb5.h
@@ -0,0 +1,23 @@
+/*
+ * pam_krb5.h
+ *
+ * $Id: pam_krb5.h,v 1.5 1999/01/19 23:43:10 fcusack Exp $
+ * $FreeBSD$
+ */
+
+int get_user_info(pam_handle_t *, char *, int, char **);
+int verify_krb_v5_tgt(krb5_context, krb5_ccache, char *, int);
+void cleanup_cache(pam_handle_t *, void *, int);
+
+krb5_prompter_fct pam_prompter;
+
+const char *compat_princ_component(krb5_context, krb5_principal, int);
+void compat_free_data_contents(krb5_context, krb5_data *);
+krb5_error_code compat_cc_next_cred(krb5_context, const krb5_ccache,
+ krb5_cc_cursor *, krb5_creds *);
+
+#ifndef ENCTYPE_DES_CBC_MD5
+#define ENCTYPE_DES_CBC_MD5 ETYPE_DES_CBC_MD5
+#endif
+
+
diff --git a/lib/libpam/modules/pam_krb5/pam_krb5_acct.c b/lib/libpam/modules/pam_krb5/pam_krb5_acct.c
new file mode 100644
index 000000000000..1a2910bc1d8e
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/pam_krb5_acct.c
@@ -0,0 +1,83 @@
+/*
+ * pam_krb5_acct.c
+ *
+ * PAM account management functions for pam_krb5
+ *
+ * $FreeBSD$
+ */
+
+static const char rcsid[] = "$Id: pam_krb5_acct.c,v 1.3 1999/01/19 21:26:44 fcusack Exp $";
+
+#include <syslog.h> /* syslog */
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <krb5.h>
+#include <com_err.h>
+#include "pam_krb5.h"
+
+/* A useful logging macro */
+#define DLOG(error_func, error_msg) \
+if (debug) \
+ syslog(LOG_DEBUG, "pam_krb5: pam_sm_acct_mgmt(%s %s): %s: %s", \
+ service, name, error_func, error_msg)
+
+/* Check authorization of user */
+int
+pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv)
+{
+ krb5_error_code krbret;
+ krb5_context pam_context;
+ krb5_ccache ccache;
+ krb5_principal princ;
+
+ char *service, *name;
+ int debug = 0;
+ int i, pamret;
+
+ for (i = 0; i < argc; i++) {
+ if (strcmp(argv[i], "debug") == 0)
+ debug = 1;
+ }
+
+ /* Get username */
+ if (pam_get_item(pamh, PAM_USER, (const void **) &name)) {
+ return PAM_PERM_DENIED;;
+ }
+
+ /* Get service name */
+ (void) pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
+ if (!service)
+ service = "unknown";
+
+ DLOG("entry", "");
+
+ if (pam_get_data(pamh, "ccache", (const void **) &ccache)) {
+ /* User did not use krb5 to login */
+ DLOG("ccache", "not found");
+ return PAM_SUCCESS;
+ }
+
+ if ((krbret = krb5_init_context(&pam_context)) != 0) {
+ DLOG("krb5_init_context()", error_message(krbret));
+ return PAM_PERM_DENIED;;
+ }
+
+ if ((krbret = krb5_cc_get_principal(pam_context, ccache, &princ)) != 0) {
+ DLOG("krb5_cc_get_principal()", error_message(krbret));
+ pamret = PAM_PERM_DENIED;;
+ goto cleanup;
+ }
+
+ if (krb5_kuserok(pam_context, princ, name))
+ pamret = PAM_SUCCESS;
+ else
+ pamret = PAM_PERM_DENIED;
+ krb5_free_principal(pam_context, princ);
+
+cleanup:
+ krb5_free_context(pam_context);
+ DLOG("exit", pamret ? "failure" : "success");
+ return pamret;
+
+}
+
diff --git a/lib/libpam/modules/pam_krb5/pam_krb5_auth.c b/lib/libpam/modules/pam_krb5/pam_krb5_auth.c
new file mode 100644
index 000000000000..fd4270b7b3b2
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/pam_krb5_auth.c
@@ -0,0 +1,505 @@
+/*
+ * pam_krb5_auth.c
+ *
+ * PAM authentication management functions for pam_krb5
+ *
+ * $FreeBSD$
+ */
+
+static const char rcsid[] = "$Id: pam_krb5_auth.c,v 1.18 2000/01/04 08:44:08 fcusack Exp $";
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <limits.h> /* PATH_MAX */
+#include <pwd.h> /* getpwnam */
+#include <stdio.h> /* tmpnam */
+#include <stdlib.h> /* malloc */
+#include <strings.h> /* strchr */
+#include <syslog.h> /* syslog */
+#include <unistd.h> /* chown */
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+
+#include <krb5.h>
+#include <com_err.h>
+#include "pam_krb5.h"
+
+extern krb5_cc_ops krb5_mcc_ops;
+
+/* A useful logging macro */
+#define DLOG(error_func, error_msg) \
+if (debug) \
+ syslog(LOG_DEBUG, "pam_krb5: pam_sm_authenticate(%s %s): %s: %s", \
+ service, name, error_func, error_msg)
+
+/* Authenticate a user via krb5 */
+int
+pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
+ const char **argv)
+{
+ krb5_error_code krbret;
+ krb5_context pam_context;
+ krb5_creds creds;
+ krb5_principal princ;
+ krb5_ccache ccache, ccache_check;
+ krb5_get_init_creds_opt opts;
+
+ int pamret, i;
+ const char *name;
+ char *source_princ = NULL;
+ char *princ_name = NULL;
+ char *pass = NULL, *service = NULL;
+ char *prompt = NULL;
+ char cache_name[L_tmpnam + 8];
+ char lname[64]; /* local acct name */
+ struct passwd *pw;
+ uid_t ruid;
+
+ int debug = 0, try_first_pass = 0, use_first_pass = 0;
+ int forwardable = 0, reuse_ccache = 0, no_ccache = 0;
+
+ for (i = 0; i < argc; i++) {
+ if (strcmp(argv[i], "debug") == 0)
+ debug = 1;
+ else if (strcmp(argv[i], "try_first_pass") == 0)
+ try_first_pass = 1;
+ else if (strcmp(argv[i], "use_first_pass") == 0)
+ use_first_pass = 1;
+ else if (strcmp(argv[i], "forwardable") == 0)
+ forwardable = 1;
+ else if (strcmp(argv[i], "reuse_ccache") == 0)
+ reuse_ccache = 1;
+ else if (strcmp(argv[i], "no_ccache") == 0)
+ no_ccache = 1;
+ }
+
+ /* Get username */
+ if ((pamret = pam_get_user(pamh, &name, "login: ")) != PAM_SUCCESS) {
+ return PAM_SERVICE_ERR;
+ }
+
+ /* Get service name */
+ (void) pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
+ if (!service)
+ service = "unknown";
+
+ DLOG("entry", "");
+
+ if ((krbret = krb5_init_context(&pam_context)) != 0) {
+ DLOG("krb5_init_context()", error_message(krbret));
+ return PAM_SERVICE_ERR;
+ }
+ krb5_get_init_creds_opt_init(&opts);
+ memset(&creds, 0, sizeof(krb5_creds));
+ memset(cache_name, 0, sizeof(cache_name));
+ memset(lname, 0, sizeof(lname));
+
+ if (forwardable)
+ krb5_get_init_creds_opt_set_forwardable(&opts, 1);
+
+ /* For CNS */
+ if ((krbret = krb5_cc_register(pam_context, &krb5_mcc_ops, FALSE)) != 0) {
+ /* Solaris dtlogin doesn't call pam_end() on failure */
+ if (krbret != KRB5_CC_TYPE_EXISTS) {
+ DLOG("krb5_cc_register()", error_message(krbret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+ }
+
+ /* Get principal name */
+ /* This case is for use mainly by su.
+ If non-root is authenticating as "root", use "source_user/root". */
+ if (!strcmp(name, "root") && (ruid = getuid()) != 0) {
+ pw = getpwuid(ruid);
+ if (pw != NULL)
+ source_princ = (char *)malloc(strlen(pw->pw_name) + 6);
+ if (source_princ)
+ sprintf(source_princ, "%s/root", pw->pw_name);
+ } else {
+ source_princ = strdup(name);
+ }
+ if (!source_princ) {
+ DLOG("malloc()", "failure");
+ pamret = PAM_BUF_ERR;
+ goto cleanup2;
+ }
+
+ if ((krbret = krb5_parse_name(pam_context, source_princ, &princ)) != 0) {
+ DLOG("krb5_parse_name()", error_message(krbret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+
+ /* Now convert the principal name into something human readable */
+ if ((krbret = krb5_unparse_name(pam_context, princ, &princ_name)) != 0) {
+ DLOG("krb5_unparse_name()", error_message(krbret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+
+ /* Get password */
+ prompt = malloc(16 + strlen(princ_name));
+ if (!prompt) {
+ DLOG("malloc()", "failure");
+ pamret = PAM_BUF_ERR;
+ goto cleanup2;
+ }
+ (void) sprintf(prompt, "Password for %s: ", princ_name);
+
+ if (try_first_pass || use_first_pass)
+ (void) pam_get_item(pamh, PAM_AUTHTOK, (const void **) &pass);
+
+get_pass:
+ if (!pass) {
+ try_first_pass = 0;
+ if ((pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF,
+ &pass)) != 0) {
+ DLOG("get_user_info()", pam_strerror(pamh, pamret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ /* We have to free pass. */
+ if ((pamret = pam_set_item(pamh, PAM_AUTHTOK, pass)) != 0) {
+ DLOG("pam_set_item()", pam_strerror(pamh, pamret));
+ free(pass);
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ free(pass);
+ /* Now we get it back from the library. */
+ (void) pam_get_item(pamh, PAM_AUTHTOK, (const void **) &pass);
+ }
+
+ /* get a local account name for this principal */
+ if ((krbret = krb5_aname_to_localname(pam_context, princ,
+ sizeof(lname), lname)) == 0) {
+ DLOG("changing PAM_USER to", lname);
+ if ((pamret = pam_set_item(pamh, PAM_USER, lname)) != 0) {
+ DLOG("pam_set_item()", pam_strerror(pamh, pamret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ if ((pamret = pam_get_item(pamh, PAM_USER, (const void **) &name)
+ != 0)) {
+ DLOG("pam_get_item()", pam_strerror(pamh, pamret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ } else {
+ DLOG("krb5_aname_to_localname()", error_message(krbret));
+ /* Not an error. */
+ }
+
+ /* Verify the local user exists (AFTER getting the password) */
+ pw = getpwnam(name);
+ if (!pw) {
+ DLOG("getpwnam()", lname);
+ pamret = PAM_USER_UNKNOWN;
+ goto cleanup2;
+ }
+
+ /* Get a TGT */
+ if ((krbret = krb5_get_init_creds_password(pam_context, &creds, princ,
+ pass, pam_prompter, pamh, 0, NULL, &opts)) != 0) {
+ DLOG("krb5_get_init_creds_password()", error_message(krbret));
+ if (try_first_pass && krbret == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
+ pass = NULL;
+ goto get_pass;
+ }
+ pamret = PAM_AUTH_ERR;
+ goto cleanup2;
+ }
+
+ /* Generate a unique cache_name */
+ strcpy(cache_name, "MEMORY:");
+ (void) tmpnam(&cache_name[7]);
+
+ if ((krbret = krb5_cc_resolve(pam_context, cache_name, &ccache)) != 0) {
+ DLOG("krb5_cc_resolve()", error_message(krbret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup;
+ }
+ if ((krbret = krb5_cc_initialize(pam_context, ccache, princ)) != 0) {
+ DLOG("krb5_cc_initialize()", error_message(krbret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup;
+ }
+ if ((krbret = krb5_cc_store_cred(pam_context, ccache, &creds)) != 0) {
+ DLOG("krb5_cc_store_cred()", error_message(krbret));
+ (void) krb5_cc_destroy(pam_context, ccache);
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup;
+ }
+
+ /* Verify it */
+ if (verify_krb_v5_tgt(pam_context, ccache, service, debug) == -1) {
+ (void) krb5_cc_destroy(pam_context, ccache);
+ pamret = PAM_AUTH_ERR;
+ goto cleanup;
+ }
+
+ /* A successful authentication, store ccache for sm_setcred() */
+ if (!pam_get_data(pamh, "ccache", (const void **) &ccache_check)) {
+ DLOG("pam_get_data()", "ccache data already present");
+ (void) krb5_cc_destroy(pam_context, ccache);
+ pamret = PAM_AUTH_ERR;
+ goto cleanup;
+ }
+ if ((pamret = pam_set_data(pamh, "ccache", ccache, cleanup_cache)) != 0) {
+ DLOG("pam_set_data()", pam_strerror(pamh, pamret));
+ (void) krb5_cc_destroy(pam_context, ccache);
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup;
+ }
+
+cleanup:
+ krb5_free_cred_contents(pam_context, &creds);
+cleanup2:
+ krb5_free_principal(pam_context, princ);
+cleanup3:
+ if (prompt)
+ free(prompt);
+ if (princ_name)
+ free(princ_name);
+ if (source_princ)
+ free(source_princ);
+
+ krb5_free_context(pam_context);
+ DLOG("exit", pamret ? "failure" : "success");
+ return pamret;
+}
+
+
+
+/* redefine this for pam_sm_setcred() */
+#undef DLOG
+#define DLOG(error_func, error_msg) \
+if (debug) \
+ syslog(LOG_DEBUG, "pam_krb5: pam_sm_setcred(%s %s): %s: %s", \
+ service, name, error_func, error_msg)
+
+/* Called after a successful authentication. Set user credentials. */
+int
+pam_sm_setcred(pam_handle_t *pamh, int flags, int argc,
+ const char **argv)
+{
+
+ krb5_error_code krbret;
+ krb5_context pam_context;
+ krb5_principal princ;
+ krb5_creds creds;
+ krb5_ccache ccache_temp, ccache_perm;
+ krb5_cc_cursor cursor;
+
+ int i, pamret;
+ char *name, *service = NULL;
+ char *cache_name = NULL, *cache_env_name;
+ struct passwd *pw = NULL;
+
+ int debug = 0;
+ uid_t euid;
+ gid_t egid;
+
+ if (flags == PAM_REINITIALIZE_CRED)
+ return PAM_SUCCESS; /* XXX Incorrect behavior */
+
+ if (flags != PAM_ESTABLISH_CRED && flags != PAM_DELETE_CRED)
+ return PAM_SERVICE_ERR;
+
+ for (i = 0; i < argc; i++) {
+ if (strcmp(argv[i], "debug") == 0)
+ debug = 1;
+ else if (strcmp(argv[i], "no_ccache") == 0)
+ return PAM_SUCCESS;
+ else if (strstr(argv[i], "ccache=") == argv[i])
+ cache_name = (char *) &argv[i][7]; /* save for later */
+ }
+
+ /* Get username */
+ if (pam_get_item(pamh, PAM_USER, (const void **) &name)) {
+ return PAM_SERVICE_ERR;
+ }
+
+ /* Get service name */
+ (void) pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
+ if (!service)
+ service = "unknown";
+
+ DLOG("entry", "");
+
+ if ((krbret = krb5_init_context(&pam_context)) != 0) {
+ DLOG("krb5_init_context()", error_message(krbret));
+ return PAM_SERVICE_ERR;
+ }
+
+ euid = geteuid(); /* Usually 0 */
+ egid = getegid();
+
+ /* Retrieve the cache name */
+ if ((pamret = pam_get_data(pamh, "ccache", (const void **) &ccache_temp))
+ != 0) {
+ /* User did not use krb5 to login */
+ DLOG("ccache", "not found");
+ pamret = PAM_SUCCESS;
+ goto cleanup3;
+ }
+
+ /* Get the uid. This should exist. */
+ pw = getpwnam(name);
+ if (!pw) {
+ DLOG("getpwnam()", name);
+ pamret = PAM_USER_UNKNOWN;
+ goto cleanup3;
+ }
+
+ /* Avoid following a symlink as root */
+ if (setegid(pw->pw_gid)) {
+ DLOG("setegid()", name); /* XXX should really log group name or id */
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+ if (seteuid(pw->pw_uid)) {
+ DLOG("seteuid()", name);
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+
+ /* Get the cache name */
+ if (!cache_name) {
+ cache_name = malloc(64); /* plenty big */
+ if (!cache_name) {
+ DLOG("malloc()", "failure");
+ pamret = PAM_BUF_ERR;
+ goto cleanup3;
+ }
+ sprintf(cache_name, "FILE:/tmp/krb5cc_%d", pw->pw_uid);
+ } else {
+ /* cache_name was supplied */
+ char *p = calloc(PATH_MAX + 10, 1); /* should be plenty */
+ char *q = cache_name;
+ if (!p) {
+ DLOG("malloc()", "failure");
+ pamret = PAM_BUF_ERR;
+ goto cleanup3;
+ }
+ cache_name = p;
+
+ /* convert %u and %p */
+ while (*q) {
+ if (*q == '%') {
+ q++;
+ if (*q == 'u') {
+ sprintf(p, "%d", pw->pw_uid);
+ p += strlen(p);
+ } else if (*q == 'p') {
+ sprintf(p, "%d", getpid());
+ p += strlen(p);
+ } else {
+ /* Not a special token */
+ *p++ = '%';
+ q--;
+ }
+ q++;
+ } else {
+ *p++ = *q++;
+ }
+ }
+ }
+
+ if ((krbret = krb5_cc_resolve(pam_context, cache_name, &ccache_perm))
+ != 0) {
+ DLOG("krb5_cc_resolve()", error_message(krbret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+ if (flags == PAM_ESTABLISH_CRED) {
+ /* Initialize the new ccache */
+ if ((krbret = krb5_cc_get_principal(pam_context, ccache_temp, &princ))
+ != 0) {
+ DLOG("krb5_cc_get_principal()", error_message(krbret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup3;
+ }
+ if ((krbret = krb5_cc_initialize(pam_context, ccache_perm, princ)) != 0) {
+ DLOG("krb5_cc_initialize()", error_message(krbret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+
+ /* Prepare for iteration over creds */
+ if ((krbret = krb5_cc_start_seq_get(pam_context, ccache_temp, &cursor))
+ != 0) {
+ DLOG("krb5_cc_start_seq_get()", error_message(krbret));
+ (void) krb5_cc_destroy(pam_context, ccache_perm);
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+
+ /* Copy the creds (should be two of them) */
+ while ((krbret = compat_cc_next_cred(pam_context, ccache_temp,
+ &cursor, &creds) == 0)) {
+ if ((krbret = krb5_cc_store_cred(pam_context, ccache_perm,
+ &creds)) != 0) {
+ DLOG("krb5_cc_store_cred()", error_message(krbret));
+ (void) krb5_cc_destroy(pam_context, ccache_perm);
+ krb5_free_cred_contents(pam_context, &creds);
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ krb5_free_cred_contents(pam_context, &creds);
+ }
+ (void) krb5_cc_end_seq_get(pam_context, ccache_temp, &cursor);
+
+ if (strstr(cache_name, "FILE:") == cache_name) {
+ if (chown(&cache_name[5], pw->pw_uid, pw->pw_gid) == -1) {
+ DLOG("chown()", strerror(errno));
+ (void) krb5_cc_destroy(pam_context, ccache_perm);
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ if (chmod(&cache_name[5], (S_IRUSR|S_IWUSR)) == -1) {
+ DLOG("chmod()", strerror(errno));
+ (void) krb5_cc_destroy(pam_context, ccache_perm);
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ }
+ (void) krb5_cc_close(pam_context, ccache_perm);
+
+ cache_env_name = malloc(strlen(cache_name) + 12);
+ if (!cache_env_name) {
+ DLOG("malloc()", "failure");
+ (void) krb5_cc_destroy(pam_context, ccache_perm);
+ pamret = PAM_BUF_ERR;
+ goto cleanup2;
+ }
+
+ sprintf(cache_env_name, "KRB5CCNAME=%s", cache_name);
+ if ((pamret = pam_putenv(pamh, cache_env_name)) != 0) {
+ DLOG("pam_putenv()", pam_strerror(pamh, pamret));
+ (void) krb5_cc_destroy(pam_context, ccache_perm);
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ } else {
+ /* flag == PAM_DELETE_CRED */
+ if ((krbret = krb5_cc_destroy(pam_context, ccache_perm)) != 0) {
+ /* log error, but otherwise ignore it */
+ DLOG("krb5_cc_destroy()", error_message(krbret));
+ }
+ goto cleanup3;
+ }
+
+cleanup2:
+ krb5_free_principal(pam_context, princ);
+cleanup3:
+ krb5_free_context(pam_context);
+ DLOG("exit", pamret ? "failure" : "success");
+ (void) seteuid(euid);
+ (void) setegid(egid);
+ return pamret;
+}
+
diff --git a/lib/libpam/modules/pam_krb5/pam_krb5_pass.c b/lib/libpam/modules/pam_krb5/pam_krb5_pass.c
new file mode 100644
index 000000000000..994c7f4720c6
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/pam_krb5_pass.c
@@ -0,0 +1,200 @@
+/*
+ * pam_krb5_pass.c
+ *
+ * PAM password management functions for pam_krb5
+ *
+ * $FreeBSD$
+ */
+
+static const char rcsid[] = "$Id: pam_krb5_pass.c,v 1.3 1999/01/19 23:43:11 fcusack Exp $";
+
+#include <errno.h>
+#include <stdio.h> /* sprintf */
+#include <stdlib.h> /* malloc */
+#include <syslog.h> /* syslog */
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <krb5.h>
+#include <com_err.h>
+#include "pam_krb5.h"
+
+/* A useful logging macro */
+#define DLOG(error_func, error_msg) \
+if (debug) \
+ syslog(LOG_DEBUG, "pam_krb5: pam_sm_chauthtok(%s %s): %s: %s", \
+ service, name, error_func, error_msg)
+
+/* Change a user's password */
+int
+pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
+{
+ krb5_error_code krbret;
+ krb5_context pam_context;
+ krb5_creds creds;
+ krb5_principal princ;
+ krb5_get_init_creds_opt opts;
+
+ int result_code;
+ krb5_data result_code_string, result_string;
+
+ int pamret, i;
+ char *name, *service = NULL, *pass = NULL, *pass2;
+ char *princ_name = NULL;
+ char *prompt = NULL;
+
+ int debug = 0;
+ int try_first_pass = 0, use_first_pass = 0;
+
+ if (!(flags & PAM_UPDATE_AUTHTOK))
+ return PAM_AUTHTOK_ERR;
+
+ for (i = 0; i < argc; i++) {
+ if (strcmp(argv[i], "debug") == 0)
+ debug = 1;
+ else if (strcmp(argv[i], "try_first_pass") == 0)
+ try_first_pass = 1;
+ else if (strcmp(argv[i], "use_first_pass") == 0)
+ use_first_pass = 1;
+ }
+
+ /* Get username */
+ if ((pam_get_item(pamh, PAM_USER, (const void **) &name)) != 0) {
+ return PAM_SERVICE_ERR;
+ }
+
+ /* Get service name */
+ (void) pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
+ if (!service)
+ service = "unknown";
+
+ DLOG("entry", "");
+
+ if ((krbret = krb5_init_context(&pam_context)) != 0) {
+ DLOG("krb5_init_context()", error_message(krbret));
+ return PAM_SERVICE_ERR;
+ }
+
+ if ((krbret = krb5_init_context(&pam_context)) != 0) {
+ DLOG("krb5_init_context()", error_message(krbret));
+ return PAM_SERVICE_ERR;
+ }
+ krb5_get_init_creds_opt_init(&opts);
+ memset(&creds, 0, sizeof(krb5_creds));
+
+ /* Get principal name */
+ if ((krbret = krb5_parse_name(pam_context, name, &princ)) != 0) {
+ DLOG("krb5_parse_name()", error_message(krbret));
+ pamret = PAM_USER_UNKNOWN;
+ goto cleanup3;
+ }
+
+ /* Now convert the principal name into something human readable */
+ if ((krbret = krb5_unparse_name(pam_context, princ, &princ_name)) != 0) {
+ DLOG("krb5_unparse_name()", error_message(krbret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+
+ /* Get password */
+ prompt = malloc(16 + strlen(princ_name));
+ if (!prompt) {
+ DLOG("malloc()", "failure");
+ pamret = PAM_BUF_ERR;
+ goto cleanup2;
+ }
+ (void) sprintf(prompt, "Password for %s: ", princ_name);
+
+ if (try_first_pass || use_first_pass)
+ (void) pam_get_item(pamh, PAM_AUTHTOK, (const void **) &pass);
+
+get_pass:
+ if (!pass) {
+ try_first_pass = 0;
+ if ((pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF,
+ &pass)) != 0) {
+ DLOG("get_user_info()", pam_strerror(pamh, pamret));
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ /* We have to free pass. */
+ if ((pamret = pam_set_item(pamh, PAM_AUTHTOK, pass)) != 0) {
+ DLOG("pam_set_item()", pam_strerror(pamh, pamret));
+ free(pass);
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup2;
+ }
+ free(pass);
+ /* Now we get it back from the library. */
+ (void) pam_get_item(pamh, PAM_AUTHTOK, (const void **) &pass);
+ }
+
+ if ((krbret = krb5_get_init_creds_password(pam_context, &creds, princ,
+ pass, pam_prompter, pamh, 0, "kadmin/changepw", &opts)) != 0) {
+ DLOG("krb5_get_init_creds_password()", error_message(krbret));
+ if (try_first_pass && krbret == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
+ pass = NULL;
+ goto get_pass;
+ }
+ pamret = PAM_AUTH_ERR;
+ goto cleanup2;
+ }
+
+ /* Now get the new password */
+ free(prompt);
+ prompt = "Enter new password: ";
+ if ((pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF, &pass))
+ != 0) {
+ DLOG("get_user_info()", pam_strerror(pamh, pamret));
+ prompt = NULL;
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup;
+ }
+ prompt = "Enter it again: ";
+ if ((pamret = get_user_info(pamh, prompt, PAM_PROMPT_ECHO_OFF, &pass2))
+ != 0) {
+ DLOG("get_user_info()", pam_strerror(pamh, pamret));
+ prompt = NULL;
+ pamret = PAM_SERVICE_ERR;
+ goto cleanup;
+ }
+ prompt = NULL;
+
+ if (strcmp(pass, pass2) != 0) {
+ DLOG("strcmp()", "passwords not equal");
+ pamret = PAM_AUTHTOK_ERR;
+ goto cleanup;
+ }
+
+ /* Change it */
+ if ((krbret = krb5_change_password(pam_context, &creds, pass,
+ &result_code, &result_code_string, &result_string)) != 0) {
+ DLOG("krb5_change_password()", error_message(krbret));
+ pamret = PAM_AUTHTOK_ERR;
+ goto cleanup;
+ }
+ if (result_code) {
+ DLOG("krb5_change_password() (result_code)", "");
+ pamret = PAM_AUTHTOK_ERR;
+ goto cleanup;
+ }
+
+ if (result_string.data)
+ free(result_string.data);
+ if (result_code_string.data)
+ free(result_code_string.data);
+
+cleanup:
+ krb5_free_cred_contents(pam_context, &creds);
+cleanup2:
+ krb5_free_principal(pam_context, princ);
+cleanup3:
+ if (prompt)
+ free(prompt);
+ if (princ_name)
+ free(princ_name);
+
+ krb5_free_context(pam_context);
+ DLOG("exit", pamret ? "failure" : "success");
+ return pamret;
+}
+
diff --git a/lib/libpam/modules/pam_krb5/pam_krb5_sess.c b/lib/libpam/modules/pam_krb5/pam_krb5_sess.c
new file mode 100644
index 000000000000..b2df06434fa6
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/pam_krb5_sess.c
@@ -0,0 +1,28 @@
+/*
+ * pam_krb5_sess.c
+ *
+ * PAM session management functions for pam_krb5
+ * (null functions)
+ *
+ * $FreeBSD$
+ */
+
+static const char rcsid[] = "$Id: pam_krb5_sess.c,v 1.3 1999/01/19 20:49:44 fcusack Exp $";
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+
+/* Initiate session management */
+int
+pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
+{
+ return PAM_SUCCESS;
+}
+
+
+/* Terminate session management */
+int
+pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
+{
+ return PAM_SUCCESS;
+}
diff --git a/lib/libpam/modules/pam_krb5/support.c b/lib/libpam/modules/pam_krb5/support.c
new file mode 100644
index 000000000000..8e1aecda640f
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/support.c
@@ -0,0 +1,185 @@
+/*
+ * support.c
+ *
+ * Support functions for pam_krb5
+ *
+ * $FreeBSD$
+ */
+
+static const char rcsid[] = "$Id: support.c,v 1.8 2000/01/04 09:50:03 fcusack Exp $";
+
+#include <errno.h>
+#include <stdio.h> /* BUFSIZ */
+#include <stdlib.h> /* malloc */
+#include <string.h> /* strncpy */
+#include <syslog.h> /* syslog */
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <krb5.h>
+#include <com_err.h>
+#include "pam_krb5.h"
+
+/*
+ * Get info from the user. Disallow null responses (regardless of flags).
+ * response gets allocated and filled in on successful return. Caller
+ * is responsible for freeing it.
+ */
+int
+get_user_info(pam_handle_t *pamh, char *prompt, int type, char **response)
+{
+ int pamret;
+ struct pam_message msg;
+ const struct pam_message *pmsg;
+ struct pam_response *resp = NULL;
+ struct pam_conv *conv;
+
+ if ((pamret = pam_get_item(pamh, PAM_CONV, (const void **) &conv)) != 0)
+ return pamret;
+
+ /* set up conversation call */
+ pmsg = &msg;
+ msg.msg_style = type;
+ msg.msg = prompt;
+
+ if ((pamret = conv->conv(1, &pmsg, &resp, conv->appdata_ptr)) != 0)
+ return pamret;
+
+ /* Caller should ignore errors for non-response conversations */
+ if (!resp)
+ return PAM_CONV_ERR;
+
+ if (!(resp->resp && resp->resp[0])) {
+ free(resp);
+ return PAM_AUTH_ERR;
+ }
+
+ *response = resp->resp;
+ free(resp);
+ return pamret;
+}
+
+/*
+ * This routine with some modification is from the MIT V5B6 appl/bsd/login.c
+ * Modified by Sam Hartman <hartmans@mit.edu> to support PAM services
+ * for Debian.
+ *
+ * Verify the Kerberos ticket-granting ticket just retrieved for the
+ * user. If the Kerberos server doesn't respond, assume the user is
+ * trying to fake us out (since we DID just get a TGT from what is
+ * supposedly our KDC). If the host/<host> service is unknown (i.e.,
+ * the local keytab doesn't have it), and we cannot find another
+ * service we do have, let her in.
+ *
+ * Returns 1 for confirmation, -1 for failure, 0 for uncertainty.
+ */
+int
+verify_krb_v5_tgt(krb5_context context, krb5_ccache ccache,
+ char * pam_service, int debug)
+{
+ char phost[BUFSIZ];
+ char *services [3];
+ char **service;
+ krb5_error_code retval = -1;
+ krb5_principal princ;
+ krb5_keyblock * keyblock = 0;
+ krb5_data packet;
+ krb5_auth_context auth_context = NULL;
+
+ packet.data = 0;
+
+ /*
+ * If possible we want to try and verify the ticket we have
+ * received against a keytab. We will try multiple service
+ * principals, including at least the host principal and the PAM
+ * service principal. The host principal is preferred because access
+ * to that key is generally sufficient to compromise root, while the
+ * service key for this PAM service may be less carefully guarded.
+ * It is important to check the keytab first before the KDC so we do
+ * not get spoofed by a fake KDC.*/
+ services [0] = "host";
+ services [1] = pam_service;
+ services [2] = NULL;
+ for ( service = &services[0]; *service != NULL; service++ ) {
+ if ((retval = krb5_sname_to_principal(context, NULL, *service, KRB5_NT_SRV_HST,
+ &princ)) != 0) {
+ if (debug)
+ syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
+ "krb5_sname_to_principal()", error_message(retval));
+ return -1;
+ }
+
+ /* Extract the name directly. */
+ strncpy(phost, compat_princ_component(context, princ, 1), BUFSIZ);
+ phost[BUFSIZ - 1] = '\0';
+
+ /*
+ * Do we have service/<host> keys?
+ * (use default/configured keytab, kvno IGNORE_VNO to get the
+ * first match, and ignore enctype.)
+ */
+ if ((retval = krb5_kt_read_service_key(context, NULL, princ, 0,
+ 0, &keyblock)) != 0)
+ continue;
+ break;
+ }
+ if (retval != 0 ) { /* failed to find key */
+ /* Keytab or service key does not exist */
+ if (debug)
+ syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
+ "krb5_kt_read_service_key()", error_message(retval));
+ retval = 0;
+ goto cleanup;
+ }
+ if (keyblock)
+ krb5_free_keyblock(context, keyblock);
+
+ /* Talk to the kdc and construct the ticket. */
+ retval = krb5_mk_req(context, &auth_context, 0, *service, phost,
+ NULL, ccache, &packet);
+ if (auth_context) {
+ krb5_auth_con_free(context, auth_context);
+ auth_context = NULL; /* setup for rd_req */
+ }
+ if (retval) {
+ if (debug)
+ syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
+ "krb5_mk_req()", error_message(retval));
+ retval = -1;
+ goto cleanup;
+ }
+
+ /* Try to use the ticket. */
+ retval = krb5_rd_req(context, &auth_context, &packet, princ,
+ NULL, NULL, NULL);
+ if (retval) {
+ if (debug)
+ syslog(LOG_DEBUG, "pam_krb5: verify_krb_v5_tgt(): %s: %s",
+ "krb5_rd_req()", error_message(retval));
+ retval = -1;
+ } else {
+ retval = 1;
+ }
+
+cleanup:
+ if (packet.data)
+ compat_free_data_contents(context, &packet);
+ krb5_free_principal(context, princ);
+ return retval;
+
+}
+
+
+/* Free the memory for cache_name. Called by pam_end() */
+void
+cleanup_cache(pam_handle_t *pamh, void *data, int pam_end_status)
+{
+ krb5_context pam_context;
+ krb5_ccache ccache;
+
+ if (krb5_init_context(&pam_context))
+ return;
+
+ ccache = (krb5_ccache) data;
+ (void) krb5_cc_destroy(pam_context, ccache);
+ krb5_free_context(pam_context);
+}