openpam_dynamic.c revision 255364
1/*- 2 * Copyright (c) 2002-2003 Networks Associates Technology, Inc. 3 * Copyright (c) 2004-2011 Dag-Erling Sm��rgrav 4 * All rights reserved. 5 * 6 * This software was developed for the FreeBSD Project by ThinkSec AS and 7 * Network Associates Laboratories, the Security Research Division of 8 * Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 9 * ("CBOSS"), as part of the DARPA CHATS research program. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. The name of the author may not be used to endorse or promote 20 * products derived from this software without specific prior written 21 * permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * $Id: openpam_dynamic.c 607 2012-04-20 11:09:37Z des $ 36 */ 37 38#ifdef HAVE_CONFIG_H 39# include "config.h" 40#endif 41 42#include <dlfcn.h> 43#include <fcntl.h> 44#include <errno.h> 45#include <stdio.h> 46#include <stdlib.h> 47#include <string.h> 48#include <unistd.h> 49 50#include <security/pam_appl.h> 51 52#include "openpam_impl.h" 53 54#ifndef RTLD_NOW 55#define RTLD_NOW RTLD_LAZY 56#endif 57 58/* 59 * OpenPAM internal 60 * 61 * Perform sanity checks and attempt to load a module 62 */ 63 64#ifdef HAVE_FDLOPEN 65static void * 66try_dlopen(const char *modfn) 67{ 68 void *dlh; 69 int fd; 70 71 if ((fd = open(modfn, O_RDONLY)) < 0) 72 return (NULL); 73 if (OPENPAM_FEATURE(VERIFY_MODULE_FILE) && 74 openpam_check_desc_owner_perms(modfn, fd) != 0) { 75 close(fd); 76 return (NULL); 77 } 78 if ((dlh = fdlopen(fd, RTLD_NOW)) == NULL) { 79 openpam_log(PAM_LOG_ERROR, "%s: %s", modfn, dlerror()); 80 close(fd); 81 errno = 0; 82 return (NULL); 83 } 84 close(fd); 85 return (dlh); 86} 87#else 88static void * 89try_dlopen(const char *modfn) 90{ 91 int check_module_file; 92 void *dlh; 93 94 openpam_get_feature(OPENPAM_VERIFY_MODULE_FILE, 95 &check_module_file); 96 if (check_module_file && 97 openpam_check_path_owner_perms(modfn) != 0) 98 return (NULL); 99 if ((dlh = dlopen(modfn, RTLD_NOW)) == NULL) { 100 openpam_log(PAM_LOG_ERROR, "%s: %s", modfn, dlerror()); 101 errno = 0; 102 return (NULL); 103 } 104 return (dlh); 105} 106#endif 107 108/* 109 * OpenPAM internal 110 * 111 * Locate a dynamically linked module 112 */ 113 114pam_module_t * 115openpam_dynamic(const char *path) 116{ 117 const pam_module_t *dlmodule; 118 pam_module_t *module; 119 const char *prefix; 120 char *vpath; 121 void *dlh; 122 int i, serrno; 123 124 dlh = NULL; 125 126 /* Prepend the standard prefix if not an absolute pathname. */ 127 if (path[0] != '/') 128 prefix = OPENPAM_MODULES_DIR; 129 else 130 prefix = ""; 131 132 /* try versioned module first, then unversioned module */ 133 if (asprintf(&vpath, "%s%s.%d", prefix, path, LIB_MAJ) < 0) 134 goto err; 135 if ((dlh = try_dlopen(vpath)) == NULL && errno == ENOENT) { 136 *strrchr(vpath, '.') = '\0'; 137 dlh = try_dlopen(vpath); 138 } 139 if (dlh == NULL) 140 goto err; 141 if ((module = calloc(1, sizeof *module)) == NULL) 142 goto buf_err; 143 if ((module->path = strdup(path)) == NULL) 144 goto buf_err; 145 module->dlh = dlh; 146 dlmodule = dlsym(dlh, "_pam_module"); 147 for (i = 0; i < PAM_NUM_PRIMITIVES; ++i) { 148 if (dlmodule) { 149 module->func[i] = dlmodule->func[i]; 150 } else { 151 module->func[i] = 152 (pam_func_t)dlsym(dlh, pam_sm_func_name[i]); 153 /* 154 * This openpam_log() call is a major source of 155 * log spam, and the cases that matter are caught 156 * and logged in openpam_dispatch(). This would 157 * be less problematic if dlerror() returned an 158 * error code so we could log an error only when 159 * dlsym() failed for a reason other than "no such 160 * symbol". 161 */ 162#if 0 163 if (module->func[i] == NULL) 164 openpam_log(PAM_LOG_DEBUG, "%s: %s(): %s", 165 path, pam_sm_func_name[i], dlerror()); 166#endif 167 } 168 } 169 FREE(vpath); 170 return (module); 171buf_err: 172 serrno = errno; 173 if (dlh != NULL) 174 dlclose(dlh); 175 FREE(module); 176 errno = serrno; 177err: 178 serrno = errno; 179 if (errno != 0) 180 openpam_log(PAM_LOG_ERROR, "%s: %m", vpath); 181 FREE(vpath); 182 errno = serrno; 183 return (NULL); 184} 185 186/* 187 * NOPARSE 188 */ 189