19fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan/*
2aadd6fad3f09bd5abcaacf8618fb8093a5aa7ba8Andrew Morgan * Copyright (c) 1999,2007 Andrew G. Morgan <morgan@kernel.org>
39fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan *
49fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan * The purpose of this module is to enforce inheritable capability sets
59fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan * for a specified user.
69fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan */
79fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
89fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan/* #define DEBUG */
99fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
109fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan#include <stdio.h>
119fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan#include <string.h>
129fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan#include <errno.h>
139fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan#include <stdarg.h>
14aadd6fad3f09bd5abcaacf8618fb8093a5aa7ba8Andrew Morgan#include <stdlib.h>
15aadd6fad3f09bd5abcaacf8618fb8093a5aa7ba8Andrew Morgan#include <syslog.h>
169fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
179fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan#include <sys/capability.h>
189fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
199fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan#include <security/pam_modules.h>
209fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan#include <security/_pam_macros.h>
219fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
229fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan#define USER_CAP_FILE           "/etc/security/capability.conf"
239fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan#define CAP_FILE_BUFFER_SIZE    4096
249fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan#define CAP_FILE_DELIMITERS     " \t\n"
259fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan#define CAP_COMBINED_FORMAT     "%s all-i %s+i"
269fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan#define CAP_DROP_ALL            "%s all-i"
279fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
289fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morganstruct pam_cap_s {
299fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    int debug;
309fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    const char *user;
319fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    const char *conf_filename;
329fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan};
339fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
349fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan/* obtain the inheritable capabilities for the current user */
359fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
369fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morganstatic char *read_capabilities_for_user(const char *user, const char *source)
379fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan{
389fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    char *cap_string = NULL;
399fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    char buffer[CAP_FILE_BUFFER_SIZE], *line;
409fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    FILE *cap_file;
419fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
429fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    cap_file = fopen(source, "r");
439fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    if (cap_file == NULL) {
449fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	D(("failed to open capability file"));
459fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	return NULL;
469fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    }
479fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
489fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    while ((line = fgets(buffer, CAP_FILE_BUFFER_SIZE, cap_file))) {
499fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	int found_one = 0;
509fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	const char *cap_text;
519fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
529fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	cap_text = strtok(line, CAP_FILE_DELIMITERS);
539fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
549fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	if (cap_text == NULL) {
559fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	    D(("empty line"));
569fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	    continue;
579fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	}
589fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	if (*cap_text == '#') {
599fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	    D(("comment line"));
609fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	    continue;
619fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	}
629fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
63aadd6fad3f09bd5abcaacf8618fb8093a5aa7ba8Andrew Morgan	while ((line = strtok(NULL, CAP_FILE_DELIMITERS))) {
649fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
659fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	    if (strcmp("*", line) == 0) {
669fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan		D(("wildcard matched"));
679fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan		found_one = 1;
689fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan		cap_string = strdup(cap_text);
699fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan		break;
709fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	    }
719fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
729fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	    if (strcmp(user, line) == 0) {
739fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan		D(("exact match for user"));
749fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan		found_one = 1;
759fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan		cap_string = strdup(cap_text);
769fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan		break;
779fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	    }
789fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
799fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	    D(("user is not [%s] - skipping", line));
809fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	}
819fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
829fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	cap_text = NULL;
839fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	line = NULL;
849fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
859fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	if (found_one) {
869fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	    D(("user [%s] matched - caps are [%s]", user, cap_string));
879fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	    break;
889fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	}
899fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    }
909fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
919fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    fclose(cap_file);
929fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
939fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    memset(buffer, 0, CAP_FILE_BUFFER_SIZE);
949fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
959fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    return cap_string;
969fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan}
979fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
989fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan/*
999fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan * Set capabilities for current process to match the current
1009fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan * permitted+executable sets combined with the configured inheritable
1019fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan * set.
1029fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan */
1039fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
1049fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morganstatic int set_capabilities(struct pam_cap_s *cs)
1059fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan{
1069fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    cap_t cap_s;
1079fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    ssize_t length = 0;
1089fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    char *conf_icaps;
1099fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    char *proc_epcaps;
1109fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    char *combined_caps;
1119fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    int ok = 0;
1129fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
1139fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    cap_s = cap_get_proc();
1149fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    if (cap_s == NULL) {
1159fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	D(("your kernel is capability challenged - upgrade: %s",
1169fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	   strerror(errno)));
1179fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	return 0;
1189fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    }
1199fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
1209fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    conf_icaps =
1219fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	read_capabilities_for_user(cs->user,
1229fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan				   cs->conf_filename
1239fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan				   ? cs->conf_filename:USER_CAP_FILE );
1249fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    if (conf_icaps == NULL) {
1259fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	D(("no capabilities found for user [%s]", cs->user));
1269fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	goto cleanup_cap_s;
1279fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    }
1289fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
1299fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    proc_epcaps = cap_to_text(cap_s, &length);
1309fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    if (proc_epcaps == NULL) {
1319fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	D(("unable to convert process capabilities to text"));
1329fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	goto cleanup_icaps;
1339fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    }
1349fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
1359fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    /*
1369fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan     * This is a pretty inefficient way to combine
1379fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan     * capabilities. However, it seems to be the most straightforward
1389fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan     * one, given the limitations of the POSIX.1e draft spec. The spec
1399fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan     * is optimized for applications that know the capabilities they
1409fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan     * want to manipulate at compile time.
1419fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan     */
1429fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
1439fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    combined_caps = malloc(1+strlen(CAP_COMBINED_FORMAT)
1449fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan			   +strlen(proc_epcaps)+strlen(conf_icaps));
1459fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    if (combined_caps == NULL) {
1469fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	D(("unable to combine capabilities into one string - no memory"));
1479fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	goto cleanup_epcaps;
1489fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    }
1499fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
1509fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    if (!strcmp(conf_icaps, "none")) {
1519fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	sprintf(combined_caps, CAP_DROP_ALL, proc_epcaps);
1529fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    } else if (!strcmp(conf_icaps, "all")) {
1539fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	/* no change */
1549fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	sprintf(combined_caps, "%s", proc_epcaps);
1559fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    } else {
1569fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	sprintf(combined_caps, CAP_COMBINED_FORMAT, proc_epcaps, conf_icaps);
1579fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    }
1589fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    D(("combined_caps=[%s]", combined_caps));
1599fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
1609fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    cap_free(cap_s);
1619fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    cap_s = cap_from_text(combined_caps);
1629fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    _pam_overwrite(combined_caps);
1639fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    _pam_drop(combined_caps);
1649fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
1659fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan#ifdef DEBUG
1669fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    {
1679fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan        char *temp = cap_to_text(cap_s, NULL);
1689fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	D(("abbreviated caps for process will be [%s]", temp));
1699fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	cap_free(temp);
1709fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    }
1719fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan#endif /* DEBUG */
1729fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
1739fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    if (cap_s == NULL) {
1749fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	D(("no capabilies to set"));
1759fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    } else if (cap_set_proc(cap_s) == 0) {
1769fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	D(("capabilities were set correctly"));
1779fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	ok = 1;
1789fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    } else {
1799fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	D(("failed to set specified capabilities: %s", strerror(errno)));
1809fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    }
1819fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
1829fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgancleanup_epcaps:
1839fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    cap_free(proc_epcaps);
1849fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
1859fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgancleanup_icaps:
1869fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    _pam_overwrite(conf_icaps);
1879fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    _pam_drop(conf_icaps);
1889fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
1899fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgancleanup_cap_s:
1909fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    if (cap_s) {
1919fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	cap_free(cap_s);
1929fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	cap_s = NULL;
1939fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    }
194aadd6fad3f09bd5abcaacf8618fb8093a5aa7ba8Andrew Morgan
1959fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    return ok;
1969fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan}
1979fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
1989fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan/* log errors */
1999fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2009fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morganstatic void _pam_log(int err, const char *format, ...)
2019fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan{
2029fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    va_list args;
2039fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2049fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    va_start(args, format);
2059fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    openlog("pam_cap", LOG_CONS|LOG_PID, LOG_AUTH);
2069fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    vsyslog(err, format, args);
2079fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    va_end(args);
2089fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    closelog();
2099fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan}
2109fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2119fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morganstatic void parse_args(int argc, const char **argv, struct pam_cap_s *pcs)
2129fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan{
2139fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    int ctrl=0;
2149fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2159fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    /* step through arguments */
2169fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    for (ctrl=0; argc-- > 0; ++argv) {
2179fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2189fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	if (!strcmp(*argv, "debug")) {
2199fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	    pcs->debug = 1;
220627017564a647d46a5ec924b0484d22575956920Andrew G. Morgan	} else if (!memcmp(*argv, "config=", 7)) {
221627017564a647d46a5ec924b0484d22575956920Andrew G. Morgan	    pcs->conf_filename = 7 + *argv;
2229fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	} else {
2239fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	    _pam_log(LOG_ERR, "unknown option; %s", *argv);
2249fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	}
2259fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2269fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    }
2279fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan}
2289fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2299fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morganint pam_sm_authenticate(pam_handle_t *pamh, int flags,
2309fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan			int argc, const char **argv)
2319fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan{
2329fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    int retval;
2339fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    struct pam_cap_s pcs;
2349fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    char *conf_icaps;
2359fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2369fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    memset(&pcs, 0, sizeof(pcs));
2379fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2389fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    parse_args(argc, argv, &pcs);
2399fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2409fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    retval = pam_get_user(pamh, &pcs.user, NULL);
2419fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2429fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    if (retval == PAM_CONV_AGAIN) {
2439fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	D(("user conversation is not available yet"));
2449fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	memset(&pcs, 0, sizeof(pcs));
2459fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	return PAM_INCOMPLETE;
2469fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    }
2479fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2489fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    if (retval != PAM_SUCCESS) {
2499fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	D(("pam_get_user failed: %s", pam_strerror(pamh, retval)));
2509fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	memset(&pcs, 0, sizeof(pcs));
2519fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	return PAM_AUTH_ERR;
2529fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    }
2539fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2549fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    conf_icaps =
2559fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	read_capabilities_for_user(pcs.user,
2569fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan				   pcs.conf_filename
2579fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan				   ? pcs.conf_filename:USER_CAP_FILE );
2589fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2599fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    memset(&pcs, 0, sizeof(pcs));
2609fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2619fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    if (conf_icaps) {
2629fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	D(("it appears that there are capabilities for this user [%s]",
2639fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	   conf_icaps));
2649fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2659fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	/* We could also store this as a pam_[gs]et_data item for use
2669fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	   by the setcred call to follow. As it is, there is a small
2679fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	   race associated with a redundant read. Oh well, if you
2689fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	   care, send me a patch.. */
2699fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2709fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	_pam_overwrite(conf_icaps);
2719fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	_pam_drop(conf_icaps);
2729fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2739fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	return PAM_SUCCESS;
2749fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2759fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    } else {
2769fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2779fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	D(("there are no capabilities restrctions on this user"));
2789fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	return PAM_IGNORE;
2799fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2809fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    }
2819fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan}
2829fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2839fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morganint pam_sm_setcred(pam_handle_t *pamh, int flags,
2849fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan		   int argc, const char **argv)
2859fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan{
2869fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    int retval;
2879fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    struct pam_cap_s pcs;
2889fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2899fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    if (!(flags & PAM_ESTABLISH_CRED)) {
2909fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	D(("we don't handle much in the way of credentials"));
2919fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	return PAM_IGNORE;
2929fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    }
2939fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2949fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    memset(&pcs, 0, sizeof(pcs));
2959fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2969fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    parse_args(argc, argv, &pcs);
2979fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
2989fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    retval = pam_get_item(pamh, PAM_USER, (const void **)&pcs.user);
2999fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    if ((retval != PAM_SUCCESS) || (pcs.user == NULL) || !(pcs.user[0])) {
3009fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
3019fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	D(("user's name is not set"));
3029fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan	return PAM_AUTH_ERR;
3039fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    }
3049fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
3059fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    retval = set_capabilities(&pcs);
3069fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
3079fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    memset(&pcs, 0, sizeof(pcs));
3089fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan
3099fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan    return (retval ? PAM_SUCCESS:PAM_IGNORE );
3109fe5d0568f1e1a2c103a3293db87be075f8c1558Andrew Morgan}
311