+++ /dev/null
-/*
- * Copyright 2000, International Business Machines Corporation and others.
- * All Rights Reserved.
- *
- * This software has been released under the terms of the IBM Public
- * License. For details, see the LICENSE file in the top-level source
- * directory or online at http://www.openafs.org/dl/license10.html
- */
-
-/*
- * This is a PAM module that calls setpag when creating a new session or
- * establishing credentials and then forks an external aklog program.
- * Eventually, it should call aklog inline without forking it.
- */
-
-#include <afsconfig.h>
-#include <afs/param.h>
-
-RCSID
- ("$Header$");
-
-#include <errno.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#include <security/pam_appl.h>
-#include <security/pam_modules.h>
-
-#include <kopenafs.h>
-
-/* This should really be set by the Makefile. */
-#ifndef AKLOG_PATH
-# define AKLOG_PATH "/usr/bin/aklog"
-#endif
-
-/* Warn about a problem. */
-#define WARN(A, B) \
- syslog(LOG_WARNING, "pam_afs_session: %s: %s", (A), (B));
-
-/* Log a debug message. */
-#define DLOG(A, B) \
- if (debug) \
- syslog(LOG_DEBUG, "pam_afs_session:%d: %s: %s", __LINE__, (A), (B))
-
-/*
- * We store in the PAM environment whether aklog has already been run by
- * setting afs_aklog. The value doesn't matter, but we need a pointer to use
- * as the data value.
- */
-static int afs_aklog_flag;
-
-
-/*
- * Given a cache template and a struct passwd, generate the cache environment
- * string and return it in newly allocated space.
- *
- * This is unfortunately necessary on HP-UX, since HP-UX's PAM implementation
- * apparently lacks any way to recover the KRB5CCNAME that's set in the PAM
- * environment; hence, this module has to be told how to reconstruct the
- * path.
- */
-static char *
-build_cache_env(const char *cache_template, struct passwd *pwd)
-{
- char *cache, *out;
- const char *p;
- char scratch[BUFSIZ];
- size_t length;
-
- length = 0;
- for (p = cache_template; *p != '\0'; p++) {
- if (*p == '%') {
- p++;
- if (*p == 'u') {
- sprintf(scratch, "%ld", (long) pwd->pw_uid);
- length += strlen(scratch);
- } else if (*p == 'p') {
- sprintf(scratch, "%ld", (long) getpid());
- length += strlen(scratch);
- } else {
- length++;
- }
- } else {
- length++;
- }
- }
- cache = malloc(length + strlen("KRB5CCNAME=") + 1);
- if (cache == NULL)
- return NULL;
- strcpy(cache, "KRB5CCNAME=");
- out = cache + strlen(cache);
- for (p = cache_template, out = cache; *p != '\0'; p++) {
- if (*p == '%') {
- p++;
- if (*p == 'u') {
- sprintf(out, "%ld", (long) pwd->pw_uid);
- out += strlen(out);
- } else if (*p == 'p') {
- sprintf(out, "%ld", (long) getpid());
- out += strlen(out);
- } else {
- *out = *p;
- out++;
- }
- } else {
- *out = *p;
- out++;
- }
- }
- return cache;
-}
-
-
-/*
- * Call aklog with the appropriate environment. Takes the PAM handle (so that
- * we can get the environment), the path to aklog, and the path to the ticket
- * cache (possibly a template). Returns a PAM status value.
- */
-static int
-run_aklog(pam_handle_t *pamh, const char *aklog, const char *cache_template)
-{
- int status, result;
- char *cache, scratch[BUFSIZ];
- char *username = NULL;
- char **env;
- struct passwd *pwd;
- pid_t child;
-
- DEBUG("run_aklog" "called");
-
- if (pam_get_item(pamh, PAM_USER, (void *) &username)) {
- status = PAM_SERVICE_ERR;
- goto done;
- }
- pwd = getpwnam(username);
- if (pwd == NULL) {
- status = PAM_USER_UNKNOWN;
- DEBUG("user unknown", username);
- goto done;
- }
-
- /*
- * HP-UX doesn't have pam_getenvlist, so for it we'll create a special
- * environment that contains only PATH and KRB5CCNAME.
- */
-#ifdef __hpux
- env = malloc(sizeof(char *) * 3);
- if (env == NULL) {
- status = PAM_SERVICE_ERR;
- goto done;
- }
- if (cache_template == NULL)
- cache_template = "FILE:/tmp/krb5cc_%u";
- cache = build_cache_path(cache_template, pwd);
- if (cache == NULL) {
- status = PAM_SERVICE_ERR;
- goto done;
- }
- env[0] = cache;
- env[1] = getenv("PATH");
- env[2] = NULL;
-#else
- env = pam_getenvlist(pamh);
-#endif
-
- /* Fork off a copy of aklog. */
- child = fork();
- if (child < 0) {
- status = PAM_SERVICE_ERR;
- goto done;
- } else if (child == 0) {
- if (setuid(pwd->pw_uid) < 0) {
- WARN("cannot setuid to user", strerror(errno));
- exit(1);
- }
- execle(aklog, aklog, NULL, env);
- WARN("cannot exec aklog", strerror(errno));
- exit(1);
- }
- if (waitpid(child, &result, 0) && WIFEXITED(result))
- status = PAM_SUCCESS;
- else
- status = PAM_SESSION_ERR;
-
-done:
- return status;
-}
-
-
-/*
- * Open a new session. Create a new PAG with k_setpag and then fork the aklog
- * binary as the user. A Kerberos v5 PAM module should have previously run to
- * obtain Kerberos tickets (or ticket forwarding should have already
- * happened).
- */
-int
-pam_sm_open_session(pam_handle_t *pamh, int flags, int argc,
- const char *argv[])
-{
- int i, status;
- int debug = 0, no_unlog = 0;
- int do_setpag = 1;
- const char *cache_template = NULL;
- const char *path = AKLOG_PATH;
-
- for (i = 0; i < argc; i++) {
- if (strcmp(argv[i], "debug") == 0)
- debug++;
- else if (strncmp(argv[i], "aklog=", strlen("aklog=")) == 0)
- path = &argv[i][strlen("aklog=")];
- else if (strcmp(argv[i], "nopag") == 0)
- do_setpag = 0;
- else if (strcmp(argv[i], "no_unlog") == 0)
- no_unlog = 1;
-#ifdef __hpux
- else if (strncmp(argv[i], "ccache=", strlen("ccache=")) == 0)
- cache_template = &argv[i][strlen("ccache=")];
-#endif
- else
- WARN("unknown option", argv[i]);
- }
-
- if (!k_hasafs()) {
- WARN("skipping AFS session initialization", "AFS not running");
- return PAM_SUCCESS;
- }
- if (do_setpag && k_setpag() != 0) {
- WARN("setpag failed", strerror(errno));
- return PAM_SESSION_ERR;
- }
- status = run_aklog(pamh, path, cache_template);
- if (status != PAM_SUCCESS)
- status = PAM_SESSION_ERR;
- return status;
-}
-
-
-/*
- * Don't do anything for authenticate. We're only an auth module so that we
- * can supply a pam_setcred implementation.
- */
-int
-pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
- const char *argv[])
-{
- return PAM_SUCCESS;
-}
-
-
-/*
- * Calling pam_setcred with PAM_ESTABLISH_CRED is equivalent to opening a new
- * session for our purposes. With PAM_REFRESH_CRED, we don't call setpag,
- * just run aklog again. PAM_DELETE_CRED calls unlog.
- */
-int
-pam_sm_setcred(pam_handle_t *pamh, int flags, int argc,
- const char *argv[])
-{
- int debug = 0, no_unlog = 0;
- int do_setpag = 1;
- int i, status;
- const char *cache_template = NULL;
- const char *path = AKLOG_PATH;
-
- for (i = 0; i < argc; i++) {
- if (strcmp(argv[i], "debug") == 0)
- debug++;
- else if (strncmp(argv[i], "aklog=", strlen("aklog=")) == 0)
- path = &argv[i][strlen("aklog=")];
- else if (strcmp(argv[i], "nopag") == 0)
- do_setpag = 0;
- else if (strcmp(argv[i], "no_unlog") == 0)
- no_unlog = 1;
-#ifdef __hpux
- else if (strncmp(argv[i], "ccache=", strlen("ccache=")) == 0)
- cache_template = &argv[i][strlen("ccache=")];
-#endif
- else
- WARN("unknown option", argv[i]);
- }
-
- if (!k_hasafs()) {
- WARN("skipping AFS session initialization", "AFS not running");
- return PAM_SUCCESS;
- }
- if (flags & PAM_DELETE_CRED) {
- if (k_unlog() != 0) {
- WARN("unable to delete credentials", strerror(errno));
- return PAM_CRED_ERR;
- }
- return PAM_SUCCESS;
- }
-
- if (flags & (PAM_REINITIALIZE_CRED | PAM_REFRESH_CRED))
- do_setpag = 0;
- if (do_setpag && k_setpag() != 0) {
- WARN("setpag failed", strerror(errno));
- return PAM_CRED_ERR;
- }
- status = run_aklog(pamh, path, cache_template);
- if (status != PAM_SUCCESS)
- status = PAM_CRED_ERR;
- return status;
-}
-
-
-/*
- * Close a session. Normally, what we do here is call unlog, but we can be
- * configured not to do so.
- */
-int
-pam_sm_close_session(pam_handle_t *pamh, int flags, int argc,
- const char *argv[])
-{
- int debug = 0, no_unlog = 0;
- int do_setpag = 1;
- int i;
- const char *cache_template = NULL;
- const char *path = AKLOG_PATH;
-
- for (i = 0; i < argc; i++) {
- if (strcmp(argv[i], "debug") == 0)
- debug++;
- else if (strncmp(argv[i], "aklog=", strlen("aklog=")) == 0)
- path = &argv[i][strlen("aklog=")];
- else if (strcmp(argv[i], "nopag") == 0)
- do_setpag = 0;
- else if (strcmp(argv[i], "no_unlog") == 0)
- no_unlog = 1;
-#ifdef __hpux
- else if (strncmp(argv[i], "ccache=", strlen("ccache=")) == 0)
- cache_template = &argv[i][strlen("ccache=")];
-#endif
- else
- WARN("unknown option", argv[i]);
- }
-
- if (!k_hasafs()) {
- WARN("skipping AFS session initialization", "AFS not running");
- return PAM_SUCCESS;
- }
- if (k_unlog() != 0) {
- WARN("unable to delete credentials", strerror(errno));
- return PAM_CRED_ERR;
- }
- return PAM_SUCCESS;
-}