|
Packit |
5f9837 |
/*
|
|
Packit |
5f9837 |
* Copyright (C) 2013 Orion Poplawski <orion@cora.nwra.com>
|
|
Packit |
5f9837 |
*
|
|
Packit |
5f9837 |
* based on gkr-pam-module.c, Copyright (C) 2007 Stef Walter
|
|
Packit |
5f9837 |
*
|
|
Packit |
5f9837 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
5f9837 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
5f9837 |
* the Free Software Foundation; either version 3 of the License, or
|
|
Packit |
5f9837 |
* (at your option) any later version.
|
|
Packit |
5f9837 |
*
|
|
Packit |
5f9837 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
5f9837 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
5f9837 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
5f9837 |
* GNU General Public License for more details.
|
|
Packit |
5f9837 |
*
|
|
Packit |
5f9837 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
5f9837 |
* along with this program; if not, write to the Free Software
|
|
Packit |
5f9837 |
*/
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
5f9837 |
#include "config.h"
|
|
Packit |
5f9837 |
#endif /* HAVE_CONFIG_H */
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
#include <assert.h>
|
|
Packit |
5f9837 |
#include <errno.h>
|
|
Packit |
5f9837 |
#include <stdio.h>
|
|
Packit |
5f9837 |
#include <stdlib.h>
|
|
Packit |
5f9837 |
#include <string.h>
|
|
Packit |
5f9837 |
#include <syslog.h>
|
|
Packit |
5f9837 |
#include <sys/types.h>
|
|
Packit |
5f9837 |
/*
|
|
Packit |
5f9837 |
#include <signal.h>
|
|
Packit |
5f9837 |
#include <unistd.h>
|
|
Packit |
5f9837 |
#include <sys/wait.h>
|
|
Packit |
5f9837 |
*/
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
#include <keyutils.h>
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
#include <security/pam_appl.h>
|
|
Packit |
5f9837 |
#include <security/pam_modules.h>
|
|
Packit |
5f9837 |
#include <security/pam_ext.h>
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
#include "cifskey.h"
|
|
Packit |
5f9837 |
#include "mount.h"
|
|
Packit |
5f9837 |
#include "resolve_host.h"
|
|
Packit |
5f9837 |
#include "util.h"
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/**
|
|
Packit |
5f9837 |
* Flags that can be passed to the PAM module
|
|
Packit |
5f9837 |
*/
|
|
Packit |
5f9837 |
enum {
|
|
Packit |
5f9837 |
ARG_DOMAIN = 1 << 0, /** Set domain password */
|
|
Packit |
5f9837 |
ARG_DEBUG = 1 << 1 /** Print debug messages */
|
|
Packit |
5f9837 |
};
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/**
|
|
Packit |
5f9837 |
* Parse the arguments passed to the PAM module.
|
|
Packit |
5f9837 |
*
|
|
Packit |
5f9837 |
* @param ph PAM handle
|
|
Packit |
5f9837 |
* @param argc number of arguments
|
|
Packit |
5f9837 |
* @param argv array of arguments
|
|
Packit |
5f9837 |
* @param kwalletopener kwalletopener argument, path to the kwalletopener binary
|
|
Packit |
5f9837 |
* @return ORed flags that have been parsed
|
|
Packit |
5f9837 |
*/
|
|
Packit |
5f9837 |
static uint parse_args (pam_handle_t *ph, int argc, const char **argv, const char **hostdomain)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
uint args = 0;
|
|
Packit |
5f9837 |
const void *svc;
|
|
Packit |
5f9837 |
int i;
|
|
Packit |
5f9837 |
const char *host = NULL;
|
|
Packit |
5f9837 |
const char *domain = NULL;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
svc = NULL;
|
|
Packit |
5f9837 |
if (pam_get_item (ph, PAM_SERVICE, &svc) != PAM_SUCCESS) {
|
|
Packit |
5f9837 |
svc = NULL;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
size_t host_len = strlen("host=");
|
|
Packit |
5f9837 |
size_t domain_len = strlen("domain=");
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* Parse the arguments */
|
|
Packit |
5f9837 |
for (i = 0; i < argc; i++) {
|
|
Packit |
5f9837 |
if (strncmp(argv[i], "host=", host_len) == 0) {
|
|
Packit |
5f9837 |
host = (argv[i]) + host_len;
|
|
Packit |
5f9837 |
if (*host == '\0') {
|
|
Packit |
5f9837 |
host = NULL;
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, ""
|
|
Packit |
5f9837 |
"host= specification missing argument");
|
|
Packit |
5f9837 |
} else {
|
|
Packit |
5f9837 |
*hostdomain = host;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
} else if (strncmp(argv[i], "domain=", domain_len) == 0) {
|
|
Packit |
5f9837 |
domain = (argv[i]) + domain_len;
|
|
Packit |
5f9837 |
if (*domain == '\0') {
|
|
Packit |
5f9837 |
domain = NULL;
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, ""
|
|
Packit |
5f9837 |
"domain= specification missing argument");
|
|
Packit |
5f9837 |
} else {
|
|
Packit |
5f9837 |
*hostdomain = domain;
|
|
Packit |
5f9837 |
args |= ARG_DOMAIN;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
} else if (strcmp(argv[i], "debug") == 0) {
|
|
Packit |
5f9837 |
args |= ARG_DEBUG;
|
|
Packit |
5f9837 |
} else {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, "invalid option %s",
|
|
Packit |
5f9837 |
argv[i]);
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (host && domain) {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, "cannot specify both host= and "
|
|
Packit |
5f9837 |
"domain= arguments");
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return args;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static void
|
|
Packit |
5f9837 |
free_password (char *password)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
volatile char *vp;
|
|
Packit |
5f9837 |
size_t len;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (!password) {
|
|
Packit |
5f9837 |
return;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* Defeats some optimizations */
|
|
Packit |
5f9837 |
len = strlen (password);
|
|
Packit |
5f9837 |
memset (password, 0xAA, len);
|
|
Packit |
5f9837 |
memset (password, 0xBB, len);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* Defeats others */
|
|
Packit |
5f9837 |
vp = (volatile char*)password;
|
|
Packit |
5f9837 |
while (*vp) {
|
|
Packit |
5f9837 |
*(vp++) = 0xAA;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
free (password);
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
static void
|
|
Packit |
5f9837 |
cleanup_free_password (pam_handle_t *ph __attribute__((unused)), void *data,
|
|
Packit |
5f9837 |
int pam_end_status __attribute__((unused)))
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
free_password (data);
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/**
|
|
Packit |
5f9837 |
* Set the cifs credentials
|
|
Packit |
5f9837 |
*
|
|
Packit |
5f9837 |
* @param ph PAM handle
|
|
Packit |
5f9837 |
* @param user
|
|
Packit |
5f9837 |
* @param password
|
|
Packit |
5f9837 |
* @param args ORed flags for this module
|
|
Packit |
5f9837 |
* @param hostdomain hostname or domainname
|
|
Packit |
5f9837 |
*/
|
|
Packit |
5f9837 |
static int cifscreds_pam_add(pam_handle_t *ph, const char *user, const char *password,
|
|
Packit |
5f9837 |
uint args, const char *hostdomain)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
int ret = PAM_SUCCESS;
|
|
Packit |
5f9837 |
char addrstr[MAX_ADDR_LIST_LEN];
|
|
Packit |
5f9837 |
char *currentaddress, *nextaddress;
|
|
Packit |
5f9837 |
char keytype = ((args & ARG_DOMAIN) == ARG_DOMAIN) ? 'd' : 'a';
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
assert(user);
|
|
Packit |
5f9837 |
assert(password);
|
|
Packit |
5f9837 |
assert(hostdomain);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (keytype == 'd') {
|
|
Packit |
5f9837 |
if (strpbrk(hostdomain, DOMAIN_DISALLOWED_CHARS)) {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, "Domain name contains invalid characters");
|
|
Packit |
5f9837 |
return PAM_SERVICE_ERR;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
strlcpy(addrstr, hostdomain, MAX_ADDR_LIST_LEN);
|
|
Packit |
5f9837 |
} else {
|
|
Packit |
5f9837 |
ret = resolve_host(hostdomain, addrstr);
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
switch (ret) {
|
|
Packit |
5f9837 |
case EX_USAGE:
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, "Could not resolve address for %s", hostdomain);
|
|
Packit |
5f9837 |
return PAM_SERVICE_ERR;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
case EX_SYSERR:
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, "Problem parsing address list");
|
|
Packit |
5f9837 |
return PAM_SERVICE_ERR;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (strpbrk(user, USER_DISALLOWED_CHARS)) {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, "Incorrect username");
|
|
Packit |
5f9837 |
return PAM_SERVICE_ERR;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* search for same credentials stashed for current host */
|
|
Packit |
5f9837 |
currentaddress = addrstr;
|
|
Packit |
5f9837 |
nextaddress = strchr(currentaddress, ',');
|
|
Packit |
5f9837 |
if (nextaddress)
|
|
Packit |
5f9837 |
*nextaddress++ = '\0';
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
while (currentaddress) {
|
|
Packit |
5f9837 |
if (key_search(currentaddress, keytype) > 0) {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_WARNING, "You already have stashed credentials "
|
|
Packit |
5f9837 |
"for %s (%s)", currentaddress, hostdomain);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return PAM_SERVICE_ERR;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
switch(errno) {
|
|
Packit |
5f9837 |
case ENOKEY:
|
|
Packit |
5f9837 |
/* success */
|
|
Packit |
5f9837 |
break;
|
|
Packit |
5f9837 |
default:
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, "Unable to search keyring for %s (%s)",
|
|
Packit |
5f9837 |
currentaddress, strerror(errno));
|
|
Packit |
5f9837 |
return PAM_SERVICE_ERR;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
currentaddress = nextaddress;
|
|
Packit |
5f9837 |
if (currentaddress) {
|
|
Packit |
5f9837 |
*(currentaddress - 1) = ',';
|
|
Packit |
5f9837 |
nextaddress = strchr(currentaddress, ',');
|
|
Packit |
5f9837 |
if (nextaddress)
|
|
Packit |
5f9837 |
*nextaddress++ = '\0';
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* Set the password */
|
|
Packit |
5f9837 |
currentaddress = addrstr;
|
|
Packit |
5f9837 |
nextaddress = strchr(currentaddress, ',');
|
|
Packit |
5f9837 |
if (nextaddress)
|
|
Packit |
5f9837 |
*nextaddress++ = '\0';
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
while (currentaddress) {
|
|
Packit |
5f9837 |
key_serial_t key = key_add(currentaddress, user, password, keytype);
|
|
Packit |
5f9837 |
if (key <= 0) {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, "error: Add credential key for %s: %s",
|
|
Packit |
5f9837 |
currentaddress, strerror(errno));
|
|
Packit |
5f9837 |
} else {
|
|
Packit |
5f9837 |
if ((args & ARG_DEBUG) == ARG_DEBUG) {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_DEBUG, "credential key for \\\\%s\\%s added",
|
|
Packit |
5f9837 |
currentaddress, user);
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
if (keyctl(KEYCTL_SETPERM, key, CIFS_KEY_PERMS) < 0) {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR,"error: Setting permissons "
|
|
Packit |
5f9837 |
"on key, attempt to delete...");
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (keyctl(KEYCTL_UNLINK, key, DEST_KEYRING) < 0) {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, "error: Deleting key from "
|
|
Packit |
5f9837 |
"keyring for %s (%s)",
|
|
Packit |
5f9837 |
currentaddress, hostdomain);
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
currentaddress = nextaddress;
|
|
Packit |
5f9837 |
if (currentaddress) {
|
|
Packit |
5f9837 |
nextaddress = strchr(currentaddress, ',');
|
|
Packit |
5f9837 |
if (nextaddress)
|
|
Packit |
5f9837 |
*nextaddress++ = '\0';
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return PAM_SUCCESS;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/**
|
|
Packit |
5f9837 |
* Update the cifs credentials
|
|
Packit |
5f9837 |
*
|
|
Packit |
5f9837 |
* @param ph PAM handle
|
|
Packit |
5f9837 |
* @param user
|
|
Packit |
5f9837 |
* @param password
|
|
Packit |
5f9837 |
* @param args ORed flags for this module
|
|
Packit |
5f9837 |
* @param hostdomain hostname or domainname
|
|
Packit |
5f9837 |
*/
|
|
Packit |
5f9837 |
static int cifscreds_pam_update(pam_handle_t *ph, const char *user, const char *password,
|
|
Packit |
5f9837 |
uint args, const char *hostdomain)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
int ret = PAM_SUCCESS;
|
|
Packit |
5f9837 |
char addrstr[MAX_ADDR_LIST_LEN];
|
|
Packit |
5f9837 |
char *currentaddress, *nextaddress;
|
|
Packit |
5f9837 |
int id, count = 0;
|
|
Packit |
5f9837 |
char keytype = ((args & ARG_DOMAIN) == ARG_DOMAIN) ? 'd' : 'a';
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
assert(user);
|
|
Packit |
5f9837 |
assert(password);
|
|
Packit |
5f9837 |
assert(hostdomain);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (keytype == 'd') {
|
|
Packit |
5f9837 |
if (strpbrk(hostdomain, DOMAIN_DISALLOWED_CHARS)) {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, "Domain name contains invalid characters");
|
|
Packit |
5f9837 |
return PAM_SERVICE_ERR;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
strlcpy(addrstr, hostdomain, MAX_ADDR_LIST_LEN);
|
|
Packit |
5f9837 |
} else {
|
|
Packit |
5f9837 |
ret = resolve_host(hostdomain, addrstr);
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
switch (ret) {
|
|
Packit |
5f9837 |
case EX_USAGE:
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, "Could not resolve address for %s", hostdomain);
|
|
Packit |
5f9837 |
return PAM_SERVICE_ERR;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
case EX_SYSERR:
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, "Problem parsing address list");
|
|
Packit |
5f9837 |
return PAM_SERVICE_ERR;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (strpbrk(user, USER_DISALLOWED_CHARS)) {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, "Incorrect username");
|
|
Packit |
5f9837 |
return PAM_SERVICE_ERR;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* search for necessary credentials stashed in session keyring */
|
|
Packit |
5f9837 |
currentaddress = addrstr;
|
|
Packit |
5f9837 |
nextaddress = strchr(currentaddress, ',');
|
|
Packit |
5f9837 |
if (nextaddress)
|
|
Packit |
5f9837 |
*nextaddress++ = '\0';
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
while (currentaddress) {
|
|
Packit |
5f9837 |
if (key_search(currentaddress, keytype) > 0)
|
|
Packit |
5f9837 |
count++;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
currentaddress = nextaddress;
|
|
Packit |
5f9837 |
if (currentaddress) {
|
|
Packit |
5f9837 |
nextaddress = strchr(currentaddress, ',');
|
|
Packit |
5f9837 |
if (nextaddress)
|
|
Packit |
5f9837 |
*nextaddress++ = '\0';
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (!count) {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, "You have no same stashed credentials for %s", hostdomain);
|
|
Packit |
5f9837 |
return PAM_SERVICE_ERR;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
for (id = 0; id < count; id++) {
|
|
Packit |
5f9837 |
key_serial_t key = key_add(currentaddress, user, password, keytype);
|
|
Packit |
5f9837 |
if (key <= 0) {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, "error: Update credential key for %s: %s",
|
|
Packit |
5f9837 |
currentaddress, strerror(errno));
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return PAM_SUCCESS;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/**
|
|
Packit |
5f9837 |
* PAM function called during authentication.
|
|
Packit |
5f9837 |
*
|
|
Packit |
5f9837 |
* This function first tries to get a password from PAM. Afterwards two
|
|
Packit |
5f9837 |
* scenarios are possible:
|
|
Packit |
5f9837 |
*
|
|
Packit |
5f9837 |
* - A session is already available which usually means that the user is already
|
|
Packit |
5f9837 |
* logged on and PAM has been used inside the screensaver. In that case, no need to
|
|
Packit |
5f9837 |
* do anything(?).
|
|
Packit |
5f9837 |
*
|
|
Packit |
5f9837 |
* - A session is not yet available. Store the password inside PAM data so
|
|
Packit |
5f9837 |
* it can be retrieved during pam_open_session to set the credentials.
|
|
Packit |
5f9837 |
*
|
|
Packit |
5f9837 |
* @param ph PAM handle
|
|
Packit |
5f9837 |
* @param unused unused
|
|
Packit |
5f9837 |
* @param argc number of arguments for this PAM module
|
|
Packit |
5f9837 |
* @param argv array of arguments for this PAM module
|
|
Packit |
5f9837 |
* @return any of the PAM return values
|
|
Packit |
5f9837 |
*/
|
|
Packit |
5f9837 |
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *ph, int unused __attribute__((unused)), int argc, const char **argv)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
const char *hostdomain;
|
|
Packit |
5f9837 |
const char *user;
|
|
Packit |
5f9837 |
const char *password;
|
|
Packit |
5f9837 |
uint args;
|
|
Packit |
5f9837 |
int ret;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
args = parse_args(ph, argc, argv, &hostdomain);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* Figure out and/or prompt for the user name */
|
|
Packit |
5f9837 |
ret = pam_get_user(ph, &user, NULL);
|
|
Packit |
5f9837 |
if (ret != PAM_SUCCESS || !user) {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, "couldn't get the user name: %s",
|
|
Packit |
5f9837 |
pam_strerror(ph, ret));
|
|
Packit |
5f9837 |
return PAM_SERVICE_ERR;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* Lookup the password */
|
|
Packit |
5f9837 |
ret = pam_get_item(ph, PAM_AUTHTOK, (const void**)&password);
|
|
Packit |
5f9837 |
if (ret != PAM_SUCCESS || password == NULL) {
|
|
Packit |
5f9837 |
if (ret == PAM_SUCCESS) {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_WARNING, "no password is available for user");
|
|
Packit |
5f9837 |
} else {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_WARNING, "no password is available for user: %s",
|
|
Packit |
5f9837 |
pam_strerror(ph, ret));
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
return PAM_SUCCESS;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* set password as pam data and launch during open_session. */
|
|
Packit |
5f9837 |
if (pam_set_data(ph, "cifscreds_password", strdup(password), cleanup_free_password) != PAM_SUCCESS) {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, "error storing password");
|
|
Packit |
5f9837 |
return PAM_AUTHTOK_RECOVER_ERR;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if ((args & ARG_DEBUG) == ARG_DEBUG) {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_DEBUG, "password stored");
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return PAM_SUCCESS;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/**
|
|
Packit |
5f9837 |
* PAM function called during opening the session.
|
|
Packit |
5f9837 |
*
|
|
Packit |
5f9837 |
* Retrieves the password stored during authentication from PAM data, then uses
|
|
Packit |
5f9837 |
* it set the cifs key.
|
|
Packit |
5f9837 |
*
|
|
Packit |
5f9837 |
* @param ph PAM handle
|
|
Packit |
5f9837 |
* @param flags currently unused, TODO: check for silent flag
|
|
Packit |
5f9837 |
* @param argc number of arguments for this PAM module
|
|
Packit |
5f9837 |
* @param argv array of arguments for this PAM module
|
|
Packit |
5f9837 |
* @return any of the PAM return values
|
|
Packit |
5f9837 |
*/
|
|
Packit |
5f9837 |
PAM_EXTERN int pam_sm_open_session(pam_handle_t *ph, int flags __attribute__((unused)), int argc, const char **argv)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
const char *user = NULL;
|
|
Packit |
5f9837 |
const char *password = NULL;
|
|
Packit |
5f9837 |
const char *hostdomain = NULL;
|
|
Packit |
5f9837 |
uint args;
|
|
Packit |
5f9837 |
int retval;
|
|
Packit |
5f9837 |
key_serial_t ses_key, uses_key;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
args = parse_args(ph, argc, argv, &hostdomain);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* Figure out the user name */
|
|
Packit |
5f9837 |
retval = pam_get_user(ph, &user, NULL);
|
|
Packit |
5f9837 |
if (retval != PAM_SUCCESS || !user) {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, "couldn't get the user name: %s",
|
|
Packit |
5f9837 |
pam_strerror(ph, retval));
|
|
Packit |
5f9837 |
return PAM_SERVICE_ERR;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* retrieve the stored password */
|
|
Packit |
5f9837 |
if (pam_get_data(ph, "cifscreds_password", (const void**)&password) != PAM_SUCCESS) {
|
|
Packit |
5f9837 |
/*
|
|
Packit |
5f9837 |
* No password, no worries, maybe this (PAM using) application
|
|
Packit |
5f9837 |
* didn't do authentication, or is hopeless and wants to call
|
|
Packit |
5f9837 |
* different PAM callbacks from different processes.
|
|
Packit |
5f9837 |
*
|
|
Packit |
5f9837 |
*
|
|
Packit |
5f9837 |
*/
|
|
Packit |
5f9837 |
password = NULL;
|
|
Packit |
5f9837 |
if ((args & ARG_DEBUG) == ARG_DEBUG) {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_DEBUG, "no stored password found");
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
return PAM_SUCCESS;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* make sure we have a host or domain name */
|
|
Packit |
5f9837 |
if (!hostdomain) {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, "one of host= or domain= must be specified");
|
|
Packit |
5f9837 |
return PAM_SERVICE_ERR;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* make sure there is a session keyring */
|
|
Packit |
5f9837 |
ses_key = keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 0);
|
|
Packit |
5f9837 |
if (ses_key == -1) {
|
|
Packit |
5f9837 |
if (errno == ENOKEY)
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, "you have no session keyring. "
|
|
Packit |
5f9837 |
"Consider using pam_keyinit to "
|
|
Packit |
5f9837 |
"install one.");
|
|
Packit |
5f9837 |
else
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, "unable to query session "
|
|
Packit |
5f9837 |
"keyring: %s", strerror(errno));
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/* A problem querying the user-session keyring isn't fatal. */
|
|
Packit |
5f9837 |
uses_key = keyctl_get_keyring_ID(KEY_SPEC_USER_SESSION_KEYRING, 0);
|
|
Packit |
5f9837 |
if ((uses_key >= 0) && (ses_key == uses_key))
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, "you have no persistent session "
|
|
Packit |
5f9837 |
"keyring. cifscreds keys will not persist.");
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return cifscreds_pam_add(ph, user, password, args, hostdomain);
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/**
|
|
Packit |
5f9837 |
* This is called when the PAM session is closed.
|
|
Packit |
5f9837 |
*
|
|
Packit |
5f9837 |
* Currently it does nothing. The session closing should remove the passwords
|
|
Packit |
5f9837 |
*
|
|
Packit |
5f9837 |
* @param ph PAM handle
|
|
Packit |
5f9837 |
* @param flags currently unused, TODO: check for silent flag
|
|
Packit |
5f9837 |
* @param argc number of arguments for this PAM module
|
|
Packit |
5f9837 |
* @param argv array of arguments for this PAM module
|
|
Packit |
5f9837 |
* @return PAM_SUCCESS
|
|
Packit |
5f9837 |
*/
|
|
Packit |
5f9837 |
PAM_EXTERN int pam_sm_close_session(pam_handle_t *ph __attribute__((unused)), int flags __attribute__((unused)), int argc __attribute__((unused)), const char **argv __attribute__((unused)))
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
return PAM_SUCCESS;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/**
|
|
Packit |
5f9837 |
* This is called when pam_set_cred() is invoked.
|
|
Packit |
5f9837 |
*
|
|
Packit |
5f9837 |
* @param ph PAM handle
|
|
Packit |
5f9837 |
* @param flags currently unused, TODO: check for silent flag
|
|
Packit |
5f9837 |
* @param argc number of arguments for this PAM module
|
|
Packit |
5f9837 |
* @param argv array of arguments for this PAM module
|
|
Packit |
5f9837 |
* @return PAM_SUCCESS
|
|
Packit |
5f9837 |
*/
|
|
Packit |
5f9837 |
PAM_EXTERN int pam_sm_setcred(pam_handle_t *ph __attribute__((unused)), int flags __attribute__((unused)), int argc __attribute__((unused)), const char **argv __attribute__((unused)))
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
return PAM_SUCCESS;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
/**
|
|
Packit |
5f9837 |
* This is called when the user's password is changed
|
|
Packit |
5f9837 |
*
|
|
Packit |
5f9837 |
* @param ph PAM handle
|
|
Packit |
5f9837 |
* @param flags currently unused, TODO: check for silent flag
|
|
Packit |
5f9837 |
* @param argc number of arguments for this PAM module
|
|
Packit |
5f9837 |
* @param argv array of arguments for this PAM module
|
|
Packit |
5f9837 |
* @return PAM_SUCCESS
|
|
Packit |
5f9837 |
*/
|
|
Packit |
5f9837 |
PAM_EXTERN int
|
|
Packit |
5f9837 |
pam_sm_chauthtok (pam_handle_t *ph, int flags, int argc, const char **argv)
|
|
Packit |
5f9837 |
{
|
|
Packit |
5f9837 |
const char *hostdomain = NULL;
|
|
Packit |
5f9837 |
const char *user = NULL;
|
|
Packit |
5f9837 |
const char *password = NULL;
|
|
Packit |
5f9837 |
uint args;
|
|
Packit |
5f9837 |
int ret;
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
args = parse_args(ph, argc, argv, &hostdomain);
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
if (flags & PAM_UPDATE_AUTHTOK) {
|
|
Packit |
5f9837 |
/* Figure out the user name */
|
|
Packit |
5f9837 |
ret = pam_get_user(ph, &user, NULL);
|
|
Packit |
5f9837 |
if (ret != PAM_SUCCESS) {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_ERR, "couldn't get the user name: %s", pam_strerror (ph, ret));
|
|
Packit |
5f9837 |
return PAM_SERVICE_ERR;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
ret = pam_get_item(ph, PAM_AUTHTOK, (const void**)&password);
|
|
Packit |
5f9837 |
if (ret != PAM_SUCCESS || password == NULL) {
|
|
Packit |
5f9837 |
if (ret == PAM_SUCCESS) {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_WARNING, "no password is available for user");
|
|
Packit |
5f9837 |
} else {
|
|
Packit |
5f9837 |
pam_syslog(ph, LOG_WARNING, "no password is available for user: %s", pam_strerror(ph, ret));
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
return PAM_AUTHTOK_RECOVER_ERR;
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
|
|
Packit |
5f9837 |
return cifscreds_pam_update(ph, user, password, args, hostdomain);
|
|
Packit |
5f9837 |
}
|
|
Packit |
5f9837 |
else
|
|
Packit |
5f9837 |
return PAM_IGNORE;
|
|
Packit |
5f9837 |
}
|