Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to set pam_u2f arguments in configuration file #325

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,5 @@ pamu2fcfg/pamu2fcfg
man/pamu2fcfg.1
tests/get_devices
fuzz/fuzz_format_parsers
tests/config
tests/expand
2 changes: 2 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ AM_CPPFLAGS = $(LIBFIDO2_CFLAGS) $(LIBCRYPTO_CFLAGS)
if ENABLE_FUZZING
AM_CPPFLAGS += -fsanitize=fuzzer-no-link
endif
AM_CPPFLAGS += -D SYSCONFDIR='"$(sysconfdir)"'

noinst_LTLIBRARIES = libmodule.la
libmodule_la_SOURCES = pam-u2f.c
Expand All @@ -26,6 +27,7 @@ libmodule_la_SOURCES += drop_privs.h
libmodule_la_SOURCES += expand.c
libmodule_la_SOURCES += explicit_bzero.c
libmodule_la_SOURCES += util.c util.h
libmodule_la_SOURCES += cfg.c cfg.h
libmodule_la_LIBADD = -lpam $(LIBFIDO2_LIBS) $(LIBCRYPTO_LIBS)

pampluginexecdir = $(PAMDIR)
Expand Down
175 changes: 175 additions & 0 deletions cfg.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
#include <string.h>
#include <errno.h>
#include <stdlib.h>

#include "cfg.h"
#include "debug.h"

#define DEFAULT_CONFIG_PATH SYSCONFDIR "/security/pam_u2f.conf"

static void cfg_load_arg(cfg_t *cfg, const char *source, const char *arg) {
if (strncmp(arg, "max_devices=", 12) == 0) {
sscanf(arg, "max_devices=%u", &cfg->max_devs);
} else if (strcmp(arg, "manual") == 0) {
cfg->manual = 1;
} else if (strcmp(arg, "debug") == 0) {
cfg->debug = 1;
} else if (strcmp(arg, "nouserok") == 0) {
cfg->nouserok = 1;
} else if (strcmp(arg, "openasuser") == 0) {
cfg->openasuser = 1;
} else if (strcmp(arg, "alwaysok") == 0) {
cfg->alwaysok = 1;
} else if (strcmp(arg, "interactive") == 0) {
cfg->interactive = 1;
} else if (strcmp(arg, "cue") == 0) {
cfg->cue = 1;
} else if (strcmp(arg, "nodetect") == 0) {
cfg->nodetect = 1;
} else if (strcmp(arg, "expand") == 0) {
cfg->expand = 1;
} else if (strncmp(arg, "userpresence=", 13) == 0) {
sscanf(arg, "userpresence=%d", &cfg->userpresence);
} else if (strncmp(arg, "userverification=", 17) == 0) {
sscanf(arg, "userverification=%d", &cfg->userverification);
} else if (strncmp(arg, "pinverification=", 16) == 0) {
sscanf(arg, "pinverification=%d", &cfg->pinverification);
} else if (strncmp(arg, "authfile=", 9) == 0) {
cfg->auth_file = arg + 9;
} else if (strcmp(arg, "sshformat") == 0) {
cfg->sshformat = 1;
} else if (strncmp(arg, "authpending_file=", 17) == 0) {
cfg->authpending_file = arg + 17;
} else if (strncmp(arg, "origin=", 7) == 0) {
cfg->origin = arg + 7;
} else if (strncmp(arg, "appid=", 6) == 0) {
cfg->appid = arg + 6;
} else if (strncmp(arg, "prompt=", 7) == 0) {
cfg->prompt = arg + 7;
} else if (strncmp(arg, "cue_prompt=", 11) == 0) {
cfg->cue_prompt = arg + 11;
} else if (strncmp(arg, "debug_file=", 11) == 0) {
cfg->debug_file = debug_replace(cfg->debug_file, arg + 11);
} else {
debug_dbg(cfg, "WARNING: ignored config \"%s\" from %s", arg, source);
}
}

static void cfg_load_defaults(cfg_t *cfg, const char *config_path) {
int config_path_default = 0;
FILE *config_file;
char *buf = NULL;
size_t bufsiz = 0;
ssize_t len;

if (!config_path) {
config_path_default = 1;
config_path = DEFAULT_CONFIG_PATH;
} else if (*config_path != '/') {
debug_dbg(cfg, "WARNING: config path \"%s\": must be absolute.",
config_path);
config_path = DEFAULT_CONFIG_PATH;
}

if ((config_file = fopen(config_path, "r")) == NULL) {
if (errno != ENOENT || !config_path_default)
debug_dbg(cfg, "WARNING: could not parse %s: %s", config_path,
strerror(errno));
return;
}

debug_dbg(cfg, "loading defaults from %s", config_path);

while (errno = 0, (len = getline(&buf, &bufsiz, config_file)) != -1) {
if (len <= 1)
continue;
if (buf[len - 1] == '\n')
buf[--len] = '\0';

cfg_load_arg(cfg, config_path, buf);
}
if (errno)
debug_dbg(cfg, "WARNING: could not parse %s: %s", config_path,
strerror(errno));
free(buf);

if (config_file) {
fclose(config_file);
}
}

void cfg_init(cfg_t *cfg, int flags, int argc, const char **argv) {
int i;
const char *config_path = NULL, *debug_file_path = NULL;

memset(cfg, 0, sizeof(cfg_t));
cfg->debug_file = DEFAULT_DEBUG_FILE;
cfg->userpresence = -1;
cfg->userverification = -1;
cfg->pinverification = -1;

// Early-loaded arguments
// 'config=', if existing, it supplies the default configuration.
// 'debug' is enabled immediately to avoid blind spots.
for (i = 0; i < argc; i++) {
if (strcmp(argv[i], "debug") == 0) {
cfg->debug = 1;
continue;
}
if (strncmp(argv[i], "config=", 7) == 0) {
config_path = argv[i] + 7;
continue;
}
if (strncmp(argv[i], "debug_file=", 11) == 0) {
debug_file_path = argv[i] + 11;
continue;
}
}

// 'debug_file' is loaded after the loop to make sure that
// debug_file opening issues can be debugged too.
if (debug_file_path)
cfg->debug_file = debug_open(debug_file_path);

cfg_load_defaults(cfg, config_path);

for (i = 0; i < argc; i++) {
if (strncmp(argv[i], "config=", 7) == 0) {
continue;
}
cfg_load_arg(cfg, "argv", argv[i]);
}

if (cfg->debug) {
debug_dbg(cfg, "called.");
debug_dbg(cfg, "flags %d argc %d", flags, argc);
for (i = 0; i < argc; i++) {
debug_dbg(cfg, "argv[%d]=%s", i, argv[i]);
}
debug_dbg(cfg, "max_devices=%d", cfg->max_devs);
debug_dbg(cfg, "debug=%d", cfg->debug);
debug_dbg(cfg, "interactive=%d", cfg->interactive);
debug_dbg(cfg, "cue=%d", cfg->cue);
debug_dbg(cfg, "nodetect=%d", cfg->nodetect);
debug_dbg(cfg, "userpresence=%d", cfg->userpresence);
debug_dbg(cfg, "userverification=%d", cfg->userverification);
debug_dbg(cfg, "pinverification=%d", cfg->pinverification);
debug_dbg(cfg, "manual=%d", cfg->manual);
debug_dbg(cfg, "nouserok=%d", cfg->nouserok);
debug_dbg(cfg, "openasuser=%d", cfg->openasuser);
debug_dbg(cfg, "alwaysok=%d", cfg->alwaysok);
debug_dbg(cfg, "sshformat=%d", cfg->sshformat);
debug_dbg(cfg, "expand=%d", cfg->expand);
debug_dbg(cfg, "authfile=%s", cfg->auth_file ? cfg->auth_file : "(null)");
debug_dbg(cfg, "authpending_file=%s",
cfg->authpending_file ? cfg->authpending_file : "(null)");
debug_dbg(cfg, "origin=%s", cfg->origin ? cfg->origin : "(null)");
debug_dbg(cfg, "appid=%s", cfg->appid ? cfg->appid : "(null)");
debug_dbg(cfg, "prompt=%s", cfg->prompt ? cfg->prompt : "(null)");
}
}

void cfg_free(cfg_t *cfg) {
debug_close(cfg->debug_file);
cfg->debug_file = DEFAULT_DEBUG_FILE;
}
38 changes: 38 additions & 0 deletions cfg.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2014-2019 Yubico AB - See COPYING
*/

#ifndef CFG_H
#define CFG_H

#include <stdio.h>

typedef struct {
unsigned max_devs;
int manual;
int debug;
int nouserok;
int openasuser;
int alwaysok;
int interactive;
int cue;
int nodetect;
int userpresence;
int userverification;
int pinverification;
int sshformat;
int expand;
const char *auth_file;
const char *authpending_file;
const char *origin;
const char *appid;
const char *prompt;
const char *cue_prompt;
FILE *debug_file;
} cfg_t;

void cfg_init(cfg_t *cfg, int flags, int argc, const char **argv);

void cfg_free(cfg_t *cfg);

#endif
64 changes: 50 additions & 14 deletions debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <string.h>
Expand All @@ -15,40 +16,75 @@
#define DEBUG_FMT "debug(pam_u2f): %s:%d (%s): %s%s"
#define MSGLEN 2048

FILE *debug_open(const char *filename) {
static int debug_get_file(const char *name, FILE **out)
{
struct stat st;
FILE *file;
int fd;

if (strcmp(filename, "stdout") == 0)
return stdout;
if (strcmp(filename, "stderr") == 0)
return stderr;
if (strcmp(filename, "syslog") == 0)
return NULL;
if (strcmp(name, "stdout") == 0) {
*out = stdout;
return 0;
}
if (strcmp(name, "stderr") == 0) {
*out = stderr;
return 0;
}
if (strcmp(name, "syslog") == 0) {
*out = NULL;
return 0;
}

fd = open(filename, O_WRONLY | O_APPEND | O_CLOEXEC | O_NOFOLLOW | O_NOCTTY);
if (fd == -1 || fstat(fd, &st) != 0)
fd = open(name, O_WRONLY | O_APPEND | O_CLOEXEC | O_NOFOLLOW | O_NOCTTY | O_CREAT);
if (fd == -1 || fstat(fd, &st) != 0) {
D(DEFAULT_DEBUG_FILE, "Could not open %s: %s", name, strerror(errno));
goto err;
}

#ifndef WITH_FUZZING
if (!S_ISREG(st.st_mode))
goto err;
#endif

if ((file = fdopen(fd, "a")) != NULL)
return file;
if ((file = fdopen(fd, "a")) != NULL) {
*out = file;
return 0;
}

err:
if (fd != -1)
close(fd);

return DEFAULT_DEBUG_FILE; /* fallback to default */
return -1;
}

FILE *debug_open(const char *name) {
FILE *ret;

if (debug_get_file(name, &ret))
return DEFAULT_DEBUG_FILE;

return ret;
}

void debug_close(FILE *f) {
if (f != NULL && f != stdout && f != stderr)
fclose(f);
if (f == NULL || f == stdout || f == stderr)
return;

if (fflush(f) == EOF)
D(DEFAULT_DEBUG_FILE, "Could not close debug file: %s", strerror(errno));

fclose(f);
}

FILE *debug_replace(FILE *old, const char *new_name) {
FILE *new;

if (debug_get_file(new_name, &new))
return old;

debug_close(old);
return new;
}

static void do_log(FILE *debug_file, const char *file, int line,
Expand Down
2 changes: 2 additions & 0 deletions debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@

FILE *debug_open(const char *);
void debug_close(FILE *f);
FILE *debug_replace(FILE *old, const char *new_path);

void debug_fprintf(FILE *, const char *, int, const char *, const char *, ...)
ATTRIBUTE_FORMAT(printf, 5, 6);

Expand Down
Loading
Loading