mirror of
git://git.gnu.org.ua/pam-modules.git
synced 2025-04-26 00:19:52 +03:00
324 lines
7.2 KiB
C
324 lines
7.2 KiB
C
/* This file is part of pam-modules.
|
|
Copyright (C) 2018-2022 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
|
|
#include <stdlib.h>
|
|
#include <netdb.h>
|
|
#include "graypam.h"
|
|
|
|
#ifndef LINUX_PAM
|
|
#include <security/pam_appl.h>
|
|
#endif
|
|
#include <security/pam_modules.h>
|
|
|
|
static long debug_level;
|
|
char const *host_name;
|
|
char const *domain_name;
|
|
char const *netgroup_name;
|
|
int use_getdomainname;
|
|
int use_resolve;
|
|
enum {
|
|
SENSE_ALLOW,
|
|
SENSE_DENY
|
|
};
|
|
const char *sense_choice[] = { "allow", "deny", NULL };
|
|
static int sense;
|
|
|
|
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(netgroup), pam_opt_string, &netgroup_name },
|
|
{ PAM_OPTSTR(hostname), pam_opt_string, &host_name },
|
|
{ PAM_OPTSTR(domainname), pam_opt_string, &domain_name },
|
|
{ PAM_OPTSTR(getdomainname), pam_opt_bool, &use_getdomainname },
|
|
{ PAM_OPTSTR(resolve), pam_opt_bool, &use_resolve },
|
|
{ PAM_OPTSTR(sense), pam_opt_enum, &sense, { enumstr: sense_choice } },
|
|
{ NULL }
|
|
};
|
|
|
|
#ifndef MAXHOSTNAMELEN
|
|
# define MAXHOSTNAMELEN 64
|
|
#endif
|
|
#ifndef SIZE_T_MAX
|
|
# define SIZE_T_MAX ((size_t)-1)
|
|
#endif
|
|
|
|
int
|
|
xgetname(int (*getfn)(char *, size_t), char **storage)
|
|
{
|
|
char *buffer = NULL;
|
|
size_t size = 0;
|
|
char *p;
|
|
|
|
while (1) {
|
|
if (size == 0) {
|
|
size = MAXHOSTNAMELEN;
|
|
p = malloc(size);
|
|
} else if (SIZE_T_MAX / 3 * 2 <= size) {
|
|
p = NULL;
|
|
} else {
|
|
size += (size + 1) / 2;
|
|
p = realloc(buffer, size);
|
|
}
|
|
if (!p) {
|
|
free(buffer);
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
buffer = p;
|
|
buffer[size - 1] = 0;
|
|
if (getfn(buffer, size - 1) == 0) {
|
|
if (!buffer[size - 1])
|
|
break;
|
|
} else if (errno != 0
|
|
&& errno != ENAMETOOLONG
|
|
&& errno != EINVAL
|
|
&& errno != ENOMEM) {
|
|
int rc = errno;
|
|
free(buffer);
|
|
errno = rc;
|
|
return -1;
|
|
}
|
|
}
|
|
*storage = buffer;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
stripdomain(char *hostname, char const *domainname)
|
|
{
|
|
size_t hlen, dlen;
|
|
|
|
if (!domainname)
|
|
return -1;
|
|
hlen = strlen(hostname);
|
|
dlen = strlen(domainname);
|
|
if (hlen > dlen + 1
|
|
&& hostname[hlen - dlen - 1] == '.'
|
|
&& strcasecmp(hostname + hlen - dlen, domainname) == 0) {
|
|
hostname[hlen - dlen - 1] = 0;
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int
|
|
get_host_domain_names(char **host_name_ptr, char **domain_name_ptr)
|
|
{
|
|
char *hostname;
|
|
char *domainname = NULL;
|
|
|
|
if (xgetname(gethostname, &hostname))
|
|
return -1;
|
|
#if HAVE_GETDOMAINNAME
|
|
if (use_getdomainname) {
|
|
if (xgetname(getdomainname, &domainname)) {
|
|
_pam_log(LOG_ERR, "getdomainname: %s", strerror(errno));
|
|
} else if (strcmp (domainname, "(none)") == 0) {
|
|
free(domainname);
|
|
domainname = NULL;
|
|
}
|
|
}
|
|
#endif
|
|
if (domainname) {
|
|
stripdomain(hostname, domainname);
|
|
} else if (use_resolve) {
|
|
char *p = strchr(hostname, '.');
|
|
if (!p) {
|
|
struct hostent *hp = gethostbyname(hostname);
|
|
if (hp) {
|
|
size_t len = strlen(hp->h_name);
|
|
p = realloc(hostname, len + 1);
|
|
if (!p) {
|
|
free(hostname);
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
hostname = p;
|
|
strcpy(hostname, hp->h_name);
|
|
p = strchr(hostname, '.');
|
|
}
|
|
}
|
|
if (p) {
|
|
*p++ = 0;
|
|
domainname = strdup(p);
|
|
if (!domainname) {
|
|
int rc = errno;
|
|
_pam_log(LOG_ERR, "getdomainname: %s",
|
|
strerror(errno));
|
|
free(hostname);
|
|
errno = rc;
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
*host_name_ptr = hostname;
|
|
*domain_name_ptr = domainname;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
check_netgroup0(pam_handle_t *pamh, int argc, const char **argv,
|
|
const char *func)
|
|
{
|
|
int rc;
|
|
char *host_name_buf = NULL;
|
|
char *domain_name_buf = NULL;
|
|
char const *user_name;
|
|
|
|
debug_level = 0;
|
|
host_name = NULL;
|
|
domain_name = NULL;
|
|
netgroup_name = NULL;
|
|
use_getdomainname = 1;
|
|
use_resolve = 1;
|
|
sense = SENSE_ALLOW;
|
|
|
|
gray_log_init(0, MODULE_NAME, LOG_AUTHPRIV);
|
|
gray_parseopt(pam_opt, argc, argv);
|
|
if (!netgroup_name) {
|
|
_pam_log(LOG_ERR, "no netgroup name given");
|
|
return PAM_AUTHINFO_UNAVAIL;
|
|
}
|
|
|
|
/*
|
|
* get username
|
|
*/
|
|
rc = pam_get_user(pamh, &user_name, "login: ");
|
|
if (rc == PAM_SUCCESS) {
|
|
DEBUG(10, ("username [%s] obtained", user_name));
|
|
} else {
|
|
_pam_log(LOG_NOTICE, "can't get username");
|
|
return PAM_AUTHINFO_UNAVAIL;
|
|
}
|
|
|
|
if (!host_name || !domain_name) {
|
|
if (get_host_domain_names (&host_name_buf, &domain_name_buf)) {
|
|
_pam_log(LOG_ERR, "%s", strerror(errno));
|
|
return PAM_SERVICE_ERR;
|
|
}
|
|
if (!host_name) {
|
|
if (!host_name_buf) {
|
|
_pam_log(LOG_NOTICE, "can't get hostname");
|
|
return PAM_AUTHINFO_UNAVAIL;
|
|
}
|
|
host_name = host_name_buf;
|
|
}
|
|
if (!domain_name) {
|
|
if (!domain_name_buf) {
|
|
_pam_log(LOG_NOTICE, "can't get domainname");
|
|
return PAM_AUTHINFO_UNAVAIL;
|
|
}
|
|
domain_name = domain_name_buf;
|
|
}
|
|
}
|
|
|
|
DEBUG(1,("checking (%s, %s, %s)",
|
|
host_name, user_name, domain_name));
|
|
|
|
rc = innetgr(netgroup_name, host_name, user_name, domain_name);
|
|
|
|
DEBUG(1,("netgroup %s, triple (%s, %s, %s): %d", netgroup_name,
|
|
host_name, user_name, domain_name, rc));
|
|
|
|
free(host_name_buf);
|
|
free(domain_name_buf);
|
|
|
|
if (sense == SENSE_DENY)
|
|
rc = !rc;
|
|
return rc ? PAM_SUCCESS : PAM_AUTH_ERR;
|
|
}
|
|
|
|
static int
|
|
check_netgroup(pam_handle_t *pamh, int argc, const char **argv,
|
|
const char *func)
|
|
{
|
|
int rc;
|
|
|
|
DEBUG(90,("enter %s", func));
|
|
rc = check_netgroup0(pamh, argc, argv, __FUNCTION__);
|
|
DEBUG(90,("leave %s=%d", func, rc));
|
|
return rc;
|
|
}
|
|
|
|
PAM_EXTERN int
|
|
pam_sm_authenticate(pam_handle_t *pamh,
|
|
int flags,
|
|
int argc,
|
|
const char **argv)
|
|
{
|
|
return check_netgroup(pamh, argc, argv, __FUNCTION__);
|
|
}
|
|
|
|
PAM_EXTERN int
|
|
pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
|
|
{
|
|
return check_netgroup(pamh, argc, argv, __FUNCTION__);
|
|
}
|
|
|
|
PAM_EXTERN int
|
|
pam_sm_chauthtok(pam_handle_t *pamh,int flags,int argc,const char **argv)
|
|
{
|
|
return check_netgroup(pamh, argc, argv, __FUNCTION__);
|
|
}
|
|
|
|
PAM_EXTERN int
|
|
pam_sm_acct_mgmt (pam_handle_t *pamh, int flags, int argc, const char **argv)
|
|
{
|
|
return check_netgroup(pamh, argc, argv, __FUNCTION__);
|
|
}
|
|
|
|
PAM_EXTERN int
|
|
pam_sm_open_session (pam_handle_t *pamh, int flags, int argc,
|
|
const char **argv)
|
|
{
|
|
return check_netgroup(pamh, argc, argv, __FUNCTION__);
|
|
}
|
|
|
|
PAM_EXTERN int
|
|
pam_sm_close_session (pam_handle_t *pamh, int flags, int argc,
|
|
const char **argv)
|
|
{
|
|
return check_netgroup(pamh, argc, argv, __FUNCTION__);
|
|
}
|
|
|
|
#ifdef PAM_STATIC
|
|
|
|
/* static module data */
|
|
|
|
struct pam_module _pam_log_modstruct = {
|
|
MODULE_NAME,
|
|
pam_sm_authenticate,
|
|
pam_sm_setcred,
|
|
pam_sm_acct_mgmt,
|
|
pam_sm_open_session,
|
|
pam_sm_close_session,
|
|
pam_sm_chauthtok,
|
|
};
|
|
|
|
#endif
|
|
|
|
/* end of module definition */
|
|
|
|
|