|
Packit |
7e982e |
%{
|
|
Packit |
7e982e |
/* Copyright 1999,2000 Red Hat, Inc.
|
|
Packit |
7e982e |
* This software may be used under the terms of the GNU General Public
|
|
Packit |
7e982e |
* License, available in the file COPYING accompanying this file
|
|
Packit |
7e982e |
*/
|
|
Packit |
7e982e |
#define YYSTYPE void *
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
#include <errno.h>
|
|
Packit |
7e982e |
#include <grp.h>
|
|
Packit |
7e982e |
#include <limits.h>
|
|
Packit |
7e982e |
#include <regex.h>
|
|
Packit |
7e982e |
#include <stdio.h>
|
|
Packit |
7e982e |
#include <stdarg.h>
|
|
Packit |
7e982e |
#include <sys/types.h>
|
|
Packit |
7e982e |
#include <sys/stat.h>
|
|
Packit |
7e982e |
#include <pwd.h>
|
|
Packit |
7e982e |
#include <chmod.h>
|
|
Packit |
7e982e |
#include <hashtable.h>
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
#include <security/pam_modules.h>
|
|
Packit |
7e982e |
#include <security/pam_modutil.h>
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
typedef struct hashtable GHashTable;
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
static GHashTable *namespace = NULL;
|
|
Packit |
7e982e |
static GSList *configList = NULL;
|
|
Packit |
7e982e |
static GSList *configListEnd = NULL;
|
|
Packit |
7e982e |
static GSList *consoleClassList = NULL;
|
|
Packit |
7e982e |
static GSList *consoleClassListEnd = NULL;
|
|
Packit |
7e982e |
static const char *consoleNameCache = NULL;
|
|
Packit |
7e982e |
static GHashTable *consoleHash = NULL;
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
static void
|
|
Packit |
7e982e |
do_yyerror(const char *format, ...);
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
static void
|
|
Packit |
7e982e |
empty_class(class *c);
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
static unsigned int
|
|
Packit |
7e982e |
str_hash(unsigned char *s)
|
|
Packit |
7e982e |
{
|
|
Packit |
7e982e |
unsigned int hash = 5381;
|
|
Packit |
7e982e |
int c;
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
while ((c = *s++))
|
|
Packit |
7e982e |
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
return hash;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
static int
|
|
Packit |
7e982e |
str_equal(void *a, void *b)
|
|
Packit |
7e982e |
{
|
|
Packit |
7e982e |
return strcmp(a, b) == 0;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
static unsigned int
|
|
Packit |
7e982e |
ptr_hash(void *p)
|
|
Packit |
7e982e |
{
|
|
Packit |
7e982e |
return (unsigned long)p >> 3;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
static int
|
|
Packit |
7e982e |
ptr_equal(void *a, void *b)
|
|
Packit |
7e982e |
{
|
|
Packit |
7e982e |
return a == b;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
%}
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
%token EOL
|
|
Packit |
7e982e |
%token OBRACKET
|
|
Packit |
7e982e |
%token CBEQUALS
|
|
Packit |
7e982e |
%token CBRACKET
|
|
Packit |
7e982e |
%token STRING
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
%%
|
|
Packit |
7e982e |
lines: lines line
|
|
Packit |
7e982e |
| /* empty */
|
|
Packit |
7e982e |
;
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
line: config
|
|
Packit |
7e982e |
| classdef
|
|
Packit |
7e982e |
| EOL
|
|
Packit |
7e982e |
| error
|
|
Packit |
7e982e |
;
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
classdef:
|
|
Packit |
7e982e |
OBRACKET string CBEQUALS stringlist EOL {
|
|
Packit |
7e982e |
class *c;
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
c = hashtable_search(namespace, $2);
|
|
Packit |
7e982e |
if (c) {
|
|
Packit |
7e982e |
empty_class(c);
|
|
Packit |
7e982e |
} else {
|
|
Packit |
7e982e |
c = malloc(sizeof(class));
|
|
Packit |
7e982e |
hashtable_insert(namespace, strdup($2), c);
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
c->name = $2;
|
|
Packit |
7e982e |
c->list = $4;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
;
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
config: classlist STRING classlist optstring optstring EOL {
|
|
Packit |
7e982e |
config *conf = malloc(sizeof(config));
|
|
Packit |
7e982e |
conf->console_class = $1;
|
|
Packit |
7e982e |
conf->mode = $2;
|
|
Packit |
7e982e |
conf->device_class = $3;
|
|
Packit |
7e982e |
conf->revert_mode = $4;
|
|
Packit |
7e982e |
conf->revert_owner = $5;
|
|
Packit |
7e982e |
if (conf->revert_owner != NULL) {
|
|
Packit |
7e982e |
conf->revert_group = strchr (conf->revert_owner, ':');
|
|
Packit |
7e982e |
if (conf->revert_group == NULL)
|
|
Packit |
7e982e |
conf->revert_group = strchr (conf->revert_owner, '.');
|
|
Packit |
7e982e |
if (conf->revert_group != NULL) {
|
|
Packit |
7e982e |
*(conf->revert_group) = '\0';
|
|
Packit |
7e982e |
conf->revert_group++;
|
|
Packit |
7e982e |
if (*(conf->revert_group) == '\0')
|
|
Packit |
7e982e |
conf->revert_group = NULL;
|
|
Packit |
7e982e |
if (*(conf->revert_owner) == '\0')
|
|
Packit |
7e982e |
conf->revert_owner = NULL;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
} else {
|
|
Packit |
7e982e |
conf->revert_group = NULL;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
configListEnd = g_slist_append(configListEnd, conf);
|
|
Packit |
7e982e |
if (configListEnd->next) configListEnd = configListEnd->next;
|
|
Packit |
7e982e |
if (!configList) configList = configListEnd;
|
|
Packit |
7e982e |
consoleClassListEnd =
|
|
Packit |
7e982e |
g_slist_append(consoleClassListEnd, conf->console_class);
|
|
Packit |
7e982e |
if (consoleClassListEnd->next)
|
|
Packit |
7e982e |
consoleClassListEnd = consoleClassListEnd->next;
|
|
Packit |
7e982e |
if (!consoleClassList) consoleClassList = consoleClassListEnd;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
;
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
classlist: OBRACKET string CBRACKET {
|
|
Packit |
7e982e |
class *c = hashtable_search(namespace, $2);
|
|
Packit |
7e982e |
if(!c) {
|
|
Packit |
7e982e |
_pam_log(NULL, LOG_ERR, FALSE,
|
|
Packit |
7e982e |
"unknown class \"%s\" at line %d in %s\n",
|
|
Packit |
7e982e |
(const char *)$2, lineno, filename);
|
|
Packit |
7e982e |
YYERROR;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
$$ = c;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
| string {
|
|
Packit |
7e982e |
class *c = malloc(sizeof(class));
|
|
Packit |
7e982e |
c->name = $1;
|
|
Packit |
7e982e |
c->list = NULL;
|
|
Packit |
7e982e |
$$ = c;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
;
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
stringlist: string {$$ = g_slist_append(NULL, $1);}
|
|
Packit |
7e982e |
| stringlist string {$$ = g_slist_append($1, $2);}
|
|
Packit |
7e982e |
;
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
optstring: string {$$=$1;}
|
|
Packit |
7e982e |
| /* empty */ {$$=NULL;}
|
|
Packit |
7e982e |
;
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
string: STRING {$$=$1;} ;
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
%%
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
/* exported functions */
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
/* parse a file given by a name */
|
|
Packit |
7e982e |
void
|
|
Packit |
7e982e |
parse_file(const char *name) {
|
|
Packit |
7e982e |
FILE *infile;
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
_pam_log(NULL, LOG_DEBUG, TRUE, "parsing config file %s", name);
|
|
Packit |
7e982e |
infile = fopen(name, "r");
|
|
Packit |
7e982e |
if (!infile) {
|
|
Packit |
7e982e |
_pam_log(NULL, LOG_ERR, FALSE, "could not parse required file %s", name);
|
|
Packit |
7e982e |
return;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
if (!namespace) namespace = create_hashtable(128, (unsigned int (*)(void *))str_hash, str_equal);
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
lex_set_filename(name);
|
|
Packit |
7e982e |
lex_file(infile);
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
yyparse();
|
|
Packit |
7e982e |
fclose(infile);
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
static int
|
|
Packit |
7e982e |
check_one_console_name (const char *name, char *classComponent) {
|
|
Packit |
7e982e |
regex_t p;
|
|
Packit |
7e982e |
int r_err;
|
|
Packit |
7e982e |
char *class_exp;
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
class_exp = _do_malloc(strlen(classComponent) + 3);
|
|
Packit |
7e982e |
sprintf(class_exp, "^%s$", classComponent);
|
|
Packit |
7e982e |
r_err = regcomp(&p, class_exp, REG_EXTENDED|REG_NOSUB);
|
|
Packit |
7e982e |
if (r_err) do_regerror(r_err, &p);
|
|
Packit |
7e982e |
r_err = regexec(&p, name, 0, NULL, 0);
|
|
Packit |
7e982e |
regfree(&p);
|
|
Packit |
7e982e |
free (class_exp);
|
|
Packit |
7e982e |
return !r_err;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
int
|
|
Packit |
7e982e |
check_console_name (const char *consolename) {
|
|
Packit |
7e982e |
GSList *this_class;
|
|
Packit |
7e982e |
GSList *this_list;
|
|
Packit |
7e982e |
class *c;
|
|
Packit |
7e982e |
int found = 0;
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
_pam_log(NULL, LOG_DEBUG, TRUE, "check console %s", consolename);
|
|
Packit |
7e982e |
if (consoleNameCache != consolename) {
|
|
Packit |
7e982e |
consoleNameCache = consolename;
|
|
Packit |
7e982e |
if (consoleHash) hashtable_destroy(consoleHash, 0);
|
|
Packit |
7e982e |
consoleHash = create_hashtable(128, ptr_hash, ptr_equal);
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
for (this_class = consoleClassList; this_class;
|
|
Packit |
7e982e |
this_class = this_class->next) {
|
|
Packit |
7e982e |
c = this_class->data;
|
|
Packit |
7e982e |
if (c->list) {
|
|
Packit |
7e982e |
for (this_list = c->list; this_list; this_list = this_list->next) {
|
|
Packit |
7e982e |
if (check_one_console_name(consolename, this_list->data)) {
|
|
Packit |
7e982e |
hashtable_insert(consoleHash, c, c);
|
|
Packit |
7e982e |
found = 1;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
} else {
|
|
Packit |
7e982e |
if (check_one_console_name(consolename, c->name)) {
|
|
Packit |
7e982e |
hashtable_insert(consoleHash, c, c);
|
|
Packit |
7e982e |
found = 1;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
if (found)
|
|
Packit |
7e982e |
return 1;
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
/* not found */
|
|
Packit |
7e982e |
_pam_log(NULL, LOG_INFO, TRUE, "did not find console %s", consolename);
|
|
Packit |
7e982e |
if (consoleHash) {
|
|
Packit |
7e982e |
hashtable_destroy(consoleHash, 0);
|
|
Packit |
7e982e |
consoleHash = NULL;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
return 0;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
int
|
|
Packit |
7e982e |
set_permissions(const char *consolename, const char *username, GSList *files) {
|
|
Packit |
7e982e |
struct passwd *pwd;
|
|
Packit |
7e982e |
config *c;
|
|
Packit |
7e982e |
GSList *cl;
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
if (!consoleNameCache || strcmp(consolename, consoleNameCache)) {
|
|
Packit |
7e982e |
if (!check_console_name(consolename)) return -1;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
pwd = getpwnam(username);
|
|
Packit |
7e982e |
if (pwd == NULL) {
|
|
Packit |
7e982e |
_pam_log(NULL, LOG_ERR, FALSE, "getpwnam failed for \"%s\"", username);
|
|
Packit |
7e982e |
return -1;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
for (cl = configList; cl; cl = cl->next) {
|
|
Packit |
7e982e |
c = cl->data;
|
|
Packit |
7e982e |
if (hashtable_search(consoleHash, c->console_class)) {
|
|
Packit |
7e982e |
if (c->device_class->list)
|
|
Packit |
7e982e |
chmod_files(c->mode, pwd->pw_uid, -1, NULL, c->device_class->list, files);
|
|
Packit |
7e982e |
else
|
|
Packit |
7e982e |
chmod_files(c->mode, pwd->pw_uid, -1, c->device_class->name, NULL, files);
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
return 0;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
int
|
|
Packit |
7e982e |
reset_permissions(const char *consolename, GSList *files) {
|
|
Packit |
7e982e |
struct passwd *pwd;
|
|
Packit |
7e982e |
struct group *grp;
|
|
Packit |
7e982e |
config *c;
|
|
Packit |
7e982e |
GSList *cl;
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
if (!consoleNameCache || strcmp(consolename, consoleNameCache)) {
|
|
Packit |
7e982e |
if (!check_console_name(consolename)) return -1;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
for (cl = configList; cl; cl = cl->next) {
|
|
Packit |
7e982e |
c = cl->data;
|
|
Packit |
7e982e |
if (hashtable_search(consoleHash, c->console_class)) {
|
|
Packit |
7e982e |
pwd = getpwnam(c->revert_owner ? c->revert_owner : "root");
|
|
Packit |
7e982e |
if (pwd == NULL) {
|
|
Packit |
7e982e |
_pam_log(NULL, LOG_ERR, FALSE, "getpwnam failed for %s",
|
|
Packit |
7e982e |
c->revert_owner ? c->revert_owner : "root");
|
|
Packit |
7e982e |
pwd = getpwuid(0);
|
|
Packit |
7e982e |
if (pwd == NULL)
|
|
Packit |
7e982e |
return -1;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
grp = getgrnam(c->revert_group ? c->revert_group : "root");
|
|
Packit |
7e982e |
if (grp == NULL) {
|
|
Packit |
7e982e |
_pam_log(NULL, LOG_ERR, FALSE, "getgrnam failed for %s",
|
|
Packit |
7e982e |
c->revert_group ? c->revert_group : "root");
|
|
Packit |
7e982e |
grp = getgrgid(0);
|
|
Packit |
7e982e |
if (grp == NULL)
|
|
Packit |
7e982e |
return -1;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
if (c->device_class->list)
|
|
Packit |
7e982e |
chmod_files(c->revert_mode ? c->revert_mode : "0600",
|
|
Packit |
7e982e |
pwd->pw_uid, grp->gr_gid, NULL, c->device_class->list, files);
|
|
Packit |
7e982e |
else
|
|
Packit |
7e982e |
chmod_files(c->revert_mode ? c->revert_mode : "0600",
|
|
Packit |
7e982e |
pwd->pw_uid, grp->gr_gid, c->device_class->name, NULL, files);
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
return 0;
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
/* local, static functions */
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
static void
|
|
Packit |
7e982e |
do_yyerror(const char *format, ...) {
|
|
Packit |
7e982e |
va_list ap;
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
va_start(ap, format);
|
|
Packit |
7e982e |
openlog("pam_console", LOG_CONS|LOG_PID, LOG_AUTHPRIV);
|
|
Packit |
7e982e |
vsyslog(LOG_PID|LOG_AUTHPRIV|LOG_ERR, format, ap);
|
|
Packit |
7e982e |
va_end(ap);
|
|
Packit |
7e982e |
}
|
|
Packit |
7e982e |
|
|
Packit |
7e982e |
static void
|
|
Packit |
7e982e |
empty_class(class *c) {
|
|
Packit |
7e982e |
free(c->name);
|
|
Packit |
7e982e |
c->name = NULL;
|
|
Packit |
7e982e |
g_slist_free(c->list);
|
|
Packit |
7e982e |
c->list = NULL;
|
|
Packit |
7e982e |
}
|