mirror of
git://git.gnu.org.ua/pam-modules.git
synced 2025-04-27 17:09:52 +03:00

* lib/Makefile.am (libgraypam_la_SOURCES): Add parseopt.c * lib/graypam.h (gray_parseopt, gray_wait_debug_fun): New functions (CNTL_DEBUG_LEV, CNTL_SET_DEBUG_LEV): Removed. * lib/log.c (gray_wait_debug): New functions. * pam_fshadow/pam_fshadow.c, pam_sql/pam_sql.c, pam_regex/pam_regex.c, pam_log/pam_log.c: Use gray_parseopt for command line parsing. git-svn-id: file:///svnroot/pam-modules/trunk@67 56984be4-0537-0410-a56c-fcb268c96130
369 lines
7.7 KiB
C
369 lines
7.7 KiB
C
/* This file is part of pam-modules.
|
||
Copyright (C) 2005, 2006, 2007, 2008 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 <graypam.h>
|
||
#if defined(HAVE_CRYPT_H)
|
||
# include <crypt.h>
|
||
#else
|
||
extern char *crypt(const char *, const char *);
|
||
#endif
|
||
|
||
/* indicate the following groups are defined */
|
||
#define PAM_SM_AUTH
|
||
|
||
#define CHKVAR(v) \
|
||
if (!(v)) { \
|
||
_pam_log(LOG_ERR, "%s: %s not defined", config_file, #v); \
|
||
return PAM_SERVICE_ERR; \
|
||
} \
|
||
DEBUG(100,("Config: %s=%s", #v, v));
|
||
|
||
static int verify_user_pass(const char *username, const char *password);
|
||
|
||
#define CNTL_AUTHTOK 0x0010
|
||
|
||
static int cntl_flags;
|
||
static long debug_level;
|
||
char *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_bitmask, &cntl_flags, CNTL_AUDIT },
|
||
{ 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_file), pam_opt_string, &config_file },
|
||
{ NULL }
|
||
};
|
||
|
||
static void
|
||
_pam_parse(int argc, const char **argv)
|
||
{
|
||
gray_log_init(0, 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(100,("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) {
|
||
if (retval == PAM_SUCCESS) { /* a good conversation */
|
||
token = XSTRDUP(resp[i - replies].resp);
|
||
DEBUG(10,("app returned [%s]", 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(100,("exit _pam_get_password: %d", retval));
|
||
return retval;
|
||
}
|
||
|
||
|
||
/* Configuration */
|
||
typedef struct config_env env_t;
|
||
struct config_env {
|
||
env_t *next;
|
||
char *name;
|
||
char *value;
|
||
};
|
||
static env_t *config_env;
|
||
|
||
/*
|
||
* Chop off trailing whitespace. Return length of the resulting string
|
||
*/
|
||
static int
|
||
chop(char *str)
|
||
{
|
||
int len;
|
||
|
||
for (len = strlen(str); len > 0 && isspace(str[len-1]); len--)
|
||
;
|
||
str[len] = 0;
|
||
return len;
|
||
}
|
||
|
||
char *
|
||
find_config(const char *name)
|
||
{
|
||
env_t *env;
|
||
|
||
for (env = config_env; env; env = env->next)
|
||
if (strcmp(env->name, name) == 0)
|
||
return env->value;
|
||
return NULL;
|
||
}
|
||
|
||
void
|
||
free_config()
|
||
{
|
||
env_t *env = config_env;
|
||
while (env) {
|
||
env_t *next = env->next;
|
||
free(env->name);
|
||
free(env);
|
||
env = next;
|
||
}
|
||
}
|
||
|
||
static int
|
||
boolean_true_p(const char *value)
|
||
{
|
||
return strcmp(value, "yes") == 0
|
||
|| strcmp(value, "true") == 0
|
||
|| strcmp(value, "t") == 0;
|
||
}
|
||
|
||
static int
|
||
check_boolean_config(const char *name, int defval)
|
||
{
|
||
const char *value = find_config(name);
|
||
if (value)
|
||
defval = boolean_true_p(value);
|
||
return defval;
|
||
}
|
||
|
||
static int
|
||
read_config ()
|
||
{
|
||
FILE *fp;
|
||
char *p;
|
||
int rc = 0;
|
||
int line = 0;
|
||
char buf[128];
|
||
|
||
fp = fopen (config_file, "r");
|
||
if (!fp) {
|
||
_pam_log(LOG_ERR, "cannot open configuration file `%s': %s",
|
||
config_file, strerror (errno));
|
||
return 1;
|
||
}
|
||
|
||
while (p = fgets (buf, sizeof buf, fp)) {
|
||
int len;
|
||
env_t *env;
|
||
|
||
line++;
|
||
while (*p && isspace(*p))
|
||
p++;
|
||
len = strlen(p);
|
||
if (len == 0)
|
||
continue;
|
||
if (p[len-1] != '\n') {
|
||
_pam_log(LOG_EMERG, "%s:%d: string too long",
|
||
config_file, line);
|
||
continue;
|
||
}
|
||
|
||
p[len-1] = 0;
|
||
chop(p);
|
||
|
||
if (*p == 0 || *p == '#')
|
||
continue;
|
||
|
||
env = malloc(sizeof *env);
|
||
if (!env) {
|
||
_pam_log(LOG_EMERG, "not enough memory");
|
||
rc = 1;
|
||
break;
|
||
}
|
||
|
||
env->name = strdup(p);
|
||
if (!env->name) {
|
||
_pam_log(LOG_EMERG, "not enough memory");
|
||
free(env);
|
||
rc = 1;
|
||
break;
|
||
}
|
||
|
||
for (p = env->name; *p && !isspace(*p); p++)
|
||
;
|
||
if (*p)
|
||
*p++ = 0;
|
||
for (; *p && isspace(*p); p++)
|
||
;
|
||
if (!*p) {
|
||
_pam_log(LOG_EMERG, "%s:%d: not enough fields",
|
||
config_file, line);
|
||
free(env->name);
|
||
free(env);
|
||
continue;
|
||
}
|
||
env->value = p;
|
||
env->next = config_env;
|
||
config_env = env;
|
||
}
|
||
|
||
fclose(fp);
|
||
return rc;
|
||
}
|
||
|
||
|
||
|
||
|
||
/* --- 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) {
|
||
_pam_log(LOG_DEBUG, "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 (read_config())
|
||
retval = PAM_SERVICE_ERR;
|
||
else
|
||
retval = verify_user_pass(username, password);
|
||
free_config();
|
||
|
||
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;
|
||
}
|
||
|
||
PAM_EXTERN
|
||
int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
|
||
int argc, const char **argv)
|
||
{
|
||
return PAM_SUCCESS;
|
||
}
|
||
|
||
#ifdef PAM_STATIC
|
||
|
||
/* static module data */
|
||
|
||
struct pam_module _pam_fshadow_modstruct = {
|
||
MODULE_NAME,
|
||
pam_sm_authenticate,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
};
|
||
|
||
#endif
|