/* This file is part of pam-modules.
Copyright (C) 2005-2008, 2010-2014 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/>. */
#ifdef HAVE__PAM_ACONF_H
# include <security/_pam_aconf.h>
#endif
#ifndef LINUX_PAM
# include <security/pam_appl.h>
#endif /* LINUX_PAM */
#include <security/pam_modules.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <ldap.h>
#include <pwd.h>
#include <grp.h>
#include "graypam.h"
/* indicate the following groups are defined */
#define PAM_SM_AUTH
static long debug_level;
static int cntl_flags;
static char *config_file_name;
static int ldap_debug_level;
/* FIXME: This should be read from sshd_config */
static char *authorized_keys_file=".ssh/authorized_keys";
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(config), pam_opt_string, &config_file_name },
{ NULL }
};
static void
_pam_parse(pam_handle_t *pamh, int argc, const char **argv)
{
cntl_flags = 0;
debug_level = 0;
config_file_name = SYSCONFDIR "/" MODULE_NAME ".conf";
gray_log_init(0, MODULE_NAME, LOG_AUTHPRIV);
gray_parseopt(pam_opt, argc, argv);
}
static void
argcv_free(int wc, char **wv)
{
int i;
for (i = 0; i < wc; i++)
free(wv[i]);
free(wv);
}
static void
argcvz_free(char **wv)
{
int i;
for (i = 0; wv[i]; i++)
free(wv[i]);
free(wv);
}
static int
argcv_split(const char *str, int *pargc, char ***pargv)
{
int argc, i;
char **argv;
const char *p;
int rc = 0;
argc = 1;
for (p = str; *p; p++) {
if (*p == ' ')
argc++;
}
argv = calloc(argc + 1, sizeof(argv[0]));
if (!argv)
return 1;
for (i = 0, p = str;;) {
size_t len = strcspn(p, " ");
char *q = malloc(len + 1);
if (!q) {
rc = errno;
break;
}
memcpy(q, p, len);
q[len] = 0;
argv[i++] = q;
p += len;
if (p)
p += strspn(p, " ");
if (!*p)
break;
}
if (rc) {
argcv_free(argc, argv);
errno = rc;
return 1;
}
argv[i] = NULL;
*pargc = argc;
*pargv = argv;
return 0;
}
static char *
argcv_concat(int wc, char **wv)
{
char *res, *p;
size_t size = 0;
int i;
for (i = 0; i < wc; i++)
size += strlen(wv[i]) + 1;
res = malloc(size);
if (!res)
return 0;
for (p = res, i = 0;;) {
strcpy(p, wv[i]);
p += strlen(wv[i]);
if (++i < wc)
*p++ = ' ';
else
break;
}
*p = 0;
return res;
}
static int
get_intval(struct gray_env *env, const char *name, int base, unsigned long *pv)
{
char *p;
char *v = gray_env_get(env, name);
if (!v)
return 1;
*pv = strtoul(v, &p, base);
if (*p) {
_pam_log(LOG_ERR, "configuration variable %s is not integer",
name);
return -1;
}
return 0;
}
char *
parse_ldap_uri(const char *uri)
{
int wc;
char **wv;
LDAPURLDesc *ludlist, **ludp;
char **urls = NULL;
int nurls = 0;
char *ldapuri = NULL;
int rc;
rc = ldap_url_parse(uri, &ludlist);
if (rc != LDAP_URL_SUCCESS) {
_pam_log(LOG_ERR, "cannot parse LDAP URL(s)=%s (%d)",
uri, rc);
return NULL;
}
for (ludp = &ludlist; *ludp; ) {
LDAPURLDesc *lud = *ludp;
char **tmp;
if (lud->lud_dn && lud->lud_dn[0]
&& (lud->lud_host == NULL ||
|