openpam_load.c revision 116520
191094Sdes/*-
2115619Sdes * Copyright (c) 2002-2003 Networks Associates Technology, Inc.
391094Sdes * All rights reserved.
491094Sdes *
591094Sdes * This software was developed for the FreeBSD Project by ThinkSec AS and
699158Sdes * Network Associates Laboratories, the Security Research Division of
799158Sdes * Network Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
899158Sdes * ("CBOSS"), as part of the DARPA CHATS research program.
991094Sdes *
1091094Sdes * Redistribution and use in source and binary forms, with or without
1191094Sdes * modification, are permitted provided that the following conditions
1291094Sdes * are met:
1391094Sdes * 1. Redistributions of source code must retain the above copyright
1491094Sdes *    notice, this list of conditions and the following disclaimer.
1591094Sdes * 2. Redistributions in binary form must reproduce the above copyright
1691094Sdes *    notice, this list of conditions and the following disclaimer in the
1791094Sdes *    documentation and/or other materials provided with the distribution.
1891094Sdes * 3. The name of the author may not be used to endorse or promote
1991094Sdes *    products derived from this software without specific prior written
2091094Sdes *    permission.
2191094Sdes *
2291094Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2391094Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2491094Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2591094Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2691094Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2791094Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2891094Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2991094Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3091094Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3191094Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3291094Sdes * SUCH DAMAGE.
3391094Sdes *
34116520Sdes * $P4: //depot/projects/openpam/lib/openpam_load.c#20 $
3591094Sdes */
3691094Sdes
3791094Sdes#include <dlfcn.h>
3891094Sdes#include <stdlib.h>
3991094Sdes#include <string.h>
4091094Sdes
4191094Sdes#include <security/pam_appl.h>
4291094Sdes
4391094Sdes#include "openpam_impl.h"
4491094Sdes
45107937Sdesconst char *_pam_func_name[PAM_NUM_PRIMITIVES] = {
46107937Sdes	"pam_authenticate",
47107937Sdes	"pam_setcred",
48107937Sdes	"pam_acct_mgmt",
49107937Sdes	"pam_open_session",
50107937Sdes	"pam_close_session",
51107937Sdes	"pam_chauthtok"
52107937Sdes};
53107937Sdes
5491094Sdesconst char *_pam_sm_func_name[PAM_NUM_PRIMITIVES] = {
5591097Sdes	"pam_sm_authenticate",
5691097Sdes	"pam_sm_setcred",
5791094Sdes	"pam_sm_acct_mgmt",
5891097Sdes	"pam_sm_open_session",
5991094Sdes	"pam_sm_close_session",
6091097Sdes	"pam_sm_chauthtok"
6191094Sdes};
6291094Sdes
6391094Sdesstatic pam_module_t *modules;
6491094Sdes
6591094Sdes/*
6691684Sdes * Locate a matching dynamic or static module.  Keep a list of previously
6791684Sdes * found modules to speed up the process.
6891094Sdes */
6991094Sdes
70115619Sdespam_module_t *
7191094Sdesopenpam_load_module(const char *path)
7291094Sdes{
7391094Sdes	pam_module_t *module;
7491094Sdes
7591094Sdes	/* check cache first */
7691094Sdes	for (module = modules; module != NULL; module = module->next)
7791094Sdes		if (strcmp(module->path, path) == 0)
7891094Sdes			goto found;
7991094Sdes
8091094Sdes	/* nope; try to load */
8191684Sdes	module = openpam_dynamic(path);
8291094Sdes	openpam_log(PAM_LOG_DEBUG, "%s dynamic %s",
8391094Sdes	    (module == NULL) ? "no" : "using", path);
8491094Sdes
8591094Sdes#ifdef OPENPAM_STATIC_MODULES
8691094Sdes	/* look for a static module */
8791094Sdes	if (module == NULL && strchr(path, '/') == NULL) {
8891100Sdes		module = openpam_static(path);
8991094Sdes		openpam_log(PAM_LOG_DEBUG, "%s static %s",
9091094Sdes		    (module == NULL) ? "no" : "using", path);
9191094Sdes	}
9291094Sdes#endif
9391830Sdes	if (module == NULL) {
9491830Sdes		openpam_log(PAM_LOG_ERROR, "no %s found", path);
9591094Sdes		return (NULL);
9691830Sdes	}
9791830Sdes	openpam_log(PAM_LOG_DEBUG, "adding %s to cache", module->path);
9891094Sdes	module->next = modules;
9991830Sdes	if (module->next != NULL)
10091830Sdes		module->next->prev = module;
10191094Sdes	module->prev = NULL;
10291094Sdes	modules = module;
10391094Sdes found:
10491094Sdes	++module->refcount;
10591094Sdes	return (module);
10691094Sdes}
10791094Sdes
10891094Sdes
10991094Sdes/*
11091094Sdes * Release a module.
11191094Sdes * XXX highly thread-unsafe
11291094Sdes */
11391094Sdes
11491094Sdesstatic void
11591094Sdesopenpam_release_module(pam_module_t *module)
11691094Sdes{
11791094Sdes	if (module == NULL)
11891094Sdes		return;
11991094Sdes	--module->refcount;
12091094Sdes	if (module->refcount > 0)
12191094Sdes		/* still in use */
12291094Sdes		return;
12391094Sdes	if (module->refcount < 0) {
12491094Sdes		openpam_log(PAM_LOG_ERROR, "module %s has negative refcount",
12591094Sdes		    module->path);
12691094Sdes		module->refcount = 0;
12791094Sdes	}
12891094Sdes	if (module->dlh == NULL)
12991094Sdes		/* static module */
13091094Sdes		return;
13191094Sdes	dlclose(module->dlh);
13291094Sdes	if (module->prev != NULL)
13391094Sdes		module->prev->next = module->next;
13491094Sdes	if (module->next != NULL)
13591094Sdes		module->next->prev = module->prev;
13691830Sdes	if (module == modules)
13791830Sdes		modules = module->next;
13891830Sdes	openpam_log(PAM_LOG_DEBUG, "releasing %s", module->path);
139115619Sdes	FREE(module->path);
140115619Sdes	FREE(module);
14191094Sdes}
14291094Sdes
14391094Sdes
14491094Sdes/*
14591094Sdes * Destroy a chain, freeing all its links and releasing the modules
14691094Sdes * they point to.
14791094Sdes */
14891094Sdes
14991094Sdesstatic void
15091094Sdesopenpam_destroy_chain(pam_chain_t *chain)
15191094Sdes{
15291094Sdes	if (chain == NULL)
15391094Sdes		return;
15491094Sdes	openpam_destroy_chain(chain->next);
15591094Sdes	chain->next = NULL;
156116520Sdes	while (chain->optc) {
157116520Sdes		--chain->optc;
158115619Sdes		FREE(chain->optv[chain->optc]);
159116520Sdes	}
160115619Sdes	FREE(chain->optv);
16191094Sdes	openpam_release_module(chain->module);
162116520Sdes	chain->module = NULL;
163115619Sdes	FREE(chain);
16491094Sdes}
16591094Sdes
16691094Sdes
16791094Sdes/*
16891094Sdes * Clear the chains and release the modules
16991094Sdes */
17091094Sdes
17191094Sdesvoid
17295908Sdesopenpam_clear_chains(pam_chain_t *policy[])
17391094Sdes{
17491094Sdes	int i;
17591094Sdes
176115619Sdes	for (i = 0; i < PAM_NUM_FACILITIES; ++i)
17795908Sdes		openpam_destroy_chain(policy[i]);
17891094Sdes}
17991100Sdes
18091100Sdes/*
18191100Sdes * NOPARSE
18291100Sdes */
183