#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <errno.h>
#include <string.h>
#include <grp.h>
#include <pwd.h>
#include <syslog.h>
#include <membership.h>
#include <membershipPriv.h>
#define _PAM_EXTERN_FUNCTIONS
#include <security/pam_modules.h>
#include <security/pam_appl.h>
#include <security/openpam.h>
#define MODULE_NAME "pam_sacl"
#define DEBUG_MESSAGE(format, ...) \
if (NULL != debug) { \
syslog(LOG_DEBUG, format, __VA_ARGS__); \
}
PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags,
int argc, const char ** argv)
{
const char * service = NULL;
const char * username = NULL;
const char * debug = NULL;
bool allow_trustacct = false;
uuid_t user_uuid;
int err;
int ismember;
service = openpam_get_option(pamh, "sacl_service");
allow_trustacct = openpam_get_option(pamh, "allow_trustacct");
debug = openpam_get_option(pamh, "debug");
if (!service) {
DEBUG_MESSAGE("%s: missing service option", MODULE_NAME);
return PAM_IGNORE;
}
if (pam_get_user(pamh, &username, NULL) != PAM_SUCCESS ||
username == NULL || *username == '\0') {
DEBUG_MESSAGE("%s: missing username", MODULE_NAME);
return PAM_SYSTEM_ERR;
}
DEBUG_MESSAGE("%s: checking if account '%s' can access service '%s'",
MODULE_NAME, username, service);
if (allow_trustacct) {
const char * c;
c = strrchr(username, '$');
if (c && *(c + 1) == '\0' && getpwnam(username) == NULL) {
DEBUG_MESSAGE("%s: allowing '%s' because it is a "
"computer trust account",
MODULE_NAME, username);
return PAM_SUCCESS;
}
}
if (mbr_user_name_to_uuid(username, user_uuid)) {
char * sacl_group;
if (asprintf(&sacl_group, "com.apple.access_%s\n",
service) == -1) {
return PAM_SYSTEM_ERR;
}
if (getgrnam(sacl_group) == NULL &&
getgrnam("com.apple.access_all_services") == NULL) {
DEBUG_MESSAGE("%s: allowing '%s' "
"due to absence of service ACL",
MODULE_NAME, username);
free(sacl_group);
return PAM_SUCCESS;
}
DEBUG_MESSAGE("%s: denying '%s' due to missing UUID",
MODULE_NAME, username);
free(sacl_group);
return PAM_PERM_DENIED;
}
err = mbr_check_service_membership(user_uuid, service, &ismember);
if (err) {
if (err == ENOENT) {
DEBUG_MESSAGE("%s: allowing '%s' "
"due to unconfigured service ACLs",
MODULE_NAME, username);
return PAM_SUCCESS;
}
DEBUG_MESSAGE("%s: denying '%s' "
"due to failed service ACL check (errno=%d)",
MODULE_NAME, username, err);
return PAM_PERM_DENIED;
}
if (ismember) {
DEBUG_MESSAGE("%s: allowing '%s'", MODULE_NAME);
return PAM_SUCCESS;
} else {
DEBUG_MESSAGE("%s: denying '%s' "
"due to failed service ACL check",
MODULE_NAME, username);
return PAM_PERM_DENIED;
}
}
#ifdef PAM_STATIC
PAM_MODULE_ENTRY(MODULE_NAME);
#endif