diff options
| author | cvs2svn <cvs2svn@FreeBSD.org> | 2001-05-20 23:12:14 +0000 |
|---|---|---|
| committer | cvs2svn <cvs2svn@FreeBSD.org> | 2001-05-20 23:12:14 +0000 |
| commit | a2a591a7dd99355b9b940cc797be071bdb19a86b (patch) | |
| tree | 411c5c7d58fd94211c4c3ec10232e5d4d3eb0bc1 /lib | |
| parent | fd24c73a2c496aaf5c7e251e75dbc5d17fcd2514 (diff) | |
Notes
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/libc/gen/getprogname.3 | 92 | ||||
| -rw-r--r-- | lib/libc/gen/getprogname.c | 13 | ||||
| -rw-r--r-- | lib/libc/gen/setprogname.c | 13 | ||||
| -rw-r--r-- | lib/libc/stdlib/hcreate.c | 184 | ||||
| -rw-r--r-- | lib/libc/string/wmemchr.3 | 145 | ||||
| -rw-r--r-- | lib/libc_r/test/join_leak_d.c | 108 | ||||
| -rw-r--r-- | lib/libc_r/test/join_leak_d.exp | 2 | ||||
| -rw-r--r-- | lib/libpam/modules/pam_krb5/COPYRIGHT | 195 | ||||
| -rw-r--r-- | lib/libpam/modules/pam_krb5/README | 72 | ||||
| -rw-r--r-- | lib/libpam/modules/pam_krb5/TODO | 16 | ||||
| -rw-r--r-- | lib/libpam/modules/pam_krb5/compat_heimdal.c | 141 | ||||
| -rw-r--r-- | lib/libpam/modules/pam_krb5/pam_krb5.8 | 191 | ||||
| -rw-r--r-- | lib/libpam/modules/pam_krb5/pam_krb5.h | 23 | ||||
| -rw-r--r-- | lib/libpam/modules/pam_krb5/pam_krb5_acct.c | 83 | ||||
| -rw-r--r-- | lib/libpam/modules/pam_krb5/pam_krb5_auth.c | 505 | ||||
| -rw-r--r-- | lib/libpam/modules/pam_krb5/pam_krb5_pass.c | 200 | ||||
| -rw-r--r-- | lib/libpam/modules/pam_krb5/pam_krb5_sess.c | 28 | ||||
| -rw-r--r-- | lib/libpam/modules/pam_krb5/support.c | 185 |
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); +} |
