pam_framework.c revision 2
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 * See the License for the specific language governing permissions 2N/A * and limitations under the License. 2N/A * When distributing Covered Code, include this CDDL HEADER in each 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 * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. 2N/A/* PAM_SERVICE */ "service",
2N/A/* PAM_USER */ "user",
2N/A/* PAM_RHOST */ "rhost",
2N/A/* PAM_CONV */ "conv",
2N/A/* PAM_AUTHTOK */ "authtok",
2N/A/* PAM_OLDAUTHTOK */ "oldauthtok",
2N/A/* PAM_RUSER */ "ruser",
2N/A/* PAM_USER_PROMPT */ "user_prompt",
2N/A/* PAM_REPOSITORY */ "repository",
2N/A/* PAM_RESOURCE */ "resource",
2N/A/* PAM_AUSER */ "auser",
2N/A/* Undefined Items */ 2N/A * This extra definition is needed in order to build this library 2N/A * on pre-64-bit-aware systems. 2N/A#
endif /* !defined(_LFS64_LARGEFILE) */ 2N/A/* functions to dynamically load modules */ 2N/A/* functions to read and store the pam.conf configuration file */ 2N/A/* functions to clean up and free memory */ 2N/A return (
"bad flag name");
2N/A * pam_settrace - setup configuration for pam tracing 2N/A * turn on PAM debug if "magic" file exists 2N/A * if exists (original), pam_debug = PAM_DEBUG_DEFAULT, 2N/A * log_priority = LOG_DEBUG(7) and log_facility = LOG_AUTH(4). 2N/A * if has contents, keywork=value pairs: 2N/A * "log_priority=" 0-7, the pam_trace syslog priority to use 2N/A * "log_facility=" 0-23, the pam_trace syslog facility to use 2N/A * "debug_flags=" PAM_DEBUG_DEFAULT (0x0001), log traditional 2N/A * (original) debugging. 2N/A * Plus the logical or of: 2N/A * PAM_DEBUG_ITEM (0x0002), log item values and 2N/A * PAM_DEBUG_MODULE (0x0004), log module return status. 2N/A * If compiled with DEBUG: 2N/A * PAM_DEBUG_AUTHTOK (0x8000), display AUTHTOK value if 2N/A * PAM_DEBUG_ITEM is set and results from 2N/A * PAM_PROMPT_ECHO_OFF responses. 2N/A * USE CAREFULLY, THIS EXPOSES THE USER'S PASSWORDS. 2N/A * or set to 0 and off even if PAM_DEBUG file exists. 2N/A * Output has the general form: 2N/A * <whatever was set syslog> PAM[<pid>]: <interface>(<handle> and other info) 2N/A * <whatever was set syslog> PAM[<pid>]: details requested for <interface> call 2N/A * Where: <pid> is the process ID of the calling process. 2N/A * <handle> is the Hex value of the pam_handle associated with the 2N/A * pam_trace - logs tracing messages 2N/A * format and args = message to print (PAM[<pid>]: is prepended). 2N/A * global log_priority = pam_trace syslog (log_priority | log_facility) 2N/A * __pam_log - logs PAM syslog messages 2N/A * priority = message priority 2N/A * format and args = message to log 2N/A * pam_XXXXX routines 2N/A * These are the entry points to the authentication switch 2N/A * pam_start - initiate an authentication transaction and 2N/A * set parameter values to be used during the 2N/A "pam_start(%s,%s,%p:%p) - debug = %x",
2N/A * pam_end - terminate an authentication transaction 2N/A "pam_end(%p): status = %s", (
void *)
pamh,
2N/A /* call the cleanup routines for module specific data */ 2N/A /* dlclose all module fds */ 2N/A /* remove all environment variables */ 2N/A * pam_set_item - set the value of a parameter that can be 2N/A * retrieved via a call to pam_get_item() 2N/A "pam_set_item(%p:%s)", (
void *)
pamh,
2N/A /* check read only items */ 2N/A * Check that item_type is within valid range 2N/A "pam_set_item(%p:%s)=%s", (
void *)
pamh,
2N/A "pam_set_item(%p:%s)=%s", (
void *)
pamh,
2N/A * pam_get_item - read the value of a parameter specified in 2N/A * the call to pam_set_item() 2N/A "a non module context",
2N/A "pam_get_item(%p:%s)=%s", (
void *)
pamh,
2N/A "pam_get_item(%p:%s)=%s", (
void *)
pamh,
2N/A * parse_user_name - process the user response: ignore 2N/A * '\t' or ' ' before or after a user name. 2N/A * user_input is a null terminated string. 2N/A * *ret_username will be the user name. 2N/A /* Set the default value for *ret_username */ 2N/A * Set the initial value for username - this is a buffer holds 2N/A * The user_input is guaranteed to be terminated by a null character. 2N/A /* Skip all the leading whitespaces if there are any. */ 2N/A * We should never get here since the user_input we got 2N/A * in pam_get_user() is not all whitespaces nor just "\0". 2N/A * username will be the first string we get from user_input 2N/A * - we skip leading whitespaces and ignore trailing whitespaces 2N/A /* ret_username will be freed in pam_get_user(). */ 2N/A * Get the value of PAM_USER. If not set, then use the convenience function 2N/A * to prompt for the user. Use prompt if specified, else use PAM_USER_PROMPT 2N/A * if it is set, else use default. 2N/A "pam_get_user(%p, %p, %s)", (
void *)
pamh, (
void *)*
user,
2N/A /* if the user is set, return it */ 2N/A * if the module is requesting a special prompt, use it. 2N/A * else use PAM_USER_PROMPT. 2N/A /* if the prompt is not set, use default */ 2N/A /* prompt for the user */ 2N/A /* essentially empty response, try again */ 2N/A /* Parse the user input to get the user name. */ 2N/A * finally, get PAM_USER. We have to call pam_get_item to get 2N/A * the value of user because pam_set_item mallocs the memory. 2N/A * Set module specific data 2N/A "pam_set_data(%p:%s:%d)=%p", (
void *)
pamh,
2N/A /* check if module data already exists */ 2N/A /* clean up original data before setting the new data */ 2N/A * get module specific data 2N/A "pam_get_data(%p:%s:%d)=%p", (
void *)
pamh,
2N/A "pam_get_data(%p:%s)=%p", (
void *)
pamh,
2N/A "PAM_NO_MODULE_DATA");
2N/A * PAM equivalent to strerror() 2N/A "Error in underlying service module"));
2N/A "Maximum number of attempts exceeded"));
2N/A "Can not retrieve authentication info"));
2N/A "Can not retrieve user credentials"));
2N/A "User credentials have expired"));
2N/A "Failure setting user credentials"));
2N/A "Authentication token manipulation error"));
2N/A "Authentication token can not be recovered"));
2N/A "Authentication token lock busy"));
2N/A "Authentication token aging disabled"));
2N/A "Module specific data not found"));
2N/A "Unable to complete operation. Try again"));
2N/A * Run through the PAM service module stack for the given module type. 2N/A * pam_eval(3PAM) calls run_stack() to evaluate a supplied PAM 2N/A * configuration file if pam_user_policy(5) is configured. On the 2N/A * first pass through run_stack() we stash away the passed in 2N/A * arguments so we can pass the same ones to run_stack() if called 2N/A * by pam_eval(3PAM) later. 2N/A * /etc/pam.d/<service> or an included PAM configuration file 2N/A * from pam_eval(3PAM) which is invoked by pam_user_policy(5). 2N/A * pam_config will be the path to a PAM configuration file if called 2N/A * from pam_eval(3PAM), otherwise it is NULL. 2N/A "no valid PAM configuration entries found in %s, " 2N/A "no valid PAM configuration entries found in %s",
2N/A /* save the return location */ 2N/A "setting for include[%d:%p]",
2N/A "run_stack: includes too deep %d " 2N/A "found trying to include %s from %s, %d " 2N/A "run_stack[%d:%s]: can't open included " 2N/A "conf %s or no valid PAM configuration " 2N/A "entries for %s were found in %s",
2N/A /* first line another include */ 2N/A "[%d:%s]:%s(%p, %x): load_modules failed",
2N/A "[%d:%s]:%s(%p, %x): load_modules failed",
2N/A "[%d:%s]:%s(%p, %x): %s returned %s",
2N/A "[%d:%s]:%s(%p, %x): %s: success",
2N/A * We need to return immediately, and 2N/A * we shouldn't reset the AUTHTOK item 2N/A * since it is not an error per-se. 2N/A "[%d:%s]:%s(%p, %x): TRY_AGAIN: %s",
2N/A "[%d:%s]:%s(%p, %x): %s: %s",
2N/A "[%d:%s]:%s(%p, %x): error %s",
2N/A /* continue at next entry */ 2N/A * All done at whatever depth we're at. 2N/A * pam_authenticate - authenticate a user 2N/A * pam_setcred - modify or retrieve user credentials 2N/A * pam_acct_mgmt - check password aging, account expiration 2N/A * pam_open_session - begin session management 2N/A * pam_close_session - terminate session management 2N/A * pam_chauthtok - change user authentication token 2N/A /* do not let apps use PAM_PRELIM_CHECK or PAM_UPDATE_AUTHTOK */ 2N/A /* 1st pass: PRELIM CHECK */ 2N/A "pam_chauthtok-prelim");
2N/A /* 2nd pass: UPDATE AUTHTOK */ 2N/A "pam_chauthtok-update");
2N/A * pam_putenv - add an environment variable to the PAM handle 2N/A * if name_value == 'NAME=VALUE' then set variable to the value 2N/A * if name_value == 'NAME=' then set variable to an empty value 2N/A * if name_value == 'NAME' then delete the variable 2N/A "pam_putenv(%p, %s)", (
void *)
pamh,
2N/A /* see if we were passed 'NAME=VALUE', 'NAME=', or 'NAME' */ 2N/A sizeof (
char))) == 0) {
2N/A /* check to see if we already have this variable in the PAM handle */ 2N/A /* remove the env variable */ 2N/A /* set env variable to empty value */ 2N/A /* set the new value */ 2N/A * could not find a match in the PAM handle. 2N/A * add the new value if there is one 2N/A /* new head of list */ 2N/A /* adding to end of list */ 2N/A * pam_getenv - retrieve an environment variable from the PAM handle 2N/A /* check to see if we already have this variable in the PAM handle */ 2N/A * pam_getenvlist - retrieve all environment variables from the PAM handle 2N/A * in a NULL terminated array. On error, return NULL. 2N/A "pam_getenvlist(%p)", (
void *)
pamh);
2N/A /* find out how many environment variables we have */ 2N/A /* allocate the array we will return to the caller */ 2N/A /* add the variables one by one */ 2N/A /* free the partially constructed list */ 2N/A /* a missing pam.conf-formatted file or an empty path is an error */ 2N/A "an empty or missing path");
2N/A * pam_eval() can only be called by PAM service provider (pam_sm_*) 2N/A * routines (viz. from a module context). 2N/A "a non module context");
2N/A * It doesn't make sense for pam_eval() to be called more than 2N/A * once in a single transaction so any attempts to do so are denied. 2N/A "pam_eval(): nested pam_user_policy(5) modules aren't " 2N/A "valid. pam_user_policy(5) referenced a second time in: " 2N/A * The pathname argument to pam_eval(3PAM), which points to a 2N/A * pam.conf(4)-formatted 'pam_policy' file, must be an absolute 2N/A * pathname. pam_user_policy(5) qualifies the pathnames it 2N/A * processes by prepending PAM_POLICY_DIR 2N/A * Verify the PAM configuration file exists. Further stringency 2N/A * checks such as permissions, ownership, size, and contents happen 2N/A * later on. We check that the filename exists here so we can 2N/A * report the precise root cause since open(2) failures in 2N/A * open_pam_conf() aren't syslogged since this is a common 2N/A * is frequently missing. 2N/A "pam_eval() PAM configuration file '%s' does not exist",
2N/A * Inside run_stack() further include directives may be processed 2N/A * so set a marker here so that we only "pop" includes added after 2N/A * this call to pam_eval() and not any includes added before. 2N/A * Routines to load a requested module on demand 2N/A * load_modules - load the requested module. 2N/A * if the dlopen or dlsym fail, then 2N/A * the module is ignored. 2N/A "while load_modules[%d:%s](%p, %s)=%s",
2N/A "done load_modules[%d:%s](%p, %s)=%s",
2N/A /* if the function has already been loaded, return */ 2N/A /* function has not been loaded yet */ 2N/A /* if open_module fails, return error */ 2N/A "load_modules[%d:%s]: can not open module " 2N/A /* load the authentication function */ 2N/A /* return error if dlsym fails */ 2N/A /* load the setcred function */ 2N/A /* return error if dlsym fails */ 2N/A * If functions are added to the account module, 2N/A * verify that one of the other functions hasn't 2N/A * already loaded it. See PAM_AUTH_MODULE code. 2N/A /* if open_module fails, return error */ 2N/A "load_modules[%d:%s]: can not open module " 2N/A "load_modules[%d:%s]: pam_sm_acct_mgmt() " 2N/A /* if open_module fails, return error */ 2N/A "load_modules[%d:%s]: can not open module " 2N/A * If functions are added to the password module, 2N/A * verify that one of the other functions hasn't 2N/A * already loaded it. See PAM_AUTH_MODULE code. 2N/A /* if open_module fails, continue */ 2N/A "load_modules[%d:%s]: can not open module " 2N/A "load_modules[%d:%s](%p, %s): unsupported type %d",
2N/A * open_module - Open the module first checking for 2N/A * propers modes and ownerships on the file. 2N/A /* Check the ownership and file modes */ 2N/A "open_module[%d:%s]: stat(%s) failed: %s",
2N/A "open_module[%d:%s]: Owner of the module %s is not root",
2N/A "open_module[%d:%s]: module %s writable by group",
2N/A "open_module[%d:%s]: module %s writable by world",
2N/A * Perform the dlopen() 2N/A /* add this fd to the pam handle */ 2N/A /* adding new head of list */ 2N/A /* appending to end of list */ 2N/A * load_function - call dlsym() to resolve the function address 2N/A "load_function: successful load of %s",
name);
2N/A * open_pam_conf - open the PAM configuration file which may be in 2N/A * either the traditional pam.conf(4) syntax or the per-service 2N/A * field for the 'service' isn't pressent. 2N/A * When looking up a per-service PAM policy file in /etc/pam.d the 2N/A * 'config' argument to read_pam_conf() is NULL. In such cases, we 2N/A * walk through the /etc/pam.d directory using readdir(3C) to find a 2N/A * case-insensitive match of a pam.d/<service> file to the current 2N/A * service name (the named service is passed in first and if no match 2N/A * is found "other" is passed in as the service name). This is to 2N/A * maintain the same behaviour of pam.conf(4) where service names are 2N/A "open_pam_conf[%d:%s/%s]: " 2N/A "couldn't open directory %s: %s",
2N/A "open_pam_conf[%d:%s/%s]: failed to find: " 2N/A "open_pam_conf[%d:%s]: open(%s) failed: %s",
2N/A /* Check the ownership and file modes; confirm it's a regular file */ 2N/A "open_pam_conf[%d:%s]: stat(%s) failed: %s",
2N/A "open_pam_conf[%d:%s]: %s is not a regular file",
2N/A "open_pam_conf[%d:%s]: %s has a size of zero",
2N/A "open_pam_conf[%d:%s]: Owner of %s is not root",
2N/A "open_pam_conf[%d:%s]: %s writable by group",
2N/A "open_pam_conf[%d:%s]: %s writable by world",
2N/A * default run_stack() scenario, no pam_eval(3PAM) or 'include' 2N/A * directives involved. The search order is as follows: 2N/A * which retains backwards compatbility with pam.conf(4) and 2N/A * also allows per-service /etc/pam.d/ files to work as well. 2N/A * A specific PAM configuration file is being processed due to 2N/A * either pam_eval(3PAM) or an 'include' directive. The 2N/A * included file could have either the pam.conf(4) syntax with 2N/A * the 'service' name present or the per-service /etc/pam.d 2N/A * syntax with the 'service' name omitted. Thus we look for 2N/A * PAM entries for the specified service and the 'other' 2N/A * service using both formats. 2N/A * read_pam_conf - read in each entry in pam.conf and store info 2N/A * under the pam handle. 2N/A * error (-1), "auth" (0), "account" (1), "session" (2), "password" (3) 2N/A /* See if entry is this service and valid */ 2N/A "read_pam_conf[%d:%s](%p): bad entry error %s",
2N/A "read_pam_conf[%d:%s](%p): processing %s",
2N/A /* process first service entry */ 2N/A /* purge "other" entries */ 2N/A "read_pam_conf(%p): purging " 2N/A "\"other\"[%d:%s][%s]",
2N/A /* add first service entry */ 2N/A "read_pam_conf(%p): adding 1st " 2N/A /* append more service entries */ 2N/A "read_pam_conf(%p): adding more " 2N/A /* irrelevant entry */ 2N/A /* no entry found for the specified service module type */ 2N/A "service = %s type = %d pam.d = %d error = %d", i,
2N/A /* copy full line for error reporting */ 2N/A /* get service name (e.g. login, su, passwd) */ 2N/A * pam_eval(3PAM) and the 'include' directive may reference 2N/A * per-service format of /etc/pam.d files so both are checked. 2N/A * The pam.conf(4) format is checked first so when looking for 2N/A * pam.conf(4) syntax and no service entry is present stop 2N/A * searching using pam.conf(4) syntax. This avoids syslog'ing 2N/A /* get module type (e.g. authentication, acct mgmt) */ 2N/A * If the token read isn't a PAM service module type then it is 2N/A * an error. However since we support both the pam.conf(4) 2N/A * format and the pam.d format for included PAM configs and PAM 2N/A * policy files specified for pam_eval() we handle the case of 2N/A * a partial PAM policy file here in pam.conf syntax but 2N/A * searching using pam.d syntax by skipping the first token 2N/A * which should be the PAM_SERVICE and then continuing with the 2N/A * format verification of the rest of the line. 2N/A /* get pam flag (e.g., requisite, required, sufficient, optional) */ 2N/A "illegal pam.conf[%s] entry: %s: missing CONTROL FLAG",
2N/A "\tinvalid control flag: %s",
arg);
2N/A * If module path does not start with "/", then 2N/A /* sizeof (PAM_LIB_DIR) has room for '\0' */ 2N/A /* Full path provided for module */ 2N/A /* Check for Instruction Set Architecture indicator */ 2N/A /* substitute the architecture dependent path */ 2N/A "strdup: out of memory");
2N/A /* count the number of module-specific options first */ 2N/A /* allocate array for the module-specific options */ 2N/A /* on error free this */ 2N/A * read_next_token - skip tab and space characters and return the next token 2N/A * nextline - skip all blank lines and comments 2N/A * Skip the blank line, comment line 2N/A /* if we are at the end of the buffer, there is no next line */ 2N/A /* skip blank line */ 2N/A * If we are at the end of the buffer, there is 2N/A /* else we check *bufferp again */ 2N/A /* skip comment line */ 2N/A * this comment line the last line. 2N/A * If we are at the end of the buffer, there is 2N/A /* now we find one line */ 2N/A * verify_pam_conf - verify that the pam_conf entry is filled in. 2N/A * True = Error if there is no service. 2N/A * True = Error if there is a service and it matches the requested service 2N/A * but, the type, flag, line overflow, or path is in error. 2N/A * Routines to free allocated storage 2N/A * clean_up - free allocated storage in the pam handle 2N/A /* Cleanup PAM_REPOSITORY structure */ 2N/A * free_pamconf - free memory used to store pam.conf entry 2N/A * free_pam_conf_info - free memory used to store all pam.conf info 2N/A * under the pam handle 2N/A * Internal convenience functions for Solaris PAM service modules. 2N/A * free storage for responses used in the call back "pam_conv" functions 2N/A /* clear before freeing -- may be a password */ 2N/A * When pam_set_item() is called to set PAM_CONV and the 2N/A * item is NULL, memset(pip->pi_addr, 0, size) is called. 2N/A * So at this point, we should check whether pam_convp->conv 2N/A * fill out the message structure to display prompt message 2N/A "pam_conv_msg(%p:%d[%d]=%s)",
2N/A * The UNIX pam modules always calls __pam_get_authtok() and 2N/A * __pam_display_msg() with a NULL pointer as the conv_apdp. 2N/A * In case the conv_apdp is NULL and the pam_convp->appdata_ptr 2N/A * is not NULL, we should pass the pam_convp->appdata_ptr 2N/A * to the conversation function. 2N/A * Call conv function to display the prompt. 2N/A "pam_conv_resp(%p pam_conv = %s) ret_respp = %p",
2N/A "pam_conv_resp(%p No response requested)", (
void *)
pamh);
2N/A "[%d] NULL response string)",
2N/A "pam_conv_resp(%p:[%d] len=%lu, " 2N/A "code=%d too long)",
2N/A "pam_conv_resp(%p:[%d]=%s, " 2N/A "pam_conv_resp(%p:[%d] len=%lu, " 2N/A "pam_conv_resp(%p:[%d]=%s, " 2N/A * __pam_display_msg(): 2N/A * display message by calling the call back functions 2N/A * provided by the application through "pam_conv" structure 2N/A * __pam_get_authtok() 2N/A * retrieves a password of at most PASS_MAX length from the pam 2N/A * handle (pam_get_item) or from the input stream (do_conv). 2N/A * This function allocates memory for the new authtok. 2N/A * Applications calling this function are responsible for 2N/A * freeing this memory. 2N/A * PAM_AUTHTOK - password is taken from pam handle (PAM_AUTHTOK) 2N/A * PAM_OLDAUTHTOK - password is taken from pam handle (PAM_OLDAUTHTOK) 2N/A * 0: Prompt for new passwd, do not even attempt 2N/A * to store it in the pam handle. 2N/A * PAM_AUTHTOK: Prompt for new passwd, store in pam handle as 2N/A * PAM_AUTHTOK item if this value is not already set. 2N/A * PAM_OLDAUTHTOK: Prompt for new passwd, store in pam handle as 2N/A * PAM_OLDAUTHTOK item if this value is not 2N/A /* get password from pam handle item list */ 2N/A "__pam_get_authtok() invalid type: %d",
type);
2N/A * Prompt for new password and save in pam handle item list 2N/A * if the that item is not already set. 2N/A /* getpass didn't return anything */ 2N/A /* save the new password if this item was NULL */ 2N/A "__pam_get_authtok() invalid source: %d",
source);