/* * Parse an option. * * Returns a dynamically allocated string containing the next module * option, or NULL if the end of the string was reached or a disallowed * non-whitespace character was encountered. * * If parse_option() is successful, it updates *line to point one * character past the end of the option. If it reaches the end of the * string, it updates *line to point to the terminating NUL character. In * all other cases, it leaves *line unmodified. * * If parse_option() fails to allocate memory, it will return NULL and set * errno to a non-zero value. * * Allowed characters for option names are all characters in the POSIX * portable filename character set. Allowed characters for option values * are any printable non-whitespace characters. The option value may be * quoted in either single or double quotes, in which case space * characters and whichever quote character was not used are allowed. * Note that the entire value must be quoted, not just part of it. */ static char * parse_option(char **line) { char *nb, *ne, *vb, *ve; unsigned char q = 0; char *option; size_t size; errno = 0; for (nb = *line; *nb && is_lws(*nb); ++nb) /* nothing */ ; if (!*nb) { *line = nb; return (NULL); } for (ne = nb; *ne && !is_lws(*ne) && *ne != '='; ++ne) if (!is_pfcs(*ne)) return (NULL); if (ne == nb) return (NULL); if (*ne == '=') { vb = ne + 1; if (*vb == '"' || *vb == '\'') q = *vb++; for (ve = vb; *ve && *ve != q && (is_p(*ve) || (q && is_lws(*ve))); ++ve) /* nothing */ ; if (q && *ve != q) /* non-printable character or missing endquote */ return (NULL); if (q && *(ve + 1) && !is_lws(*(ve + 1))) /* garbage after value */ return (NULL); } else { vb = ve = ne; } size = (ne - nb) + 1; if (ve > vb) size += (ve - vb) + 1; if ((option = malloc(size)) == NULL) return (NULL); strncpy(option, nb, ne - nb); if (ve > vb) { option[ne - nb] = '='; strncpy(option + (ne - nb) + 1, vb, ve - vb); } option[size - 1] = '\0'; *line = q ? ve + 1 : ve; return (option); }
/* * Parse the service name. * * Returns the length of the service name, or 0 if the end of the string * was reached or a disallowed non-whitespace character was encountered. * * If parse_service_name() is successful, it updates *service to point to * the first character of the service name and *line to point one * character past the end. If it reaches the end of the string, it * updates *line to point to the terminating NUL character and leaves * *service unmodified. In all other cases, it leaves both *line and * *service unmodified. * * Allowed characters are all characters in the POSIX portable filename * character set. */ static int parse_service_name(char **line, char **service) { char *b, *e; for (b = *line; *b && is_lws(*b); ++b) /* nothing */ ; if (!*b) { *line = b; return (0); } for (e = b; *e && !is_lws(*e); ++e) if (!is_pfcs(*e)) return (0); if (e == b) return (0); *line = e; *service = b; return (e - b); }
/* * Parse a file name. * * Returns the length of the file name, or 0 if the end of the string was * reached or a disallowed non-whitespace character was encountered. * * If parse_filename() is successful, it updates *filename to point to the * first character of the filename and *line to point one character past * the end. If it reaches the end of the string, it updates *line to * point to the terminating NUL character and leaves *filename unmodified. * In all other cases, it leaves both *line and *filename unmodified. * * Allowed characters are all characters in the POSIX portable filename * character set, plus the path separator (forward slash). */ static int parse_filename(char **line, char **filename) { char *b, *e; for (b = *line; *b && is_lws(*b); ++b) /* nothing */ ; if (!*b) { *line = b; return (0); } for (e = b; *e && !is_lws(*e); ++e) if (!is_pfcs(*e) && *e != '/') return (0); if (e == b) return (0); *line = e; *filename = b; return (e - b); }
/* * Parse the word "include". * * If the next word on the line is "include", parse_include() updates * *line to point one character past "include" and returns 1. Otherwise, * it leaves *line unmodified and returns 0. */ static int parse_include(char **line) { char *b, *e; for (b = *line; *b && is_lws(*b); ++b) /* nothing */ ; if (!*b) { *line = b; return (-1); } for (e = b; *e && !is_lws(*e); ++e) /* nothing */ ; if (e == b) return (0); if (strlcmp("include", b, e - b) != 0) return (0); *line = e; return (1); }
/* * Consume trailing whitespace. * * If there are no non-whitespace characters left on the line, parse_eol() * updates *line to point at the terminating NUL character and returns 0. * Otherwise, it leaves *line unmodified and returns a non-zero value. */ static int parse_eol(char **line) { char *p; for (p = *line; *p && is_lws(*p); ++p) /* nothing */ ; if (*p) return ((unsigned char)*p); *line = p; return (0); }
/* * Parse the control flag. * * Returns the corresponding pam_control_t value, or -1 if the end of the * string was reached, a disallowed non-whitespace character was * encountered, or the first word was not a recognized control flag. * * If parse_control_flag() is successful, it updates *line to point one * character past the end of the control flag. If it reaches the end of * the string, it updates *line to point to the terminating NUL character. * In all other cases, it leaves *line unmodified. */ static pam_control_t parse_control_flag(char **line) { char *b, *e; int i; for (b = *line; *b && is_lws(*b); ++b) /* nothing */ ; if (!*b) { *line = b; return ((pam_control_t)-1); } for (e = b; *e && !is_lws(*e); ++e) /* nothing */ ; if (e == b) return ((pam_control_t)-1); for (i = 0; i < PAM_NUM_CONTROL_FLAGS; ++i) if (strlcmp(pam_control_flag_name[i], b, e - b) == 0) break; if (i == PAM_NUM_CONTROL_FLAGS) return ((pam_control_t)-1); *line = e; return (i); }
/* * Parse the facility name. * * Returns the corresponding pam_facility_t value, or -1 if the end of the * string was reached, a disallowed non-whitespace character was * encountered, or the first word was not a recognized facility name. * * If parse_facility_name() is successful, it updates *line to point one * character past the end of the facility name. If it reaches the end of * the string, it updates *line to point to the terminating NUL character. * In all other cases, it leaves *line unmodified. */ static pam_facility_t parse_facility_name(char **line) { char *b, *e; int i; for (b = *line; *b && is_lws(*b); ++b) /* nothing */ ; if (!*b) { *line = b; return ((pam_facility_t)-1); } for (e = b; *e && !is_lws(*e); ++e) /* nothing */ ; if (e == b) return ((pam_facility_t)-1); for (i = 0; i < PAM_NUM_FACILITIES; ++i) if (strlcmp(pam_facility_name[i], b, e - b) == 0) break; if (i == PAM_NUM_FACILITIES) return ((pam_facility_t)-1); *line = e; return (i); }
char * openpam_readword(FILE *f, int *lineno, size_t *lenp) { char *word; size_t size, len; int ch, comment, escape, quote; int serrno; errno = 0; /* skip initial whitespace */ comment = 0; while ((ch = getc(f)) != EOF && ch != '\n') { if (ch == '#') comment = 1; if (!is_lws(ch) && !comment) break; } if (ch == EOF) return (NULL); ungetc(ch, f); if (ch == '\n') return (NULL); word = NULL; size = len = 0; escape = quote = 0; while ((ch = fgetc(f)) != EOF && (!is_ws(ch) || quote || escape)) { if (ch == '\\' && !escape && quote != '\'') { /* escape next character */ escape = ch; } else if ((ch == '\'' || ch == '"') && !quote && !escape) { /* begin quote */ quote = ch; /* edge case: empty quoted string */ if (openpam_straddch(&word, &size, &len, 0) != 0) return (NULL); } else if (ch == quote && !escape) { /* end quote */ quote = 0; } else if (ch == '\n' && escape && quote != '\'') { /* line continuation */ escape = 0; } else { if (escape && quote && ch != '\\' && ch != quote && openpam_straddch(&word, &size, &len, '\\') != 0) { free(word); errno = ENOMEM; return (NULL); } if (openpam_straddch(&word, &size, &len, ch) != 0) { free(word); errno = ENOMEM; return (NULL); } escape = 0; } if (lineno != NULL && ch == '\n') ++*lineno; } if (ch == EOF && ferror(f)) { serrno = errno; free(word); errno = serrno; return (NULL); } if (ch == EOF && (escape || quote)) { /* Missing escaped character or closing quote. */ openpam_log(PAM_LOG_ERROR, "unexpected end of file"); free(word); errno = EINVAL; return (NULL); } ungetc(ch, f); if (lenp != NULL) *lenp = len; return (word); }
Result ws::http_request_parser::consume(char c) { switch(state_) { case METHOD_GET_1: return require_char(c, 'G', METHOD_GET_2); break; case METHOD_GET_2: return require_char(c, 'E', METHOD_GET_3); break; case METHOD_GET_3: return require_char(c, 'T', METHOD_GET_SP); break; case METHOD_GET_SP: return require_char(c, ' ', URI); break; case URI: if (c == ' ') state_ = HTTP_1; else if (!is_ctl(c)) request.uri.push_back(c); else return BAD_REQUEST; return INDETERMINATE; break; case HTTP_1: return require_char(c, 'H', HTTP_2); break; case HTTP_2: return require_char(c, 'T', HTTP_3); break; case HTTP_3: return require_char(c, 'T', HTTP_4); break; case HTTP_4: return require_char(c, 'P', HTTP_SLASH); break; case HTTP_SLASH: return require_char(c, '/', HTTP_VERSION_MAJOR); break; case HTTP_VERSION_MAJOR: return require_char(c, '1', HTTP_VERSION_POINT); break; case HTTP_VERSION_POINT: return require_char(c, '.', HTTP_VERSION_MINOR); break; case HTTP_VERSION_MINOR: return require_char(c, '1', REQUEST_LINE_CR); break; case REQUEST_LINE_CR: return require_char(c, CR, REQUEST_LINE_LF); break; case REQUEST_LINE_LF: return require_char(c, LF, HEADER_START); break; case HEADER_START: if (c == CR) { state_ = FINAL_LF; return INDETERMINATE; } state_ = HEADER_NAME; return process_header_name_char(c); break; case HEADER_NAME: if (c == ':') { state_ = HEADER_VALUE_START; return INDETERMINATE; } return process_header_name_char(c); break; case HEADER_VALUE_START: if (is_lws(c)) return INDETERMINATE; state_ = HEADER_VALUE; return process_header_value_char(c); break; case HEADER_VALUE: if (c == CR) { header_value_complete(); state_ = HEADER_LF; return INDETERMINATE; } return process_header_value_char(c); break; case HEADER_LF: return require_char(c, LF, HEADER_START); break; case FINAL_LF: if (c == LF) { state_ = AFTER_FINAL_LF; return GOOD; } else return BAD_REQUEST; break; case AFTER_FINAL_LF: return BAD_REQUEST; break; } return BAD_REQUEST; }