mirror of
git://git.gnu.org.ua/pam-modules.git
synced 2025-04-26 00:19:52 +03:00

* .gitmodules: Add wordsplit * configure.ac: Likewise. * lib/Makefile.am: Likewise. * lib/graypam.h (gray_expand_argv): Remove. (gray_expand_string): Change prototype. * lib/vartab.c (gray_expand_argv): Remove. (gray_expand_string): Rewrite using wordsplit. * pam_ldaphome/pam_ldaphome.c (import_public_key): Assume sshPublicKey as a default attribute. * pam_log/pam_log.c (_pam_parse): Take two return arguments. (echo): Use gray_expand_string. * pam_sql/pam_mysql.c: Update gray_expand_string usage. * pam_sql/pam_pgsql.c: Likewise. * pam_sql/pam_sql.c: Likewise. * pam_sql/pam_sql.h (gpam_sql_get_query): Change signature. * pam_umotd/pam_umotd.c (pam_sm_open_session): Update gray_expand_string usage.
304 lines
7.2 KiB
C
304 lines
7.2 KiB
C
/* This file is part of pam-modules.
|
||
Copyright (C) 2005-2020 Sergey Poznyakoff
|
||
|
||
This program is free software; you can redistribute it and/or modify it
|
||
under the terms of the GNU General Public License as published by the
|
||
Free Software Foundation; either version 3 of the License, or (at your
|
||
option) any later version.
|
||
|
||
This program is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
GNU General Public License for more details.
|
||
|
||
You should have received a copy of the GNU General Public License along
|
||
with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||
|
||
#include "pam_sql.h"
|
||
|
||
/* indicate the following groups are defined */
|
||
#define PAM_SM_AUTH
|
||
#define PAM_SM_SESSION
|
||
|
||
#define CNTL_AUTHTOK 0x0010
|
||
|
||
static int cntl_flags;
|
||
long gpam_sql_debug_level;
|
||
char *gpam_sql_config_file = SYSCONFDIR "/pam_sql.conf";
|
||
|
||
struct pam_opt pam_opt[] = {
|
||
{ PAM_OPTSTR(debug), pam_opt_long, &debug_level },
|
||
{ PAM_OPTSTR(debug), pam_opt_const, &debug_level, { 1 } },
|
||
{ PAM_OPTSTR(audit), pam_opt_const, &debug_level, { 100 } },
|
||
{ PAM_OPTSTR(waitdebug), pam_opt_null, NULL, { 0 },
|
||
gray_wait_debug_fun },
|
||
{ PAM_OPTSTR(use_authtok), pam_opt_bitmask, &cntl_flags,
|
||
{ CNTL_AUTHTOK } },
|
||
{ PAM_OPTSTR(config), pam_opt_string, &gpam_sql_config_file },
|
||
{ NULL }
|
||
};
|
||
|
||
static void
|
||
_pam_parse(int argc, const char **argv)
|
||
{
|
||
cntl_flags = 0;
|
||
debug_level = 0;
|
||
gpam_sql_config_file = SYSCONFDIR "/pam_sql.conf";
|
||
gray_log_init(0, gpam_sql_module_name, LOG_AUTHPRIV);
|
||
gray_parseopt(pam_opt, argc, argv);
|
||
}
|
||
|
||
|
||
static int
|
||
_pam_get_password(pam_handle_t *pamh, char **password, const char *prompt)
|
||
{
|
||
char *item, *token;
|
||
int retval;
|
||
struct pam_message msg[3], *pmsg[3];
|
||
struct pam_response *resp;
|
||
int i, replies;
|
||
|
||
DEBUG(90,("enter _pam_get_password"));
|
||
|
||
if (cntl_flags & CNTL_AUTHTOK) {
|
||
/*
|
||
* get the password from the PAM item
|
||
*/
|
||
retval = pam_get_item(pamh, PAM_AUTHTOK,
|
||
(const void **) &item);
|
||
if (retval != PAM_SUCCESS) {
|
||
/* very strange. */
|
||
_pam_log(LOG_ALERT,
|
||
"can't retrieve password item: %s",
|
||
pam_strerror(pamh, retval));
|
||
return retval;
|
||
} else if (item != NULL) {
|
||
*password = item;
|
||
item = NULL;
|
||
return PAM_SUCCESS;
|
||
} else
|
||
return PAM_AUTHTOK_RECOVER_ERR;
|
||
}
|
||
|
||
/*
|
||
* ask user for the password
|
||
*/
|
||
/* prepare to converse */
|
||
|
||
i = 0;
|
||
pmsg[i] = &msg[i];
|
||
msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
|
||
msg[i++].msg = (const void*)prompt;
|
||
replies = 1;
|
||
|
||
/* run conversation */
|
||
resp = NULL;
|
||
token = NULL;
|
||
retval = gray_converse(pamh, i, pmsg, &resp);
|
||
|
||
if (resp != NULL && resp[i - replies].resp) {
|
||
if (retval == PAM_SUCCESS) { /* a good conversation */
|
||
token = XSTRDUP(resp[i - replies].resp);
|
||
DEBUG(100,("app returned [%s]", token));
|
||
pam_set_item(pamh, PAM_AUTHTOK, token);
|
||
PAM_DROP_REPLY(resp, 1);
|
||
} else {
|
||
_pam_log(LOG_ERR, "conversation error: %s",
|
||
pam_strerror(pamh, retval));
|
||
}
|
||
|
||
} else {
|
||
retval = (retval == PAM_SUCCESS)
|
||
? PAM_AUTHTOK_RECOVER_ERR : retval;
|
||
}
|
||
|
||
if (retval == PAM_SUCCESS) {
|
||
/*
|
||
* keep password as data specific to this module. pam_end()
|
||
* will arrange to clean it up.
|
||
*/
|
||
retval = pam_set_data(pamh, "password",
|
||
(void *)token,
|
||
gray_cleanup_string);
|
||
if (retval != PAM_SUCCESS) {
|
||
_pam_log(LOG_CRIT,
|
||
"can't keep password: %s",
|
||
pam_strerror(pamh, retval));
|
||
gray_pam_delete(token);
|
||
} else {
|
||
*password = token;
|
||
token = NULL; /* break link to password */
|
||
}
|
||
} else {
|
||
_pam_log(LOG_ERR,
|
||
"unable to obtain a password: %s",
|
||
pam_strerror(pamh, retval));
|
||
}
|
||
|
||
DEBUG(90,("exit _pam_get_password: %d", retval));
|
||
return retval;
|
||
}
|
||
|
||
|
||
/* Configuration */
|
||
static struct gray_env *config_env;
|
||
|
||
char *
|
||
gpam_sql_find_config(const char *name)
|
||
{
|
||
return gray_env_get(config_env, name);
|
||
}
|
||
|
||
int
|
||
gpam_sql_check_boolean_config(const char *name, int defval)
|
||
{
|
||
const char *value = gpam_sql_find_config(name);
|
||
if (value)
|
||
defval = gray_boolean_true_p(value);
|
||
return defval;
|
||
}
|
||
|
||
|
||
int
|
||
gpam_sql_get_query(pam_handle_t *pamh, const char *name, int required,
|
||
char **retptr)
|
||
{
|
||
const char *query = gpam_sql_find_config(name);
|
||
int rc;
|
||
|
||
if (!query) {
|
||
if (required) {
|
||
_pam_log(LOG_ERR, "%s: %s not defined",
|
||
gpam_sql_config_file, name);
|
||
return PAM_AUTHINFO_UNAVAIL;
|
||
}
|
||
*retptr = NULL;
|
||
return PAM_SUCCESS;
|
||
}
|
||
|
||
rc = gray_expand_string(pamh, query, retptr);
|
||
if (rc != PAM_SUCCESS)
|
||
return rc;
|
||
return PAM_SUCCESS;
|
||
}
|
||
|
||
|
||
/* --- authentication management functions (only) --- */
|
||
|
||
PAM_EXTERN int
|
||
pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
|
||
{
|
||
const char *username;
|
||
char *password;
|
||
int retval = PAM_AUTH_ERR;
|
||
|
||
/* parse arguments */
|
||
_pam_parse(argc, argv);
|
||
|
||
/* Get the username */
|
||
retval = pam_get_user(pamh, &username, NULL);
|
||
if (retval != PAM_SUCCESS || !username) {
|
||
DEBUG(1, ("can not get the username"));
|
||
return PAM_SERVICE_ERR;
|
||
}
|
||
|
||
/* Get the password */
|
||
if (_pam_get_password(pamh, &password, "Password:"))
|
||
return PAM_SERVICE_ERR;
|
||
|
||
if (retval != PAM_SUCCESS) {
|
||
_pam_log(LOG_ERR, "Could not retrive user's password");
|
||
return PAM_SERVICE_ERR;
|
||
}
|
||
|
||
if (gray_env_read(gpam_sql_config_file, &config_env))
|
||
retval = PAM_SERVICE_ERR;
|
||
else {
|
||
char *query;
|
||
|
||
/* FIXME: This comment is needed to pacify
|
||
`make check-sql-config' in doc:
|
||
gpam_sql_find_config("passwd-query") */
|
||
retval = gpam_sql_get_query(pamh, "passwd-query", 1, &query);
|
||
if (retval == PAM_SUCCESS) {
|
||
retval = gpam_sql_verify_user_pass(pamh, password,
|
||
query);
|
||
free(query);
|
||
}
|
||
}
|
||
|
||
gray_env_free(config_env);
|
||
config_env = NULL;
|
||
|
||
switch (retval) {
|
||
case PAM_ACCT_EXPIRED:
|
||
_pam_log(LOG_NOTICE, "user '%s': account expired", username);
|
||
break;
|
||
case PAM_SUCCESS:
|
||
_pam_log(LOG_NOTICE, "user '%s' granted access", username);
|
||
break;
|
||
default:
|
||
_pam_log(LOG_NOTICE, "user '%s' failed to authenticate",
|
||
username);
|
||
}
|
||
|
||
return retval;
|
||
}
|
||
|
||
PAM_EXTERN int
|
||
pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
|
||
{
|
||
return PAM_SUCCESS;
|
||
}
|
||
|
||
static int
|
||
sql_session_mgmt(pam_handle_t *pamh, int flags,
|
||
int argc, const char **argv, const char *query_name)
|
||
{
|
||
int retval;
|
||
|
||
|
||
/* parse arguments */
|
||
_pam_parse(argc, argv);
|
||
|
||
if (gray_env_read(gpam_sql_config_file, &config_env))
|
||
retval = PAM_SERVICE_ERR;
|
||
else {
|
||
gray_slist_t slist;
|
||
char *query;
|
||
|
||
retval = gpam_sql_get_query(pamh, query_name, 0, &query);
|
||
if (retval == PAM_SUCCESS) {
|
||
if (query) {
|
||
retval = gpam_sql_acct(pamh, query);
|
||
free(query);
|
||
}
|
||
}
|
||
}
|
||
|
||
gray_env_free(config_env);
|
||
config_env = NULL;
|
||
|
||
return retval;
|
||
}
|
||
|
||
PAM_EXTERN int
|
||
pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
|
||
{
|
||
/* FIXME: This comment is needed to pacify `make check-sql-config'
|
||
in doc:
|
||
gpam_sql_find_config("session-start-query") */
|
||
return sql_session_mgmt(pamh, flags, argc, argv,
|
||
"session-start-query");
|
||
}
|
||
|
||
PAM_EXTERN int
|
||
pam_sm_close_session(pam_handle_t *pamh, int flags,
|
||
int argc, const char **argv)
|
||
{
|
||
/* FIXME: This comment is needed to pacify `make check-sql-config'
|
||
in doc:
|
||
gpam_sql_find_config("session-stop-query") */
|
||
return sql_session_mgmt(pamh, flags, argc, argv,
|
||
"session-stop-query");
|
||
}
|