/* * Read a line from the temp file and verify that the result matches our * expectations: whether a line was read at all, how many and which words * it contained, how many lines were read (in case of quoted or escaped * newlines) and whether we reached the end of the file. */ static int orlv_expect(const char **expectedv, int lines, int eof) { int expectedc, gotc, i, lineno = 0; char **gotv; expectedc = 0; if (expectedv != NULL) while (expectedv[expectedc] != NULL) ++expectedc; gotv = openpam_readlinev(f, &lineno, &gotc); if (ferror(f)) err(1, "%s(): %s", __func__, filename); if (expectedv != NULL && gotv == NULL) { t_verbose("expected %d words, got nothing\n", expectedc); return (0); } if (expectedv == NULL && gotv != NULL) { t_verbose("expected nothing, got %d words\n", gotc); FREEV(gotc, gotv); return (0); } if (expectedv != NULL && gotv != NULL) { if (expectedc != gotc) { t_verbose("expected %d words, got %d\n", expectedc, gotc); FREEV(gotc, gotv); return (0); } for (i = 0; i < gotc; ++i) { if (strcmp(expectedv[i], gotv[i]) != 0) { t_verbose("word %d: expected <<%s>>, " "got <<%s>>\n", i, expectedv[i], gotv[i]); FREEV(gotc, gotv); return (0); } } FREEV(gotc, gotv); } if (lineno != lines) { t_verbose("expected to advance %d lines, advanced %d lines\n", lines, lineno); return (0); } if (eof && !feof(f)) { t_verbose("expected EOF, but didn't get it\n"); return (0); } if (!eof && feof(f)) { t_verbose("didn't expect EOF, but got it anyway\n"); return (0); } return (1); }
void write_ticket(const char* user, const char* data) { int fd, ret, word_count; FILE *f, *t; char **words; struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); if ((fd = open_ticket(O_RDWR|O_CREAT|O_EXLOCK)) < 0 || (f = fdopen(fd, "r")) == NULL) { if (fd >= 0) close(fd); return; } char temp_path[strlen(AUTH_TICKET_PATH) + 7 + 1]; if (sprintf(temp_path, "%s.XXXXXX", AUTH_TICKET_PATH) < 0) goto done; if ((ret = mkstemp(temp_path)) == -1 || (t = fopen(temp_path, "w")) == NULL) { if (ret != -1) unlink(temp_path); goto done; } ret = 0; while ((words = openpam_readlinev(f, NULL, &word_count)) != NULL) { if (word_count == 3 && strcmp(user, words[0]) != 0) ret = fprintf(t, "%s %s %s\n", words[0], words[1], words[2]); for(int i = 0; i < word_count; i++) free(words[i]); free(words); if (ret < 0) break; } if (ret >= 0) ret = fprintf(t, "%s %s %d\n", user, data, (int)now.tv_sec); if (fclose(t) == 0) { if (ret >= 0 && rename(temp_path, AUTH_TICKET_PATH) == 0) { ftruncate(fd, 0); goto done; } } truncate(temp_path, 0); unlink(temp_path); done: fclose(f); }
static bool read_ticket(const char *user, int *timestamp, char **password) { int fd, word_count; FILE *f; char **words; bool success = false; if ((fd = open_ticket(O_RDONLY|O_SHLOCK)) < 0 || (f = fdopen(fd, "r")) == NULL) { if (fd >= 0) close(fd); return (false); } words = openpam_readlinev(f, NULL, &word_count); while (words != NULL) { if (word_count != 3 || strcmp(user, words[0]) != 0) { for(int i = 0; i < word_count; i++) { free(words[i]); } free(words); words = openpam_readlinev(f, NULL, &word_count); continue; } *password = words[1]; const char *err; *timestamp = strtonum(words[2], 0, INT_MAX - TIMEOUT, &err); success = (err == NULL); free(words[0]); free(words[2]); free(words); words = NULL; } fclose(f); return (success); }
/* * Extracts given chains from a policy file. * * Returns the number of policy entries which were found for the specified * service and facility, or -1 if a system error occurred or a syntax * error was encountered. */ static int openpam_parse_chain(pam_handle_t *pamh, const char *service, pam_facility_t facility, FILE *f, const char *filename, openpam_style_t style) { pam_chain_t *this, **next; pam_facility_t fclt; pam_control_t ctlf; char *name, *servicename, *modulename; int count, lineno, ret, serrno; char **wordv, *word; int i, wordc; count = 0; this = NULL; name = NULL; lineno = 0; wordc = 0; wordv = NULL; while ((wordv = openpam_readlinev(f, &lineno, &wordc)) != NULL) { /* blank line? */ if (wordc == 0) { FREEV(wordc, wordv); continue; } i = 0; /* check service name if necessary */ if (style == pam_conf_style && strcmp(wordv[i++], service) != 0) { FREEV(wordc, wordv); continue; } /* check facility name */ if ((word = wordv[i++]) == NULL || (fclt = parse_facility_name(word)) == (pam_facility_t)-1) { openpam_log(PAM_LOG_ERROR, "%s(%d): missing or invalid facility", filename, lineno); errno = EINVAL; goto fail; } if (facility != fclt && facility != PAM_FACILITY_ANY) { FREEV(wordc, wordv); continue; } /* check for "include" */ if ((word = wordv[i++]) != NULL && strcmp(word, "include") == 0) { if ((servicename = wordv[i++]) == NULL || !valid_service_name(servicename)) { openpam_log(PAM_LOG_ERROR, "%s(%d): missing or invalid service name", filename, lineno); errno = EINVAL; goto fail; } if (wordv[i] != NULL) { openpam_log(PAM_LOG_ERROR, "%s(%d): garbage at end of line", filename, lineno); errno = EINVAL; goto fail; } ret = openpam_load_chain(pamh, servicename, fclt); FREEV(wordc, wordv); if (ret < 0) { /* * Bogus errno, but this ensures that the * outer loop does not just ignore the * error and keep searching. */ if (errno == ENOENT) errno = EINVAL; goto fail; } continue; } /* get control flag */ if (word == NULL || /* same word we compared to "include" */ (ctlf = parse_control_flag(word)) == (pam_control_t)-1) { openpam_log(PAM_LOG_ERROR, "%s(%d): missing or invalid control flag", filename, lineno); errno = EINVAL; goto fail; } /* get module name */ if ((modulename = wordv[i++]) == NULL || !valid_module_name(modulename)) { openpam_log(PAM_LOG_ERROR, "%s(%d): missing or invalid module name", filename, lineno); errno = EINVAL; goto fail; } /* allocate new entry */ if ((this = calloc(1, sizeof *this)) == NULL) goto syserr; this->flag = ctlf; /* load module */ if ((this->module = openpam_load_module(modulename)) == NULL) { if (errno == ENOENT) errno = ENOEXEC; goto fail; } /* * The remaining items in wordv are the module's * arguments. We could set this->optv = wordv + i, but * then free(this->optv) wouldn't work. Instead, we free * the words we've already consumed, shift the rest up, * and clear the tail end of the array. */ this->optc = wordc - i; for (i = 0; i < wordc - this->optc; ++i) { FREE(wordv[i]); } for (i = 0; i < this->optc; ++i) { wordv[i] = wordv[wordc - this->optc + i]; wordv[wordc - this->optc + i] = NULL; } this->optv = wordv; wordv = NULL; wordc = 0; /* hook it up */ for (next = &pamh->chains[fclt]; *next != NULL; next = &(*next)->next) /* nothing */ ; *next = this; this = NULL; ++count; } /* * The loop ended because openpam_readword() returned NULL, which * can happen for four different reasons: an I/O error (ferror(f) * is true), a memory allocation failure (ferror(f) is false, * feof(f) is false, errno is non-zero), the file ended with an * unterminated quote or backslash escape (ferror(f) is false, * feof(f) is true, errno is non-zero), or the end of the file was * reached without error (ferror(f) is false, feof(f) is true, * errno is zero). */ if (ferror(f) || errno != 0) goto syserr; if (!feof(f)) goto fail; fclose(f); return (count); syserr: serrno = errno; openpam_log(PAM_LOG_ERROR, "%s: %m", filename); errno = serrno; /* fall through */ fail: serrno = errno; if (this && this->optc && this->optv) FREEV(this->optc, this->optv); FREE(this); FREEV(wordc, wordv); FREE(wordv); FREE(name); fclose(f); errno = serrno; return (-1); }