394 lines
9.5 KiB
C
394 lines
9.5 KiB
C
/*
|
|
* pam_listfile module
|
|
*
|
|
* by Elliot Lee <sopwith@redhat.com>, Red Hat Software. July 25, 1996.
|
|
* log refused access error christopher mccrory <chrismcc@netus.com> 1998/7/11
|
|
*
|
|
* This code began life as the pam_rootok module.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <syslog.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <pwd.h>
|
|
#include <grp.h>
|
|
|
|
#ifdef PAM_DEBUG
|
|
#include <assert.h>
|
|
#endif
|
|
|
|
#include <security/pam_modules.h>
|
|
#include <security/_pam_macros.h>
|
|
#include <security/pam_modutil.h>
|
|
#include <security/pam_ext.h>
|
|
#include "pam_inline.h"
|
|
|
|
/* --- authentication management functions (only) --- */
|
|
|
|
/* Extended Items that are not directly available via pam_get_item() */
|
|
#define EI_GROUP (1 << 0)
|
|
#define EI_SHELL (1 << 1)
|
|
|
|
/* Constants for apply= parameter */
|
|
#define APPLY_TYPE_NULL 0
|
|
#define APPLY_TYPE_NONE 1
|
|
#define APPLY_TYPE_USER 2
|
|
#define APPLY_TYPE_GROUP 3
|
|
|
|
#define LESSER(a, b) ((a) < (b) ? (a) : (b))
|
|
|
|
static int
|
|
pam_listfile(pam_handle_t *pamh, int argc, const char **argv)
|
|
{
|
|
int retval = -1;
|
|
int onerr = PAM_SERVICE_ERR;
|
|
int citem = 0;
|
|
int extitem = 0;
|
|
int sense = -1;
|
|
int quiet = 0;
|
|
int i;
|
|
const void *void_citemp;
|
|
const char *citemp;
|
|
const char *ifname=NULL;
|
|
char *aline=NULL;
|
|
const char *apply_val;
|
|
struct stat fileinfo;
|
|
FILE *inf;
|
|
int apply_type;
|
|
size_t n=0;
|
|
|
|
/* Stuff for "extended" items */
|
|
struct passwd *userinfo;
|
|
|
|
apply_type=APPLY_TYPE_NULL;
|
|
apply_val = "";
|
|
|
|
for(i=0; i < argc; i++) {
|
|
const char *str;
|
|
|
|
/* option quiet has no value */
|
|
if(!strcmp(argv[i],"quiet")) {
|
|
quiet = 1;
|
|
continue;
|
|
}
|
|
|
|
if(strchr(argv[i], '=') == NULL) {
|
|
pam_syslog(pamh,LOG_ERR, "Bad option: \"%s\"", argv[i]);
|
|
continue;
|
|
}
|
|
if ((str = pam_str_skip_prefix(argv[i], "onerr=")) != NULL) {
|
|
if(!strcmp(str,"succeed"))
|
|
onerr = PAM_SUCCESS;
|
|
else if(!strcmp(str,"fail"))
|
|
onerr = PAM_SERVICE_ERR;
|
|
else {
|
|
pam_syslog(pamh, LOG_ERR, "Unknown option: %s", argv[i]);
|
|
if (retval == -1)
|
|
retval = PAM_SERVICE_ERR;
|
|
continue;
|
|
}
|
|
} else if ((str = pam_str_skip_prefix(argv[i], "sense=")) != NULL) {
|
|
if(!strcmp(str,"allow"))
|
|
sense=0;
|
|
else if(!strcmp(str,"deny"))
|
|
sense=1;
|
|
else {
|
|
pam_syslog(pamh, LOG_ERR, "Unknown option: %s", argv[i]);
|
|
if (retval == -1)
|
|
retval = onerr;
|
|
continue;
|
|
}
|
|
} else if ((str = pam_str_skip_prefix(argv[i], "file=")) != NULL) {
|
|
ifname = str;
|
|
} else if ((str = pam_str_skip_prefix(argv[i], "item=")) != NULL) {
|
|
if(!strcmp(str,"user"))
|
|
citem = PAM_USER;
|
|
else if(!strcmp(str,"tty"))
|
|
citem = PAM_TTY;
|
|
else if(!strcmp(str,"rhost"))
|
|
citem = PAM_RHOST;
|
|
else if(!strcmp(str,"ruser"))
|
|
citem = PAM_RUSER;
|
|
else { /* These items are related to the user, but are not
|
|
directly gettable with pam_get_item */
|
|
citem = PAM_USER;
|
|
if(!strcmp(str,"group"))
|
|
extitem = EI_GROUP;
|
|
else if(!strcmp(str,"shell"))
|
|
extitem = EI_SHELL;
|
|
else
|
|
citem = 0;
|
|
}
|
|
} else if ((str = pam_str_skip_prefix(argv[i], "apply=")) != NULL) {
|
|
apply_type=APPLY_TYPE_NONE;
|
|
if (*str=='@') {
|
|
apply_type=APPLY_TYPE_GROUP;
|
|
apply_val = str+1;
|
|
} else {
|
|
apply_type=APPLY_TYPE_USER;
|
|
apply_val = str;
|
|
}
|
|
} else {
|
|
pam_syslog(pamh,LOG_ERR, "Unknown option: %s",argv[i]);
|
|
if (retval == -1)
|
|
retval = onerr;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (!citem) {
|
|
pam_syslog(pamh,LOG_ERR,
|
|
"Unknown item or item not specified");
|
|
if (retval == -1)
|
|
retval = onerr;
|
|
}
|
|
|
|
if (!ifname) {
|
|
pam_syslog(pamh,LOG_ERR, "List filename not specified");
|
|
if (retval == -1)
|
|
retval = onerr;
|
|
}
|
|
|
|
if (sense == -1) {
|
|
pam_syslog(pamh,LOG_ERR,
|
|
"Unknown sense or sense not specified");
|
|
if (retval == -1)
|
|
retval = onerr;
|
|
}
|
|
|
|
if ((apply_type == APPLY_TYPE_NONE) ||
|
|
((apply_type != APPLY_TYPE_NULL) && (*apply_val == '\0'))) {
|
|
pam_syslog(pamh,LOG_ERR,
|
|
"Invalid usage for apply= parameter");
|
|
if (retval == -1)
|
|
retval = onerr;
|
|
}
|
|
|
|
if (retval != -1)
|
|
return retval;
|
|
|
|
/* Check if it makes sense to use the apply= parameter */
|
|
if (apply_type != APPLY_TYPE_NULL) {
|
|
if((citem==PAM_USER) || (citem==PAM_RUSER)) {
|
|
pam_syslog(pamh,LOG_WARNING,
|
|
"Non-sense use for apply= parameter");
|
|
apply_type=APPLY_TYPE_NULL;
|
|
}
|
|
if(extitem && (extitem==EI_GROUP)) {
|
|
pam_syslog(pamh,LOG_WARNING,
|
|
"Non-sense use for apply= parameter");
|
|
apply_type=APPLY_TYPE_NULL;
|
|
}
|
|
}
|
|
|
|
/* Short-circuit - test if this session applies for this user */
|
|
{
|
|
const char *user_name;
|
|
int rval;
|
|
|
|
rval=pam_get_user(pamh,&user_name,NULL);
|
|
if(rval==PAM_SUCCESS && user_name[0]) {
|
|
/* Got it ? Valid ? */
|
|
if(apply_type==APPLY_TYPE_USER) {
|
|
if(strcmp(user_name, apply_val)) {
|
|
/* Does not apply to this user */
|
|
#ifdef PAM_DEBUG
|
|
pam_syslog(pamh,LOG_DEBUG,
|
|
"don't apply: apply=%s, user=%s",
|
|
apply_val,user_name);
|
|
#endif /* PAM_DEBUG */
|
|
return PAM_IGNORE;
|
|
}
|
|
} else if(apply_type==APPLY_TYPE_GROUP) {
|
|
if(!pam_modutil_user_in_group_nam_nam(pamh,user_name,apply_val)) {
|
|
/* Not a member of apply= group */
|
|
#ifdef PAM_DEBUG
|
|
pam_syslog(pamh,LOG_DEBUG,
|
|
|
|
"don't apply: %s not a member of group %s",
|
|
user_name,apply_val);
|
|
#endif /* PAM_DEBUG */
|
|
return PAM_IGNORE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
retval = pam_get_item(pamh,citem,&void_citemp);
|
|
citemp = void_citemp;
|
|
if(retval != PAM_SUCCESS) {
|
|
return onerr;
|
|
}
|
|
if((citem == PAM_USER) && !citemp) {
|
|
retval = pam_get_user(pamh,&citemp,NULL);
|
|
if (retval != PAM_SUCCESS) {
|
|
return PAM_SERVICE_ERR;
|
|
}
|
|
}
|
|
if((citem == PAM_TTY) && citemp) {
|
|
/* Normalize the TTY name. */
|
|
const char *str = pam_str_skip_prefix(citemp, "/dev/");
|
|
if (str != NULL)
|
|
citemp = str;
|
|
}
|
|
|
|
if(!citemp || (strlen(citemp) == 0)) {
|
|
/* The item was NULL - we are sure not to match */
|
|
return sense?PAM_SUCCESS:PAM_AUTH_ERR;
|
|
}
|
|
|
|
if(extitem) {
|
|
switch(extitem) {
|
|
case EI_GROUP:
|
|
/* Just ignore, call pam_modutil_in_group... later */
|
|
break;
|
|
case EI_SHELL:
|
|
/* Assume that we have already gotten PAM_USER in
|
|
pam_get_item() - a valid assumption since citem
|
|
gets set to PAM_USER in the extitem switch */
|
|
userinfo = pam_modutil_getpwnam(pamh, citemp);
|
|
if (userinfo == NULL) {
|
|
pam_syslog(pamh, LOG_NOTICE, "getpwnam(%s) failed",
|
|
citemp);
|
|
return onerr;
|
|
}
|
|
citemp = userinfo->pw_shell;
|
|
break;
|
|
default:
|
|
pam_syslog(pamh,LOG_ERR,
|
|
|
|
"Internal weirdness, unknown extended item %d",
|
|
extitem);
|
|
return onerr;
|
|
}
|
|
}
|
|
#ifdef PAM_DEBUG
|
|
pam_syslog(pamh,LOG_INFO,
|
|
|
|
"Got file = %s, item = %d, value = %s, sense = %d",
|
|
ifname, citem, citemp, sense);
|
|
#endif
|
|
if(lstat(ifname,&fileinfo)) {
|
|
if(!quiet)
|
|
pam_syslog(pamh,LOG_ERR, "Couldn't open %s",ifname);
|
|
return onerr;
|
|
}
|
|
|
|
if((fileinfo.st_mode & S_IWOTH)
|
|
|| !S_ISREG(fileinfo.st_mode)) {
|
|
/* If the file is world writable or is not a
|
|
normal file, return error */
|
|
pam_syslog(pamh,LOG_ERR,
|
|
"%s is either world writable or not a normal file",
|
|
ifname);
|
|
return PAM_AUTH_ERR;
|
|
}
|
|
|
|
inf = fopen(ifname,"r");
|
|
if(inf == NULL) { /* Check that we opened it successfully */
|
|
if (onerr == PAM_SERVICE_ERR) {
|
|
/* Only report if it's an error... */
|
|
pam_syslog(pamh,LOG_ERR, "Error opening %s", ifname);
|
|
}
|
|
return onerr;
|
|
}
|
|
/* There should be no more errors from here on */
|
|
retval=PAM_AUTH_ERR;
|
|
/* This loop assumes that PAM_SUCCESS == 0
|
|
and PAM_AUTH_ERR != 0 */
|
|
#ifdef PAM_DEBUG
|
|
assert(PAM_SUCCESS == 0);
|
|
assert(PAM_AUTH_ERR != 0);
|
|
#endif
|
|
while(retval && getline(&aline,&n,inf) != -1) {
|
|
const char *a = aline;
|
|
|
|
aline[strcspn(aline, "\r\n")] = '\0';
|
|
if(aline[0] == '\0')
|
|
continue;
|
|
if(citem == PAM_TTY) {
|
|
const char *str = pam_str_skip_prefix(a, "/dev/");
|
|
if (str != NULL)
|
|
a = str;
|
|
}
|
|
if (extitem == EI_GROUP) {
|
|
retval = !pam_modutil_user_in_group_nam_nam(pamh,
|
|
citemp, aline);
|
|
} else {
|
|
retval = strcmp(a, citemp);
|
|
}
|
|
}
|
|
|
|
free(aline);
|
|
fclose(inf);
|
|
if ((sense && retval) || (!sense && !retval)) {
|
|
#ifdef PAM_DEBUG
|
|
pam_syslog(pamh,LOG_INFO,
|
|
"Returning PAM_SUCCESS, retval = %d", retval);
|
|
#endif
|
|
return PAM_SUCCESS;
|
|
}
|
|
else {
|
|
const void *service;
|
|
const char *user_name;
|
|
#ifdef PAM_DEBUG
|
|
pam_syslog(pamh,LOG_INFO,
|
|
"Returning PAM_AUTH_ERR, retval = %d", retval);
|
|
#endif
|
|
(void) pam_get_item(pamh, PAM_SERVICE, &service);
|
|
(void) pam_get_user(pamh, &user_name, NULL);
|
|
if (!quiet)
|
|
pam_syslog (pamh, LOG_NOTICE, "Refused user %s for service %s",
|
|
user_name, (const char *)service);
|
|
return PAM_AUTH_ERR;
|
|
}
|
|
}
|
|
|
|
int
|
|
pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED,
|
|
int argc, const char **argv)
|
|
{
|
|
return pam_listfile(pamh, argc, argv);
|
|
}
|
|
|
|
int
|
|
pam_sm_setcred(pam_handle_t *pamh UNUSED, int flags UNUSED,
|
|
int argc UNUSED, const char **argv UNUSED)
|
|
{
|
|
return PAM_SUCCESS;
|
|
}
|
|
|
|
int
|
|
pam_sm_acct_mgmt(pam_handle_t *pamh, int flags UNUSED,
|
|
int argc, const char **argv)
|
|
{
|
|
return pam_listfile(pamh, argc, argv);
|
|
}
|
|
|
|
int
|
|
pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
|
|
int argc, const char **argv)
|
|
{
|
|
return pam_listfile(pamh, argc, argv);
|
|
}
|
|
|
|
int
|
|
pam_sm_close_session(pam_handle_t *pamh, int flags UNUSED,
|
|
int argc, const char **argv)
|
|
{
|
|
return pam_listfile(pamh, argc, argv);
|
|
}
|
|
|
|
int
|
|
pam_sm_chauthtok(pam_handle_t *pamh, int flags UNUSED,
|
|
int argc, const char **argv)
|
|
{
|
|
return pam_listfile(pamh, argc, argv);
|
|
}
|