1/*- 2 * Copyright 2010 Apple Inc 3 */ 4 5#include <sys/cdefs.h> 6 7#include <sys/types.h> 8#include <sys/stat.h> 9#include <sys/param.h> 10#include <stdio.h> 11#include <stdlib.h> 12#include <string.h> 13#include <unistd.h> 14#include <pwd.h> 15 16#include <OpenDirectory/OpenDirectory.h> 17 18#include <GSS/gssapi_ntlm.h> 19#include <GSS/gssapi_spi.h> 20 21#define PAM_SM_AUTH 22#define PAM_SM_ACCOUNT 23#define PAM_SM_PASSWORD 24 25#include <security/pam_appl.h> 26#include <security/pam_modules.h> 27#include <security/openpam.h> 28 29#include "Common.h" 30 31#define PAM_OPT_DEBUG "debug" 32 33#define PAM_LOG(...) \ 34 openpam_log(PAM_LOG_DEBUG, __VA_ARGS__) 35 36#define PAM_VERBOSE_ERROR(...) \ 37openpam_log(PAM_LOG_ERROR, __VA_ARGS__) 38 39static const char *password_key = "NTLMPWD"; 40 41 42/* 43 * authentication management 44 */ 45 46PAM_EXTERN int 47pam_sm_authenticate(pam_handle_t *pamh, int flags __unused, 48 int argc __unused, const char *argv[] __unused) 49{ 50 int retval; 51 const char *password; 52 53 PAM_LOG("pam_sm_authenticate: ntlm"); 54 55 /* get password */ 56 retval = pam_get_authtok(pamh, PAM_AUTHTOK, &password, NULL); 57 if (retval != PAM_SUCCESS) 58 return retval; 59 60 retval = pam_setenv(pamh, password_key, password, 1); 61 if (retval != PAM_SUCCESS) 62 return retval; 63 64 return PAM_IGNORE; 65} 66 67static void 68ac_complete(void *ctx, OM_uint32 major, gss_status_id_t status, 69 gss_cred_id_t cred, gss_OID_set oids, OM_uint32 time_rec) 70{ 71 OM_uint32 junk; 72 gss_release_cred(&junk, &cred); 73 gss_release_oid_set(&junk, &oids); 74 PAM_LOG("ac_complete returned: %d for %d", major, geteuid()); 75} 76 77 78 79PAM_EXTERN int 80pam_sm_setcred(pam_handle_t *pamh, int flags, 81 int argc __unused, const char *argv[] __unused) 82{ 83 gss_auth_identity_desc identity; 84 const char *user, *password; 85 struct passwd *pwd; 86 struct passwd pwdbuf; 87 char pwbuffer[2 * PATH_MAX]; 88 int retval; 89 uid_t euid = geteuid(); 90 gid_t egid = getegid(); 91 ODRecordRef record = NULL; 92 CFArrayRef array = NULL; 93 CFIndex i, count; 94 95 PAM_LOG("pam_sm_setcred: ntlm"); 96 97 memset(&identity, 0, sizeof(identity)); 98 99 /* Get username */ 100 retval = pam_get_item(pamh, PAM_USER, (const void **)&user); 101 if (retval != PAM_SUCCESS) { 102 PAM_LOG("pam_sm_setcred: ntlm user can't be found"); 103 goto cleanup; 104 } 105 106 if (getpwnam_r(user, &pwdbuf, pwbuffer, sizeof(pwbuffer), &pwd) != 0 || pwd == NULL) { 107 PAM_LOG("pam_sm_setcred: ntlm user %s doesn't exists", user); 108 retval = PAM_USER_UNKNOWN; 109 goto cleanup; 110 } 111 112 password = pam_getenv(pamh, password_key); 113 if (password == NULL) { 114 PAM_LOG("pam_sm_setcred: ntlm user %s doesn't have a password", user); 115 retval = PAM_IGNORE; 116 goto cleanup; 117 } 118 119 retval = od_record_create_cstring(pamh, &record, user); 120 if (retval || record == NULL) { 121 retval = PAM_IGNORE; 122 goto cleanup; 123 } 124 125 array = ODRecordCopyValues(record, kODAttributeTypeAuthenticationAuthority, NULL); 126 if (array == NULL) { 127 PAM_LOG("pam_sm_setcred: ntlm user %s doesn't have auth authority", user); 128 retval = PAM_IGNORE; 129 goto cleanup; 130 } 131 132 identity.username = (char *)user; 133 identity.password = (char *)password; 134 135 count = CFArrayGetCount(array); 136 for (i = 0; i < count && identity.realm == NULL; i++) { 137 CFStringRef val = CFArrayGetValueAtIndex(array, i); 138 if (NULL == val || CFGetTypeID(val) != CFStringGetTypeID()) 139 break; 140 141 if (!CFStringHasPrefix(val, CFSTR(";NetLogon;"))) 142 continue; 143 144 CFArrayRef parts = CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, val, CFSTR(";")); 145 if (parts == NULL) 146 continue; 147 148 if (CFArrayGetCount(parts) < 4) { 149 CFRelease(parts); 150 continue; 151 } 152 153 CFStringRef domain = CFArrayGetValueAtIndex(parts, 3); 154 155 retval = cfstring_to_cstring(domain, &identity.realm); 156 CFRelease(parts); 157 if (retval) 158 goto cleanup; 159 } 160 161 if (identity.realm == NULL) { 162 PAM_LOG("pam_sm_setcred: no domain found skipping"); 163 retval = PAM_IGNORE; 164 goto cleanup; 165 } 166 167 if (euid == 0) { 168 if (setegid(pwd->pw_gid) != 0) { 169 retval = PAM_SERVICE_ERR; 170 goto cleanup; 171 } 172 if (seteuid(pwd->pw_uid) != 0) { 173 retval = PAM_SERVICE_ERR; 174 goto cleanup; 175 } 176 } 177 178 (void)gss_acquire_cred_ex_f(NULL, 179 GSS_C_NO_NAME, 180 0, 181 GSS_C_INDEFINITE, 182 GSS_NTLM_MECHANISM, 183 GSS_C_INITIATE, 184 &identity, 185 NULL, 186 ac_complete); 187 188 if (euid == 0) { 189 seteuid(euid); 190 setegid(egid); 191 } 192 193 PAM_LOG("pam_sm_setcred: ntlm done, used domain: %s", identity.realm); 194 195cleanup: 196 if (record) 197 CFRelease(record); 198 if (array) 199 CFRelease(array); 200 if (identity.realm) 201 free(identity.realm); 202 pam_unsetenv(pamh, password_key); 203 return retval; 204} 205 206/* 207 * account management 208 */ 209PAM_EXTERN int 210pam_sm_acct_mgmt(pam_handle_t *pamh, int flags __unused, 211 int argc __unused, const char *argv[] __unused) 212{ 213 return PAM_SUCCESS; 214} 215 216/* 217 * password management 218 */ 219PAM_EXTERN int 220pam_sm_chauthtok(pam_handle_t *pamh, int flags, 221 int argc __unused, const char *argv[] __unused) 222{ 223 return PAM_AUTHTOK_ERR; 224} 225 226PAM_MODULE_ENTRY("pam_ntlm"); 227