1/* 2 * Copyright (c) 2007-2009 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include <stdio.h> 25#include <stdlib.h> 26#include <stdbool.h> 27#include <errno.h> 28#include <string.h> 29#include <grp.h> 30#include <pwd.h> 31#include <membership.h> 32#include <membershipPriv.h> 33#include <sys/syslimits.h> 34 35#define _PAM_EXTERN_FUNCTIONS 36#include <security/pam_modules.h> 37#include <security/pam_appl.h> 38#include <security/openpam.h> 39 40#define MODULE_NAME "pam_sacl" 41 42/* Note to self: To enable debug logging, we also have to make the syslog 43 * *.debug level go somewhere. 44 */ 45#define DEBUG_MESSAGE(format, ...) \ 46 if (NULL != debug) { \ 47 openpam_log(PAM_LOG_DEBUG, format, __VA_ARGS__); \ 48 } 49 50 51PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags, 52 int argc, const char ** argv) 53{ 54 const char * service = NULL; 55 const char * username = NULL; 56 const char * debug = NULL; 57 bool allow_trustacct = false; 58 59 struct passwd *pwd = NULL; 60 struct passwd pwdbuf; 61 char pwbuffer[2 * PATH_MAX]; 62 63 uuid_t user_uuid; 64 int err; 65 int ismember; 66 67 service = openpam_get_option(pamh, "sacl_service"); 68 allow_trustacct = openpam_get_option(pamh, "allow_trustacct"); 69 debug = openpam_get_option(pamh, "debug"); 70 71 if (!service) { 72 DEBUG_MESSAGE("%s: missing service option", MODULE_NAME); 73 return PAM_IGNORE; 74 } 75 76 if (pam_get_user(pamh, &username, NULL) != PAM_SUCCESS || 77 username == NULL || *username == '\0') { 78 DEBUG_MESSAGE("%s: missing username", MODULE_NAME); 79 return PAM_SYSTEM_ERR; 80 } 81 82 DEBUG_MESSAGE("%s: checking if account '%s' can access service '%s'", 83 MODULE_NAME, username, service); 84 85 /* Since computer trust accounts in OD are not user accounts, you can't 86 * add them to a SACL, so we always let them through (if the option is 87 * set). A computer trust account has a username ending in '$' and no 88 * corresponding user account (ie. no passwd entry). 89 */ 90 if (allow_trustacct) { 91 const char * c; 92 93 c = strrchr(username, '$'); 94 if (c && *(c + 1) == '\0' && getpwnam_r(username, &pwdbuf, pwbuffer, sizeof(pwbuffer), &pwd) == 0) { 95 DEBUG_MESSAGE("%s: allowing '%s' because it is a " 96 "computer trust account", 97 MODULE_NAME, username); 98 return PAM_SUCCESS; 99 } 100 } 101 102 /* Get the UUID. This will fail if the user is is logging in over 103 * SMB, is specifed as DOMAIN\user or user@REALM and the directory 104 * does not have the aliases we need. 105 */ 106 if (mbr_user_name_to_uuid(username, user_uuid)) { 107 char * sacl_group; 108 109 /* We couldn't map the user to a UID, but we only care about 110 * this if the relevant SACL groups exist. 111 */ 112 113 if (asprintf(&sacl_group, "com.apple.access_%s\n", 114 service) == -1) { 115 return PAM_SYSTEM_ERR; 116 } 117 118 if (getgrnam(sacl_group) == NULL && 119 getgrnam("com.apple.access_all_services") == NULL) { 120 121 DEBUG_MESSAGE("%s: allowing '%s' " 122 "due to absence of service ACL", 123 MODULE_NAME, username); 124 125 free(sacl_group); 126 return PAM_SUCCESS; 127 } 128 129 DEBUG_MESSAGE("%s: denying '%s' due to missing UUID", 130 MODULE_NAME, username); 131 132 free(sacl_group); 133 return PAM_PERM_DENIED; 134 } 135 136 err = mbr_check_service_membership(user_uuid, service, &ismember); 137 if (err) { 138 if (err == ENOENT) { 139 /* Service ACLs not configured. */ 140 DEBUG_MESSAGE("%s: allowing '%s' " 141 "due to unconfigured service ACLs", 142 MODULE_NAME, username); 143 return PAM_SUCCESS; 144 } 145 146 DEBUG_MESSAGE("%s: denying '%s' " 147 "due to failed service ACL check (errno=%d)", 148 MODULE_NAME, username, err); 149 150 return PAM_PERM_DENIED; 151 } 152 153 if (ismember) { 154 DEBUG_MESSAGE("%s: allowing '%s'", MODULE_NAME, username); 155 return PAM_SUCCESS; 156 } else { 157 DEBUG_MESSAGE("%s: denying '%s' " 158 "due to failed service ACL check", 159 MODULE_NAME, username); 160 return PAM_PERM_DENIED; 161 } 162} 163 164#ifdef PAM_STATIC 165PAM_MODULE_ENTRY(MODULE_NAME); 166#endif 167 168