source: trunk/debathena/debathena/libpam-krb524/pam_krb524.c @ 22686

Revision 22686, 5.9 KB checked in by ghudson, 17 years ago (diff)
* debathena/debathena: Snapshot debathena package sources from /mit/debathena/packages/debathena.
Line 
1/*
2 * pam_krb524.c
3 * PAM session management functions for pam_krb524.so
4 *
5 * Copyright © 2007 Tim Abbott <tabbott@mit.edu> and Anders Kaseorg
6 * <andersk@mit.edu>
7 *
8 * Permission is hereby granted, free of charge, to any person
9 * obtaining a copy of this software and associated documentation
10 * files (the "Software"), to deal in the Software without
11 * restriction, including without limitation the rights to use, copy,
12 * modify, merge, publish, distribute, sublicense, and/or sell copies
13 * of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be
17 * included in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
29#include <stdio.h>      /* snprintf */
30#include <string.h>     /* strcmp */
31#include <unistd.h>     /* unlink, syslog */
32#include <security/pam_appl.h>
33#include <security/pam_modules.h>
34#include <sys/types.h>
35#include <sys/wait.h>
36#include <pwd.h>
37#include <stdlib.h>
38#include <errno.h>
39#include <syslog.h>
40
41#define MAXBUF 256
42
43
44/*
45 * Make up a deterministic name for the Kerberos 4 ticket cache from
46 * KRB5CCNAME.
47 */
48static int
49get_krb4_name(pam_handle_t *pamh, const char **cache_name, char *cache_name4, size_t len)
50{
51    int n;
52    *cache_name = pam_getenv(pamh, "KRB5CCNAME");
53    if (*cache_name == NULL) {
54        syslog(LOG_ERR, "pam_krb524: No krb5 cache found");
55        return PAM_SESSION_ERR;
56    }
57
58    if (strncmp(*cache_name, "FILE:/tmp/krb5cc_", 17) == 0)
59        n = snprintf(cache_name4, len, "/tmp/tkt_%s", *cache_name + 17);
60    else if (strncmp(*cache_name, "/tmp/krb5cc_", 12) == 0)
61        n = snprintf(cache_name4, len, "/tmp/tkt_%s", *cache_name + 12);
62    else {
63        syslog(LOG_ERR, "pam_krb524: Could not get krb4 name from krb5 name: %s", *cache_name);
64        return PAM_SESSION_ERR;
65    }
66    if (n < 0 || n >= len) {
67        syslog(LOG_ERR, "pam_krb524: snprintf failed");
68        return PAM_BUF_ERR;
69    }
70    return PAM_SUCCESS;
71}
72
73/*
74 * Do the Kerberos 4 ticket getting work, using a name based on the
75 * name of the Kerberos 5 ticket cache.  The flags are ignored.
76 */
77int
78pam_sm_open_session(pam_handle_t *pamh, int flags, int argc,
79                    const char **argv)
80{
81    int i;
82    int pamret;
83    struct passwd *pw = NULL;
84    uid_t uid;
85    gid_t gid;
86    int debug = 0;
87    int pid;
88    const char *user = NULL;
89    int n;
90    char cache_name4[MAXBUF];
91    char cache_env_name4[MAXBUF];
92    const char *cache_name;
93    int status;
94
95    for (i = 0; i < argc; i++) {
96        if (strcmp(argv[i], "debug") == 0)
97            debug = 1;
98    }
99
100    /* Get username */
101    if ((pamret = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) {
102        return PAM_SERVICE_ERR;
103    }
104
105    pw = getpwnam(user);
106    if (pw == NULL) {
107        return PAM_USER_UNKNOWN;
108    }
109    uid = pw->pw_uid;
110    gid = pw->pw_gid;
111
112    if ((pamret = get_krb4_name(pamh, &cache_name, cache_name4, MAXBUF)) !=
113        PAM_SUCCESS)
114        return pamret;
115
116    if (debug)
117        syslog(LOG_DEBUG, "pam_krb524: Got krb4 name: %s", cache_name4);
118
119    n = snprintf(cache_env_name4, MAXBUF, "KRBTKFILE=%s", cache_name4);
120    if (n < 0 || n >= MAXBUF) {
121        syslog(LOG_ERR, "pam_krb524: snprintf failed");
122        return PAM_BUF_ERR;
123    }
124
125    if ((pamret = pam_putenv(pamh, cache_env_name4)) != PAM_SUCCESS) {
126        syslog(LOG_ERR, "pam_krb524: pam_putenv(): %s", pam_strerror(pamh, pamret));
127        return PAM_SESSION_ERR;
128    }
129
130    if ((pid = fork()) == -1) {
131        syslog(LOG_ERR, "pam_krb524: fork(): %s", strerror(errno));
132        return PAM_SESSION_ERR;
133    }
134    if (pid == 0) {
135        /* setup the environment */
136        char buf[MAXBUF], buf4[MAXBUF];
137        char *envi[3] = {buf, buf4, NULL};
138        n = snprintf(buf, MAXBUF, "KRB5CCNAME=%s", cache_name);
139        if (n < 0 || n >= MAXBUF) {
140            syslog(LOG_ERR, "pam_krb524: snprintf failed");
141            _exit(-1);
142        }
143        n = snprintf(buf4, MAXBUF, "KRBTKFILE=%s", cache_name4);
144        if (n < 0 || n >= MAXBUF) {
145            syslog(LOG_ERR, "pam_krb524: snprintf failed");
146            _exit(-1);
147        }
148
149        /* make the forked process have the right real UID for krb524init
150           which is very unhappy with uid != euid. */
151        if (setregid(gid, gid) != 0 ||
152            setreuid(uid, uid) != 0) {
153            syslog(LOG_ERR, "pam_krb524: could not set egid and euid");
154            _exit(-1);
155        }
156
157        execle("/usr/bin/krb524init", "krb524init", NULL, envi);
158        syslog(LOG_ERR, "pam_krb524: execle(): %s", strerror(errno));
159        _exit(-1);
160    }
161    if (waitpid(pid, &status, 0) == -1) {
162        syslog(LOG_ERR, "pam_krb524: waitpid(): %s", strerror(errno));
163        return PAM_SESSION_ERR;
164    }
165    if (!WIFEXITED(status)) {
166        syslog(LOG_ERR, "pam_krb524: krb524init failed");
167        return PAM_SESSION_ERR;
168    }
169    if (debug)
170        syslog(LOG_DEBUG, "pam_krb524: Success: %s", cache_name4);
171
172    return PAM_SUCCESS;
173}
174
175
176/* Terminate session management. */
177int
178pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
179{
180    int i;
181    int pamret;
182    const char *cache_name;
183    char cache_name4[MAXBUF];
184    int debug = 0;
185
186    for (i = 0; i < argc; i++) {
187        if (strcmp(argv[i], "debug") == 0)
188            debug = 1;
189    }
190
191    if ((pamret = get_krb4_name(pamh, &cache_name, cache_name4, MAXBUF)) !=
192        PAM_SUCCESS)
193        return pamret;
194
195    if (debug)
196        syslog(LOG_DEBUG, "pam_krb524: Unlinking %s", cache_name4);
197    unlink(cache_name4);
198    return PAM_SUCCESS;
199}
200
201
202int
203pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
204{
205    if (flags == PAM_ESTABLISH_CRED)
206        return pam_sm_open_session(pamh, flags, argc, argv);
207    return PAM_SUCCESS;
208}
209
210int
211pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
212{
213    return PAM_SUCCESS;
214}
Note: See TracBrowser for help on using the repository browser.