2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A#include <secdb.h>
2N/A#include <user_attr.h>
2N/A#include <syslog.h>
2N/A#include <note.h>
2N/A#include <pwd.h>
2N/A#include <nss_dbdefs.h>
2N/A#include <libintl.h>
2N/A
2N/A#include <security/pam_appl.h>
2N/A#include <security/pam_modules.h>
2N/A#include <security/pam_impl.h>
2N/A
2N/A#define PAM_USER_POLICY_DATA "SUNW-PAM-USER-POLICY-DATA"
2N/A
2N/A/*
2N/A * Callback function for _enum_attrs() which looks for the 'pam_policy'
2N/A * keyword, passed in via the 'ctxt' argument, in any entries in the
2N/A * user_attr(4) database for this user or in any profiles granted to this
2N/A * user in the prof_attr(4) database or in policy.conf(4) which are
2N/A * passed in as key-value pair attributes in 'kva'.
2N/A */
2N/Astatic int
2N/Afind_pam_policy_cb(const char *profile, kva_t *kva, void *ctxt, void *result)
2N/A{
2N/A NOTE(ARGUNUSED(profile))
2N/A char *match;
2N/A
2N/A if ((match = kva_match(kva, (char *)ctxt)) != NULL) {
2N/A if (*match != '/') {
2N/A char *pam_policy;
2N/A
2N/A if ((strstr(match, "/") != NULL) ||
2N/A (strlen(match) >= MAXNAMELEN) ||
2N/A (*match == '\0')) {
2N/A __pam_log(LOG_AUTH | LOG_ERR,
2N/A "pam_user_policy: find_pam_policy_cb() "
2N/A "invalid path supplied: '%s'", match);
2N/A return (0);
2N/A }
2N/A (void) asprintf(&pam_policy, "%s%s", PAM_POLICY_DIR,
2N/A match);
2N/A *(char **)result = pam_policy;
2N/A } else {
2N/A *(char **)result = strdup(match);
2N/A }
2N/A return (1);
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Cleanup function for pam_set_data(3PAM) which is called from
2N/A * pam_end(3PAM) to free the memory allocated for 'pam_policy' which is
2N/A * stored here.
2N/A */
2N/Astatic void
2N/Apam_policy_data_cleanup(pam_handle_t *pamh, void *data, int pam_status)
2N/A{
2N/A NOTE(ARGUNUSED(pamh))
2N/A NOTE(ARGUNUSED(pam_status))
2N/A free(data);
2N/A}
2N/A
2N/A/*
2N/A * This is the common routine called by all of the PAM service module
2N/A * API routines (pam_sm(3PAM)) which implements the core of the
2N/A * pam_user_policy(5) functionality. We lookup a user's 'pam_policy' key in
2N/A * their user attributes or an assigned profile and then evaluate the
2N/A * pam.conf(4) formatted file pointed to by 'pam_policy' using pam_eval(3PAM).
2N/A * If no 'pam_policy' has been set for the user the default is 'unix'
2N/A * which uses UNIX for authentication, account management, session
2N/A * management, and password management. The value of 'pam_policy' is cached
2N/A * using pam_set_data(3PAM) so other modules in the same authentication
2N/A * transaction don't have to repeat the lookup.
2N/A */
2N/Astatic int
2N/Apam_user_policy_common(pam_handle_t *pamh, int flags, int argc,
2N/A const char **argv, const char *function_name)
2N/A{
2N/A int rval;
2N/A boolean_t debug = B_FALSE;
2N/A char *user;
2N/A struct passwd pwd;
2N/A char pwd_buf[NSS_BUFLEN_PASSWD];
2N/A char *pam_policy = NULL;
2N/A
2N/A if (argc > 0 && strcmp(argv[0], "debug") == 0) {
2N/A debug = B_TRUE;
2N/A }
2N/A
2N/A if (debug) {
2N/A __pam_log(LOG_AUTH | LOG_DEBUG,
2N/A "pam_user_policy: %s(flags = 0x%x, argc = %d)",
2N/A function_name, flags, argc);
2N/A }
2N/A
2N/A /*
2N/A * Get the value of PAM_USER; prompting if necessary when called
2N/A * by the authentication service module. This username is then
2N/A * used to look up that user's respective 'pam_policy' key in
2N/A * their user attributes.
2N/A */
2N/A if (strcmp(function_name, "pam_sm_authenticate") == 0) {
2N/A if ((rval = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) {
2N/A if (debug) {
2N/A __pam_log(LOG_AUTH | LOG_DEBUG,
2N/A "pam_user_policy: pam_get_user() failed: "
2N/A "%s", pam_strerror(pamh, rval));
2N/A }
2N/A return (rval);
2N/A }
2N/A } else {
2N/A (void) pam_get_item(pamh, PAM_USER, (void **)&user);
2N/A }
2N/A
2N/A if (user == NULL || *user == '\0') {
2N/A if (debug) {
2N/A __pam_log(LOG_AUTH | LOG_DEBUG,
2N/A "pam_user_policy: PAM_USER is NULL or empty");
2N/A }
2N/A return (PAM_IGNORE);
2N/A }
2N/A
2N/A if (getpwnam_r(user, &pwd, pwd_buf, sizeof (pwd_buf)) == NULL) {
2N/A if (debug) {
2N/A __pam_log(LOG_AUTH | LOG_DEBUG,
2N/A "pam_user_policy: unknown username '%s'", user);
2N/A }
2N/A return (PAM_IGNORE);
2N/A }
2N/A
2N/A /*
2N/A * Check if 'pam_policy' was looked up previously and stashed away
2N/A * successfully. Since the 'pam_policy' data is per-user we
2N/A * don't check for a previously saved copy unless the user has
2N/A * successfully authenticated.
2N/A */
2N/A if ((strcmp(function_name, "pam_sm_authenticate") != 0) &&
2N/A (pam_get_data(pamh, PAM_USER_POLICY_DATA,
2N/A (const void **)&pam_policy) == PAM_SUCCESS)) {
2N/A if (debug) {
2N/A __pam_log(LOG_AUTH | LOG_DEBUG, "pam_user_policy: "
2N/A "pam_get_data: pam_policy = %s for user '%s'",
2N/A pam_policy ? pam_policy : "NULL", user);
2N/A }
2N/A return (pam_eval(pamh, pam_policy));
2N/A }
2N/A
2N/A /*
2N/A * Walk the user_attr(4) and prof_attr(4) databases for this user's
2N/A * attributes and any profiles granted as well as profiles specified
2N/A * in policy.conf(4) for the 'pam_policy' keyword and store the value
2N/A * associated with that key, if any, in pam_policy_attr.pam_policy.
2N/A */
2N/A (void) _enum_attrs(user, find_pam_policy_cb, USERATTR_PAM_POLICY,
2N/A &pam_policy);
2N/A
2N/A if (debug) {
2N/A __pam_log(LOG_AUTH | LOG_DEBUG, "pam_user_policy: "
2N/A "find_pam_policy: pam_policy = %s for user '%s'",
2N/A pam_policy ? pam_policy : "NULL", user);
2N/A }
2N/A
2N/A /*
2N/A * Default to UNIX policy if no pam_policy key set for user.
2N/A * This is done by falling through to the rest of /etc/pam.conf
2N/A * which by default implements UNIX authentication.
2N/A */
2N/A if (pam_policy == NULL) {
2N/A return (PAM_IGNORE);
2N/A }
2N/A
2N/A /*
2N/A * Store the pam_policy in the pam handle in case there are
2N/A * additional pam_user_policy(5) modules configured in the stack
2N/A * for this PAM authentication transaction.
2N/A */
2N/A if ((rval = pam_set_data(pamh, PAM_USER_POLICY_DATA, pam_policy,
2N/A pam_policy_data_cleanup)) != PAM_SUCCESS) {
2N/A __pam_log(LOG_AUTH | LOG_ERR,
2N/A "pam_user_policy: pam_set_data() failed: %s",
2N/A pam_strerror(pamh, rval));
2N/A free(pam_policy);
2N/A return (PAM_SERVICE_ERR);
2N/A }
2N/A
2N/A return (pam_eval(pamh, pam_policy));
2N/A}
2N/A
2N/Aint
2N/Apam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv)
2N/A{
2N/A return (pam_user_policy_common(pamh, flags, argc, argv,
2N/A "pam_sm_acct_mgmt"));
2N/A}
2N/A
2N/Aint
2N/Apam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
2N/A{
2N/A return (pam_user_policy_common(pamh, flags, argc, argv,
2N/A "pam_sm_authenticate"));
2N/A}
2N/A
2N/Aint
2N/Apam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
2N/A{
2N/A return (pam_user_policy_common(pamh, flags, argc, argv,
2N/A "pam_sm_chauthtok"));
2N/A}
2N/A
2N/Aint
2N/Apam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
2N/A{
2N/A return (pam_user_policy_common(pamh, flags, argc, argv,
2N/A "pam_sm_open_session"));
2N/A}
2N/A
2N/Aint
2N/Apam_sm_close_session(pam_handle_t *pamh, int flags, int argc,
2N/A const char **argv)
2N/A{
2N/A return (pam_user_policy_common(pamh, flags, argc, argv,
2N/A "pam_sm_close_session"));
2N/A}
2N/A
2N/Aint
2N/Apam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
2N/A{
2N/A return (pam_user_policy_common(pamh, flags, argc, argv,
2N/A "pam_sm_setcred"));
2N/A}