int cfstring_to_cstring(const CFStringRef val, char **buffer) { CFIndex maxlen = 0; int retval = PAM_BUF_ERR; if (NULL == val || NULL == buffer) { openpam_log(PAM_LOG_DEBUG, "NULL argument passed"); retval = PAM_SERVICE_ERR; goto cleanup; } maxlen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(val), kCFStringEncodingUTF8); *buffer = calloc(maxlen + 1, sizeof(char)); if (NULL == *buffer) { openpam_log(PAM_LOG_DEBUG, "malloc() failed"); retval = PAM_BUF_ERR; goto cleanup; } if (CFStringGetCString(val, *buffer, maxlen + 1, kCFStringEncodingUTF8)) { retval = PAM_SUCCESS; } else { openpam_log(PAM_LOG_DEBUG, "CFStringGetCString failed."); free(*buffer); *buffer = NULL; } cleanup: if (PAM_SUCCESS != retval) openpam_log(PAM_LOG_ERROR, "failed: %d", retval); return retval; }
int cstring_to_cfstring(const char *val, CFStringRef *buffer) { int retval = PAM_BUF_ERR; if (NULL == val || NULL == buffer) { openpam_log(PAM_LOG_DEBUG, "NULL argument passed"); retval = PAM_SERVICE_ERR; goto cleanup; } *buffer = CFStringCreateWithCString(kCFAllocatorDefault, val, kCFStringEncodingUTF8); if (NULL == *buffer) { openpam_log(PAM_LOG_DEBUG, "CFStringCreateWithCString() failed"); retval = PAM_BUF_ERR; goto cleanup; } retval = PAM_SUCCESS; cleanup: if (PAM_SUCCESS != retval) openpam_log(PAM_LOG_ERROR, "failed: %d", retval); return retval; }
static char * prompt_echo_off(const char *msg, FILE *infp, FILE *outfp, FILE *errfp) { struct termios tattr; tcflag_t lflag; char *ret; int fd; fd = fileno(infp); if (tcgetattr(fd, &tattr) != 0) { openpam_log(PAM_LOG_ERROR, "tcgetattr(): %s", strerror(errno)); return (NULL); } lflag = tattr.c_lflag; tattr.c_lflag &= ~ECHO; if (tcsetattr(fd, TCSAFLUSH, &tattr) != 0) { openpam_log(PAM_LOG_ERROR, "tcsetattr(): %s", strerror(errno)); return (NULL); } ret = prompt(msg, infp, outfp, errfp); tattr.c_lflag = lflag; (void)tcsetattr(fd, TCSANOW, &tattr); if (ret != NULL) fputs("\n", outfp); return (ret); }
static void * try_dlopen(const char *modfn, int *error) { void *dlh; int fd; openpam_log(PAM_LOG_LIBDEBUG, "dlopen(%s)", modfn); if ((fd = open(modfn, O_RDONLY)) < 0) { if (errno != ENOENT) openpam_log(PAM_LOG_ERROR, "%s: %m", modfn); return (NULL); } if (OPENPAM_FEATURE(VERIFY_MODULE_FILE) && openpam_check_desc_owner_perms(modfn, fd) != 0) { close(fd); return (NULL); } if ((dlh = fdlopen(fd, RTLD_NOW)) == NULL) { openpam_log(PAM_LOG_ERROR, "%s: %s", modfn, dlerror()); close(fd); errno = 0; return (NULL); } close(fd); return (dlh); }
int od_record_check_pwpolicy(ODRecordRef record) { CFDictionaryRef policy = NULL; const void *isDisabled; const void *newPasswordRequired; int retval = PAM_SERVICE_ERR; if (NULL == record) { openpam_log(PAM_LOG_DEBUG, "NULL argument passed"); retval = PAM_SERVICE_ERR; goto cleanup; } if (NULL == (policy = ODRecordCopyPasswordPolicy(kCFAllocatorDefault, record, NULL)) || NULL == (isDisabled = CFDictionaryGetValue(policy, CFSTR("isDisabled"))) || !cfboolean_get_value(isDisabled)) retval = PAM_SUCCESS; else retval = PAM_PERM_DENIED; if (NULL != policy && NULL != (newPasswordRequired = CFDictionaryGetValue(policy, CFSTR("newPasswordRequired"))) && cfboolean_get_value(newPasswordRequired)) retval = PAM_NEW_AUTHTOK_REQD; if (NULL != policy) { CFRelease(policy); } cleanup: openpam_log(PAM_LOG_DEBUG, "retval: %d", retval); return retval; }
int od_record_create_cstring(pam_handle_t *pamh, ODRecordRef *record, const char *user) { int retval = PAM_SUCCESS; CFStringRef cfUser = NULL; if (NULL == record || NULL == user) { openpam_log(PAM_LOG_DEBUG, "NULL argument passed"); retval = PAM_SERVICE_ERR; goto cleanup; } if (PAM_SUCCESS != (retval = cstring_to_cfstring(user, &cfUser)) || PAM_SUCCESS != (retval = od_record_create(pamh, record, cfUser))) { openpam_log(PAM_LOG_DEBUG, "od_record_create() failed"); goto cleanup; } cleanup: if (PAM_SUCCESS != retval) { openpam_log(PAM_LOG_ERROR, "failed: %d", retval); if (NULL != *record) { CFRelease(*record); } } if (NULL != cfUser) { CFRelease(cfUser); } return retval; }
int openpam_straddch(char **str, size_t *size, size_t *len, int ch) { size_t tmpsize; char *tmpstr; if (*str == NULL) { /* initial allocation */ tmpsize = MIN_STR_SIZE; if ((tmpstr = malloc(tmpsize)) == NULL) { openpam_log(PAM_LOG_ERROR, "malloc(): %m"); errno = ENOMEM; return (-1); } *str = tmpstr; *size = tmpsize; *len = 0; } else if (ch != 0 && *len + 1 >= *size) { /* additional space required */ tmpsize = *size * 2; if ((tmpstr = realloc(*str, tmpsize)) == NULL) { openpam_log(PAM_LOG_ERROR, "realloc(): %m"); errno = ENOMEM; return (-1); } *size = tmpsize; *str = tmpstr; } if (ch != 0) { (*str)[*len] = ch; ++*len; } (*str)[*len] = '\0'; return (0); }
/* * Attempts to load a private key from the specified file in the specified * directory, using the specified passphrase. If successful, returns a * struct pam_ssh_key containing the key and its comment. */ static struct pam_ssh_key * pam_ssh_load_key(const char *dir, const char *kfn, const char *passphrase) { struct pam_ssh_key *psk; char fn[PATH_MAX]; char *comment; Key *key; if (snprintf(fn, sizeof(fn), "%s/%s", dir, kfn) > (int)sizeof(fn)) return (NULL); comment = NULL; key = key_load_private(fn, passphrase, &comment); if (key == NULL) { openpam_log(PAM_LOG_DEBUG, "failed to load key from %s\n", fn); return (NULL); } openpam_log(PAM_LOG_DEBUG, "loaded '%s' from %s\n", comment, fn); if ((psk = malloc(sizeof(*psk))) == NULL) { key_free(key); free(comment); return (NULL); } psk->key = key; psk->comment = comment; return (psk); }
pam_module_t * openpam_dynamic(const char *path) { const pam_module_t *dlmodule; pam_module_t *module; const char *prefix, *epath = path; char *vpath; void *dlh; int i, serrno; dlh = NULL; /* Prepend the standard prefix if not an absolute pathname. */ if (path[0] != '/') prefix = OPENPAM_MODULES_DIR; else prefix = ""; /* try versioned module first, then unversioned module */ if (asprintf(&vpath, "%s/%s.%d", prefix, path, LIB_MAJ) < 0) goto err; epath = vpath; if ((dlh = try_dlopen(vpath)) == NULL && errno == ENOENT) { *strrchr(vpath, '.') = '\0'; dlh = try_dlopen(vpath); } serrno = errno; FREE(vpath); errno = serrno; if (dlh == NULL) goto err; if ((module = calloc((size_t)1, sizeof *module)) == NULL) goto buf_err; if ((module->path = strdup(path)) == NULL) goto buf_err; module->dlh = dlh; dlmodule = dlsym(dlh, "_pam_module"); for (i = 0; i < PAM_NUM_PRIMITIVES; ++i) { module->func[i] = dlmodule ? dlmodule->func[i] : (pam_func_t)dlsym(dlh, pam_sm_func_name[i]); if (module->func[i] == NULL) openpam_log(PAM_LOG_DEBUG, "%s: %s(): %s", path, pam_sm_func_name[i], dlerror()); } return (module); buf_err: serrno = errno; if (dlh != NULL) dlclose(dlh); FREE(module); errno = serrno; err: openpam_log(errno == ENOENT ? PAM_LOG_DEBUG : PAM_LOG_ERROR, "%s: %s", epath, strerror(errno)); return (NULL); }
char * openpam_readline(FILE *f, int *lineno, size_t *lenp) { char *line; size_t len, size; int ch; if ((line = malloc(size = MIN_LINE_LENGTH)) == NULL) { openpam_log(PAM_LOG_ERROR, "malloc(): %m"); return (NULL); } len = 0; for (;;) { ch = fgetc(f); /* strip comment */ if (ch == '#') { do { ch = fgetc(f); } while (ch != EOF && ch != '\n'); } /* eof */ if (ch == EOF) { /* done */ break; } /* eol */ if (ch == '\n') { if (lineno != NULL) ++*lineno; /* skip blank lines */ if (len == 0) continue; /* continuation */ if (line[len - 1] == '\\') { line[--len] = '\0'; continue; } /* done */ break; } /* anything else */ if (openpam_straddch(&line, &size, &len, ch) != 0) goto fail; } if (len == 0) goto fail; if (lenp != NULL) *lenp = len; openpam_log(PAM_LOG_LIBDEBUG, "returning '%s'", line); return (line); fail: FREE(line); return (NULL); }
/* * Try to load a module from the suggested location. */ static pam_module_t * try_module(const char *modpath) { const pam_module_t *dlmodule; pam_module_t *module; int i, serrno; if ((module = calloc(1, sizeof *module)) == NULL || (module->path = strdup(modpath)) == NULL || (module->dlh = try_dlopen(modpath)) == NULL) goto err; dlmodule = dlsym(module->dlh, "_pam_module"); for (i = 0; i < PAM_NUM_PRIMITIVES; ++i) { if (dlmodule) { module->func[i] = dlmodule->func[i]; } else { module->func[i] = (pam_func_t)dlfunc(module->dlh, pam_sm_func_name[i]); /* * This openpam_log() call is a major source of * log spam, and the cases that matter are caught * and logged in openpam_dispatch(). This would * be less problematic if dlerror() returned an * error code so we could log an error only when * dlfunc() failed for a reason other than "no * such symbol". */ #if 0 if (module->func[i] == NULL) openpam_log(PAM_LOG_LIBDEBUG, "%s: %s(): %s", modpath, pam_sm_func_name[i], dlerror()); #endif } } return (module); err: serrno = errno; if (module != NULL) { if (module->dlh != NULL) dlclose(module->dlh); if (module->path != NULL) FREE(module->path); FREE(module); } errno = serrno; if (serrno != 0 && serrno != ENOENT) openpam_log(PAM_LOG_ERROR, "%s: %m", modpath); errno = serrno; return (NULL); }
int od_record_check_homedir(ODRecordRef record) { int retval = PAM_SERVICE_ERR; CFStringRef tmp = NULL; if (NULL == record) { openpam_log(PAM_LOG_DEBUG, "NULL argument passed"); retval = PAM_SERVICE_ERR; goto cleanup; } retval = od_record_attribute_create_cfstring(record, kODAttributeTypeNFSHomeDirectory, &tmp); if (PAM_SUCCESS != retval) { openpam_log(PAM_LOG_DEBUG, "od_record_attribute_create_cfstring() failed"); goto cleanup; } /* Allow NULL home directories */ if (NULL == tmp) { retval = PAM_SUCCESS; goto cleanup; } /* Do not allow login with '/dev/null' home */ if (kCFCompareEqualTo == CFStringCompare(tmp, CFSTR("/dev/null"), 0)) { openpam_log(PAM_LOG_DEBUG, "home directory is /dev/null"); retval = PAM_PERM_DENIED; goto cleanup; } if (kCFCompareEqualTo == CFStringCompare(tmp, CFSTR("99"), 0)) { openpam_log(PAM_LOG_DEBUG, "home directory is 99"); retval = PAM_PERM_DENIED; goto cleanup; } retval = PAM_SUCCESS; cleanup: if (PAM_SUCCESS != retval) openpam_log(PAM_LOG_ERROR, "failed: %d", retval); if (NULL != tmp) { CFRelease(tmp); } return retval; }
int od_string_from_record(ODRecordRef record, CFStringRef attrib, char **out) { int retval = PAM_SERVICE_ERR; CFStringRef val = NULL; if (NULL == record) { openpam_log(PAM_LOG_DEBUG, "%s - NULL ODRecord passed.", __func__); goto cleanup; } retval = od_record_attribute_create_cfstring(record, attrib, &val); if (PAM_SUCCESS != retval) { goto cleanup; } if (val) retval = cfstring_to_cstring(val, out); cleanup: if (val) CFRelease(val); return retval; }
int pam_start(const char *service, const char *user, const struct pam_conv *pam_conv, pam_handle_t **pamh) { char hostname[HOST_NAME_MAX + 1]; struct pam_handle *ph; int r; ENTER(); if ((ph = calloc(1, sizeof *ph)) == NULL) RETURNC(PAM_BUF_ERR); if ((r = pam_set_item(ph, PAM_SERVICE, service)) != PAM_SUCCESS) goto fail; if (gethostname(hostname, sizeof hostname) != 0) strlcpy(hostname, "localhost", sizeof hostname); if ((r = pam_set_item(ph, PAM_HOST, hostname)) != PAM_SUCCESS) goto fail; if ((r = pam_set_item(ph, PAM_USER, user)) != PAM_SUCCESS) goto fail; if ((r = pam_set_item(ph, PAM_CONV, pam_conv)) != PAM_SUCCESS) goto fail; if ((r = openpam_configure(ph, service)) != PAM_SUCCESS) goto fail; *pamh = ph; openpam_log(PAM_LOG_DEBUG, "pam_start(\"%s\") succeeded", service); RETURNC(PAM_SUCCESS); fail: pam_end(ph, r); RETURNC(r); }
int pam_vprompt(const pam_handle_t *pamh, int style, char **resp, const char *fmt, va_list ap) { char msgbuf[PAM_MAX_MSG_SIZE]; struct pam_message msg; const struct pam_message *msgp; struct pam_response *rsp; const struct pam_conv *conv; const void *convp; int r; ENTER(); r = pam_get_item(pamh, PAM_CONV, &convp); if (r != PAM_SUCCESS) RETURNC(r); conv = convp; if (conv == NULL || conv->conv == NULL) { openpam_log(PAM_LOG_ERROR, "no conversation function"); RETURNC(PAM_SYSTEM_ERR); } vsnprintf(msgbuf, (size_t)PAM_MAX_MSG_SIZE, fmt, ap); msg.msg_style = style; msg.msg = msgbuf; msgp = &msg; rsp = NULL; r = (conv->conv)(1, &msgp, &rsp, conv->appdata_ptr); *resp = rsp == NULL ? NULL : rsp->resp; FREE(rsp); RETURNC(r); /*NOTREACHED*/ }
int openpam_configure(pam_handle_t *pamh, const char *service) { pam_facility_t fclt; int serrno; ENTERS(service); if (!valid_service_name(service)) { openpam_log(PAM_LOG_ERROR, "invalid service name"); RETURNC(PAM_SYSTEM_ERR); } if (openpam_load_chain(pamh, service, PAM_FACILITY_ANY) < 0) { if (errno != ENOENT) goto load_err; } for (fclt = 0; fclt < PAM_NUM_FACILITIES; ++fclt) { if (pamh->chains[fclt] != NULL) continue; if (openpam_load_chain(pamh, PAM_OTHER, fclt) < 0) goto load_err; } RETURNC(PAM_SUCCESS); load_err: serrno = errno; openpam_clear_chains(pamh->chains); errno = serrno; RETURNC(PAM_SYSTEM_ERR); }
int openpam_configure(pam_handle_t *pamh, const char *service) { pam_facility_t fclt; int serrno; ENTERS(service); if (!valid_service_name(service)) { openpam_log(PAM_LOG_ERROR, "invalid service name"); RETURNC(PAM_SYSTEM_ERR); } if (openpam_load_chain(pamh, service, PAM_FACILITY_ANY) < 0) goto load_err; for (fclt = 0; fclt < PAM_NUM_FACILITIES; ++fclt) { if (pamh->chains[fclt] != NULL) continue; if (openpam_load_chain(pamh, PAM_OTHER, fclt) < 0) goto load_err; } #ifdef __NetBSD__ /* * On NetBSD we require the AUTH chain to have a binding * or a required module. */ { pam_chain_t *this = pamh->chains[PAM_AUTH]; for (; this != NULL; this = this->next) if (this->flag == PAM_BINDING || this->flag == PAM_REQUIRED) break; if (this == NULL) { openpam_log(PAM_LOG_ERROR, "No required or binding component " "in service %s, facility %s", service, pam_facility_name[PAM_AUTH]); goto load_err; } } #endif RETURNC(PAM_SUCCESS); load_err: serrno = errno; openpam_clear_chains(pamh->chains); errno = serrno; RETURNC(PAM_SYSTEM_ERR); }
int openpam_borrow_cred(pam_handle_t *pamh, const struct passwd *pwd) { struct pam_saved_cred *scred; const void *scredp; int r; ENTERI(pwd->pw_uid); r = pam_get_data(pamh, PAM_SAVED_CRED, &scredp); if (r == PAM_SUCCESS && scredp != NULL) { openpam_log(PAM_LOG_DEBUG, "already operating under borrowed credentials"); RETURNC(PAM_SYSTEM_ERR); } if (geteuid() != 0 && geteuid() != pwd->pw_uid) { openpam_log(PAM_LOG_DEBUG, "called with non-zero euid: %d", (int)geteuid()); RETURNC(PAM_PERM_DENIED); } scred = calloc((size_t)1, sizeof *scred); if (scred == NULL) RETURNC(PAM_BUF_ERR); scred->euid = geteuid(); scred->egid = getegid(); r = getgroups(NGROUPS_MAX, scred->groups); if (r < 0) { FREE(scred); RETURNC(PAM_SYSTEM_ERR); } scred->ngroups = r; r = pam_set_data(pamh, PAM_SAVED_CRED, scred, &openpam_free_data); if (r != PAM_SUCCESS) { FREE(scred); RETURNC(r); } if (geteuid() == pwd->pw_uid) RETURNC(PAM_SUCCESS); if (initgroups(pwd->pw_name, pwd->pw_gid) < 0 || setegid(pwd->pw_gid) < 0 || seteuid(pwd->pw_uid) < 0) { openpam_restore_cred(pamh); RETURNC(PAM_SYSTEM_ERR); } RETURNC(PAM_SUCCESS); /*NOTREACHED*/ }
static void openpam_check_error_code(int primitive, int r) { /* common error codes */ if (r == PAM_SUCCESS || r == PAM_SYSTEM_ERR || r == PAM_SERVICE_ERR || r == PAM_BUF_ERR || r == PAM_CONV_ERR || r == PAM_PERM_DENIED || r == PAM_ABORT) return; /* specific error codes */ switch (primitive) { case PAM_SM_AUTHENTICATE: if (r == PAM_AUTH_ERR || r == PAM_CRED_INSUFFICIENT || r == PAM_AUTHINFO_UNAVAIL || r == PAM_USER_UNKNOWN || r == PAM_MAXTRIES) return; break; case PAM_SM_SETCRED: if (r == PAM_CRED_UNAVAIL || r == PAM_CRED_EXPIRED || r == PAM_USER_UNKNOWN || r == PAM_CRED_ERR) return; break; case PAM_SM_ACCT_MGMT: if (r == PAM_USER_UNKNOWN || r == PAM_AUTH_ERR || r == PAM_NEW_AUTHTOK_REQD || r == PAM_ACCT_EXPIRED) return; break; case PAM_SM_OPEN_SESSION: case PAM_SM_CLOSE_SESSION: if (r == PAM_SESSION_ERR) return; break; case PAM_SM_CHAUTHTOK: if (r == PAM_PERM_DENIED || r == PAM_AUTHTOK_ERR || r == PAM_AUTHTOK_RECOVERY_ERR || r == PAM_AUTHTOK_LOCK_BUSY || r == PAM_AUTHTOK_DISABLE_AGING || r == PAM_TRY_AGAIN) return; break; } openpam_log(PAM_LOG_ERROR, "%s(): unexpected return value %d", pam_sm_func_name[primitive], r); }
static void * try_dlopen(const char *modfn) { int check_module_file; void *dlh; openpam_log(PAM_LOG_LIBDEBUG, "dlopen(%s)", modfn); openpam_get_feature(OPENPAM_VERIFY_MODULE_FILE, &check_module_file); if (check_module_file && openpam_check_path_owner_perms(modfn) != 0) return (NULL); if ((dlh = dlopen(modfn, RTLD_NOW)) == NULL) { openpam_log(PAM_LOG_ERROR, "%s: %s", modfn, dlerror()); errno = 0; return (NULL); } return (dlh); }
/* * Attempts to load a private key from the specified file in the specified * directory, using the specified passphrase. If successful, returns a * struct pam_ssh_key containing the key and its comment. */ static struct pam_ssh_key * pam_ssh_load_key(const char *dir, const char *kfn, const char *passphrase, int nullok) { struct pam_ssh_key *psk; char fn[PATH_MAX]; char *comment; Key *key; if (snprintf(fn, sizeof(fn), "%s/%s", dir, kfn) > (int)sizeof(fn)) return (NULL); comment = NULL; /* * If the key is unencrypted, OpenSSL ignores the passphrase, so * it will seem like the user typed in the right one. This allows * a user to circumvent nullok by providing a dummy passphrase. * Verify that the key really *is* encrypted by trying to load it * with an empty passphrase, and if the key is not encrypted, * accept only an empty passphrase. */ key = key_load_private(fn, "", &comment); if (key != NULL && !(*passphrase == '\0' && nullok)) { key_free(key); return (NULL); } if (key == NULL) key = key_load_private(fn, passphrase, &comment); if (key == NULL) { openpam_log(PAM_LOG_DEBUG, "failed to load key from %s", fn); return (NULL); } openpam_log(PAM_LOG_DEBUG, "loaded '%s' from %s", comment, fn); if ((psk = malloc(sizeof(*psk))) == NULL) { key_free(key); free(comment); return (NULL); } psk->key = key; psk->comment = comment; return (psk); }
static void openpam_release_module(pam_module_t *module) { if (module == NULL) return; if (module->dlh == NULL) /* static module */ return; dlclose(module->dlh); openpam_log(PAM_LOG_DEBUG, "releasing %s", module->path); FREE(module->path); FREE(module); }
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc ,const char **argv) { int retval = PAM_AUTH_ERR; if (getuid() == 0) retval = PAM_SUCCESS; openpam_log(PAM_LOG_DEBUG, "authentication %s", retval==PAM_SUCCESS ? "succeeded":"failed" ); return retval; }
int od_record_check_shell(ODRecordRef record) { int retval = PAM_PERM_DENIED; CFStringRef cfstr = NULL; if (NULL == record) { openpam_log(PAM_LOG_DEBUG, "NULL argument passed"); retval = PAM_SERVICE_ERR; goto cleanup; } retval = od_record_attribute_create_cfstring(record, kODAttributeTypeUserShell, &cfstr); if (PAM_SUCCESS != retval) { openpam_log(PAM_LOG_DEBUG, "od_record_attribute_create_cfstring() failed"); goto cleanup; } if (NULL == cfstr) { retval = PAM_SUCCESS; goto cleanup; } if (CFStringCompare(cfstr, CFSTR("/usr/bin/false"), 0) == kCFCompareEqualTo) { openpam_log(PAM_LOG_DEBUG, "user shell is /bin/false"); retval = PAM_PERM_DENIED; } cleanup: if (PAM_SUCCESS != retval) openpam_log(PAM_LOG_ERROR, "failed: %d", retval); if (NULL != cfstr) { CFRelease(cfstr); } return retval; }
pam_module_t * openpam_load_module(const char *path) { pam_module_t *module; module = openpam_dynamic(path); openpam_log(PAM_LOG_DEBUG, "%s dynamic %s", (module == NULL) ? "no" : "using", path); #ifdef OPENPAM_STATIC_MODULES /* look for a static module */ if (module == NULL && strchr(path, '/') == NULL) { module = openpam_static(path); openpam_log(PAM_LOG_DEBUG, "%s static %s", (module == NULL) ? "no" : "using", path); } #endif if (module == NULL) { openpam_log(PAM_LOG_ERROR, "no %s found", path); return (NULL); } return (module); }
/* Can return NULL */ int od_record_attribute_create_cstring(ODRecordRef record, CFStringRef attrib, char **out) { int retval = PAM_SERVICE_ERR; CFStringRef val = NULL; if (NULL == record || NULL == attrib || NULL == out) { openpam_log(PAM_LOG_DEBUG, "NULL argument passed"); retval = PAM_SERVICE_ERR; goto cleanup; } retval = od_record_attribute_create_cfstring(record, attrib, &val); if (PAM_SUCCESS != retval) { openpam_log(PAM_LOG_DEBUG, "od_record_attribute_create_cfstring() failed"); goto cleanup; } if (NULL != val) { retval = cfstring_to_cstring(val, out); if (PAM_SUCCESS != retval) { openpam_log(PAM_LOG_DEBUG, "cfstring_to_cstring() failed"); goto cleanup; } } cleanup: if (PAM_SUCCESS != retval) { free(out); } if (NULL != val) { CFRelease(val); } return retval; }
int od_extract_home(pam_handle_t *pamh, const char *username, char **server_URL, char **path, char **homedir) { int retval = PAM_SERVICE_ERR; char *tmp = NULL; ODRecordRef record = NULL; retval = od_record_create_cstring(pamh, &record, username); if (PAM_SUCCESS != retval) { goto cleanup; } retval = od_string_from_record(record, kODAttributeTypeHomeDirectory, &tmp); if (retval) { openpam_log(PAM_LOG_DEBUG, "%s - get kODAttributeTypeHomeDirectory : %d", __func__, retval); goto cleanup; } extract_homemount(tmp, server_URL, path); openpam_log(PAM_LOG_DEBUG, "%s - Server URL : %s", __func__, *server_URL); openpam_log(PAM_LOG_DEBUG, "%s - Path to mount: %s", __func__, *path); retval = od_string_from_record(record, kODAttributeTypeNFSHomeDirectory, homedir); openpam_log(PAM_LOG_DEBUG, "%s - Home dir : %s", __func__, *homedir); if (retval) goto cleanup; retval = PAM_SUCCESS; cleanup: if (tmp) free(tmp); if (record) CFRelease(record); return retval; }
/* * Locates the policy file for a given service and reads the given chains * from it. */ static int openpam_load_chain(pam_handle_t *pamh, const char *service, pam_facility_t facility) { const char **path; char *filename; size_t len; int r; /* don't allow to escape from policy_path */ if (strchr(service, '/')) { openpam_log(PAM_LOG_ERROR, "invalid service name: %s", service); return (-PAM_SYSTEM_ERR); } for (path = openpam_policy_path; *path != NULL; ++path) { len = strlen(*path); if ((*path)[len - 1] == '/') { if (asprintf(&filename, "%s%s", *path, service) < 0) { openpam_log(PAM_LOG_ERROR, "asprintf(): %m"); return (-PAM_BUF_ERR); } r = openpam_read_chain(pamh, service, facility, filename, pam_d_style); FREE(filename); } else { r = openpam_read_chain(pamh, service, facility, *path, pam_conf_style); } if (r != 0) return (r); } return (0); }
/* * Read the specified chains from the specified file. * * Returns 0 if the file exists but does not contain any matching lines. * * Returns -1 and sets errno to ENOENT if the file does not exist. * * Returns -1 and sets errno to some other non-zero value if the file * exists but is unsafe or unreadable, or an I/O error occurs. */ static int openpam_load_file(pam_handle_t *pamh, const char *service, pam_facility_t facility, const char *filename, openpam_style_t style) { FILE *f; int ret, serrno; /* attempt to open the file */ if ((f = fopen(filename, "r")) == NULL) { serrno = errno; openpam_log(errno == ENOENT ? PAM_LOG_DEBUG : PAM_LOG_ERROR, "%s: %m", filename); errno = serrno; RETURNN(-1); } else { openpam_log(PAM_LOG_DEBUG, "found %s", filename); } /* verify type, ownership and permissions */ if (OPENPAM_FEATURE(VERIFY_POLICY_FILE) && openpam_check_desc_owner_perms(filename, fileno(f)) != 0) { /* already logged the cause */ serrno = errno; fclose(f); errno = serrno; RETURNN(-1); } /* parse the file */ ret = openpam_parse_chain(pamh, service, facility, f, filename, style); RETURNN(ret); }
int od_record_check_authauthority(ODRecordRef record) { int retval = PAM_PERM_DENIED; CFStringRef authauth = NULL; if (NULL == record) { openpam_log(PAM_LOG_DEBUG, "NULL argument passed"); retval = PAM_SERVICE_ERR; goto cleanup; } retval = od_record_attribute_create_cfstring(record, kODAttributeTypeAuthenticationAuthority, &authauth); if (PAM_SUCCESS != retval) { openpam_log(PAM_LOG_DEBUG, "od_record_attribute_create_cfstring() failed"); goto cleanup; } if (NULL == authauth) { retval = PAM_SUCCESS; goto cleanup; } if (!CFStringHasPrefix(authauth, CFSTR(kDSValueAuthAuthorityDisabledUser))) { retval = PAM_SUCCESS; } cleanup: if (PAM_SUCCESS != retval) { openpam_log(PAM_LOG_ERROR, "failed: %d", retval); } if (authauth) { CFRelease(authauth); } return retval; }