static char * scan_quote(CONF *conf, char *p) { int q = *p; p++; while (!(IS_EOF(conf, *p)) && (*p != q)) { if (IS_ESC(conf, *p)) { p++; if (IS_EOF(conf, *p)) return (p); } p++; } if (*p == q) p++; return (p); }
static void clear_comments(CONF *conf, char *p) { for (;;) { if (IS_FCOMMENT(conf,*p)) { *p='\0'; return; } if (!IS_WS(conf,*p)) { break; } p++; } for (;;) { if (IS_COMMENT(conf,*p)) { *p='\0'; return; } if (IS_DQUOTE(conf,*p)) { p=scan_dquote(conf, p); continue; } if (IS_QUOTE(conf,*p)) { p=scan_quote(conf, p); continue; } if (IS_ESC(conf,*p)) { p=scan_esc(conf,p); continue; } if (IS_EOF(conf,*p)) return; else p++; } }
static int str_copy(CONF *conf, char *section, char **pto, char *from) { int q, r, rr = 0, to = 0, len = 0; char *s, *e, *rp, *p, *rrp, *np, *cp, v; BUF_MEM *buf; if ((buf = BUF_MEM_new()) == NULL) return 0; len = strlen(from) + 1; if (!BUF_MEM_grow(buf, len)) goto err; for (;;) { if (IS_QUOTE(conf, *from)) { q = *from; from++; while (!IS_EOF(conf, *from) && (*from != q)) { if (IS_ESC(conf, *from)) { from++; if (IS_EOF(conf, *from)) break; } buf->data[to++] = *(from++); } if (*from == q) from++; } else if (IS_DQUOTE(conf, *from)) { q = *from; from++; while (!IS_EOF(conf, *from)) { if (*from == q) { if (*(from + 1) == q) { from++; } else { break; } } buf->data[to++] = *(from++); } if (*from == q) from++; } else if (IS_ESC(conf, *from)) { from++; v = *(from++); if (IS_EOF(conf, v)) break; else if (v == 'r') v = '\r'; else if (v == 'n') v = '\n'; else if (v == 'b') v = '\b'; else if (v == 't') v = '\t'; buf->data[to++] = v; } else if (IS_EOF(conf, *from)) break; else if (*from == '$') { size_t newsize; /* try to expand it */ rrp = NULL; s = &(from[1]); if (*s == '{') q = '}'; else if (*s == '(') q = ')'; else q = 0; if (q) s++; cp = section; e = np = s; while (IS_ALNUM(conf, *e)) e++; if ((e[0] == ':') && (e[1] == ':')) { cp = np; rrp = e; rr = *e; *rrp = '\0'; e += 2; np = e; while (IS_ALNUM(conf, *e)) e++; } r = *e; *e = '\0'; rp = e; if (q) { if (r != q) { CONFerr(CONF_F_STR_COPY, CONF_R_NO_CLOSE_BRACE); goto err; } e++; } /*- * So at this point we have * np which is the start of the name string which is * '\0' terminated. * cp which is the start of the section string which is * '\0' terminated. * e is the 'next point after'. * r and rr are the chars replaced by the '\0' * rp and rrp is where 'r' and 'rr' came from. */ p = _CONF_get_string(conf, cp, np); if (rrp != NULL) *rrp = rr; *rp = r; if (p == NULL) { CONFerr(CONF_F_STR_COPY, CONF_R_VARIABLE_HAS_NO_VALUE); goto err; } newsize = strlen(p) + buf->length - (e - from); if (newsize > MAX_CONF_VALUE_LENGTH) { CONFerr(CONF_F_STR_COPY, CONF_R_VARIABLE_EXPANSION_TOO_LONG); goto err; } if (!BUF_MEM_grow_clean(buf, newsize)) { CONFerr(CONF_F_STR_COPY, ERR_R_MALLOC_FAILURE); goto err; } while (*p) buf->data[to++] = *(p++); /* * Since we change the pointer 'from', we also have to change the * perceived length of the string it points at. /RL */ len -= e - from; from = e; /* * In case there were no braces or parenthesis around the * variable reference, we have to put back the character that was * replaced with a '\0'. /RL */ *rp = r; } else buf->data[to++] = *(from++); } buf->data[to] = '\0'; OPENSSL_free(*pto); *pto = buf->data; OPENSSL_free(buf); return 1; err: BUF_MEM_free(buf); return 0; }
static int def_load_bio(CONF *conf, BIO *in, long *line) { /* The macro BUFSIZE conflicts with a system macro in VxWorks */ #define CONFBUFSIZE 512 int bufnum = 0, i, ii; BUF_MEM *buff = NULL; char *s, *p, *end; int again; long eline = 0; char btmp[DECIMAL_SIZE(eline) + 1]; CONF_VALUE *v = NULL, *tv; CONF_VALUE *sv = NULL; char *section = NULL, *buf; char *start, *psection, *pname; void *h = (void *)(conf->data); STACK_OF(BIO) *biosk = NULL; #ifndef OPENSSL_NO_POSIX_IO char *dirpath = NULL; OPENSSL_DIR_CTX *dirctx = NULL; #endif if ((buff = BUF_MEM_new()) == NULL) { CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_BUF_LIB); goto err; } section = OPENSSL_strdup("default"); if (section == NULL) { CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); goto err; } if (_CONF_new_data(conf) == 0) { CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); goto err; } sv = _CONF_new_section(conf, section); if (sv == NULL) { CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_UNABLE_TO_CREATE_NEW_SECTION); goto err; } bufnum = 0; again = 0; for (;;) { if (!BUF_MEM_grow(buff, bufnum + CONFBUFSIZE)) { CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_BUF_LIB); goto err; } p = &(buff->data[bufnum]); *p = '\0'; read_retry: BIO_gets(in, p, CONFBUFSIZE - 1); p[CONFBUFSIZE - 1] = '\0'; ii = i = strlen(p); if (i == 0 && !again) { /* the currently processed BIO is at EOF */ BIO *parent; #ifndef OPENSSL_NO_POSIX_IO /* continue processing with the next file from directory */ if (dirctx != NULL) { BIO *next; if ((next = get_next_file(dirpath, &dirctx)) != NULL) { BIO_vfree(in); in = next; goto read_retry; } else { OPENSSL_free(dirpath); dirpath = NULL; } } #endif /* no more files in directory, continue with processing parent */ if ((parent = sk_BIO_pop(biosk)) == NULL) { /* everything processed get out of the loop */ break; } else { BIO_vfree(in); in = parent; goto read_retry; } } again = 0; while (i > 0) { if ((p[i - 1] != '\r') && (p[i - 1] != '\n')) break; else i--; } /* * we removed some trailing stuff so there is a new line on the end. */ if (ii && i == ii) again = 1; /* long line */ else { p[i] = '\0'; eline++; /* another input line */ } /* we now have a line with trailing \r\n removed */ /* i is the number of bytes */ bufnum += i; v = NULL; /* check for line continuation */ if (bufnum >= 1) { /* * If we have bytes and the last char '\\' and second last char * is not '\\' */ p = &(buff->data[bufnum - 1]); if (IS_ESC(conf, p[0]) && ((bufnum <= 1) || !IS_ESC(conf, p[-1]))) { bufnum--; again = 1; } } if (again) continue; bufnum = 0; buf = buff->data; clear_comments(conf, buf); s = eat_ws(conf, buf); if (IS_EOF(conf, *s)) continue; /* blank line */ if (*s == '[') { char *ss; s++; start = eat_ws(conf, s); ss = start; again: end = eat_alpha_numeric(conf, ss); p = eat_ws(conf, end); if (*p != ']') { if (*p != '\0' && ss != p) { ss = p; goto again; } CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_MISSING_CLOSE_SQUARE_BRACKET); goto err; } *end = '\0'; if (!str_copy(conf, NULL, §ion, start)) goto err; if ((sv = _CONF_get_section(conf, section)) == NULL) sv = _CONF_new_section(conf, section); if (sv == NULL) { CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_UNABLE_TO_CREATE_NEW_SECTION); goto err; } continue; } else { pname = s; end = eat_alpha_numeric(conf, s); if ((end[0] == ':') && (end[1] == ':')) { *end = '\0'; end += 2; psection = pname; pname = end; end = eat_alpha_numeric(conf, end); } else { psection = section; } p = eat_ws(conf, end); if (strncmp(pname, ".include", 8) == 0 && (p != pname + 8 || *p == '=')) { char *include = NULL; BIO *next; if (*p == '=') { p++; p = eat_ws(conf, p); } trim_ws(conf, p); if (!str_copy(conf, psection, &include, p)) goto err; /* get the BIO of the included file */ #ifndef OPENSSL_NO_POSIX_IO next = process_include(include, &dirctx, &dirpath); if (include != dirpath) { /* dirpath will contain include in case of a directory */ OPENSSL_free(include); } #else next = BIO_new_file(include, "r"); OPENSSL_free(include); #endif if (next != NULL) { /* push the currently processing BIO onto stack */ if (biosk == NULL) { if ((biosk = sk_BIO_new_null()) == NULL) { CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); goto err; } } if (!sk_BIO_push(biosk, in)) { CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); goto err; } /* continue with reading from the included BIO */ in = next; } continue; } else if (*p != '=') { CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_MISSING_EQUAL_SIGN); goto err; } *end = '\0'; p++; start = eat_ws(conf, p); trim_ws(conf, start); if ((v = OPENSSL_malloc(sizeof(*v))) == NULL) { CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); goto err; } v->name = OPENSSL_strdup(pname); v->value = NULL; if (v->name == NULL) { CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); goto err; } if (!str_copy(conf, psection, &(v->value), start)) goto err; if (strcmp(psection, section) != 0) { if ((tv = _CONF_get_section(conf, psection)) == NULL) tv = _CONF_new_section(conf, psection); if (tv == NULL) { CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_UNABLE_TO_CREATE_NEW_SECTION); goto err; } } else tv = sv; if (_CONF_add_string(conf, tv, v) == 0) { CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); goto err; } v = NULL; } } BUF_MEM_free(buff); OPENSSL_free(section); /* * No need to pop, since we only get here if the stack is empty. * If this causes a BIO leak, THE ISSUE IS SOMEWHERE ELSE! */ sk_BIO_free(biosk); return 1; err: BUF_MEM_free(buff); OPENSSL_free(section); /* * Since |in| is the first element of the stack and should NOT be freed * here, we cannot use sk_BIO_pop_free(). Instead, we pop and free one * BIO at a time, making sure that the last one popped isn't. */ while (sk_BIO_num(biosk) > 0) { BIO *popped = sk_BIO_pop(biosk); BIO_vfree(in); in = popped; } sk_BIO_free(biosk); #ifndef OPENSSL_NO_POSIX_IO OPENSSL_free(dirpath); if (dirctx != NULL) OPENSSL_DIR_end(&dirctx); #endif if (line != NULL) *line = eline; BIO_snprintf(btmp, sizeof(btmp), "%ld", eline); ERR_add_error_data(2, "line ", btmp); if (h != conf->data) { CONF_free(conf->data); conf->data = NULL; } if (v != NULL) { OPENSSL_free(v->name); OPENSSL_free(v->value); OPENSSL_free(v); } return 0; }
static qse_rex_node_t* comp_atom (comp_t* com) { qse_rex_node_t* atom; if (!IS_ESC(com)) { switch (com->c.value) { case QSE_T('('): atom = comp_group (com); if (atom == QSE_NULL) return QSE_NULL; break; case QSE_T('.'): atom = newnode (com, QSE_REX_NODE_ANY); if (atom == QSE_NULL) return QSE_NULL; if (getc_esc(com) <= -1) return QSE_NULL; break; case QSE_T('^'): atom = newnode (com, QSE_REX_NODE_BOL); if (atom == QSE_NULL) return QSE_NULL; if (getc_esc(com) <= -1) return QSE_NULL; break; case QSE_T('$'): atom = newnode (com, QSE_REX_NODE_EOL); if (atom == QSE_NULL) return QSE_NULL; if (getc_esc(com) <= -1) return QSE_NULL; break; case QSE_T('['): atom = newnode (com, QSE_REX_NODE_CSET); if (atom == QSE_NULL) return QSE_NULL; if (getc_esc(com) <= -1) return QSE_NULL; if (charset(com, atom) <= -1) return QSE_NULL; break; default: if (com->rex->option & QSE_REX_STRICT) { /* check if a special charcter is at the * position that requires a normal character. */ switch (com->c.value) { case QSE_T('{'): /* { is a normal charcter when bound is disabled */ if (com->rex->option & QSE_REX_NOBOUND) break; case QSE_T(')'): case QSE_T('?'): case QSE_T('*'): case QSE_T('+'): /* it's at the wrong postion */ com->rex->errnum = QSE_REX_ESPCAWP; return QSE_NULL; } } goto normal_char; } } else { normal_char: /* normal character */ atom = newcharnode (com, com->c.value); if (atom == QSE_NULL) return QSE_NULL; if (getc_esc(com) <= -1) return QSE_NULL; } atom->occ.min = 1; atom->occ.max = 1; if (!IS_ESC(com)) { /* handle the occurrence specifier, if any */ if (comp_occ (com, atom) == QSE_NULL) return QSE_NULL; } return atom; }
static int def_load_bio(CONF *conf, BIO *in, long *line) { /* The macro BUFSIZE conflicts with a system macro in VxWorks */ #define CONFBUFSIZE 512 int bufnum=0,i,ii; BUF_MEM *buff=NULL; char *s,*p,*end; int again; long eline=0; char btmp[DECIMAL_SIZE(eline)+1]; CONF_VALUE *v=NULL,*tv; CONF_VALUE *sv=NULL; char *section=NULL,*buf; STACK_OF(CONF_VALUE) *section_sk=NULL,*ts __UNUSED; char *start,*psection,*pname; void *h = (void *)(conf->data); if ((buff=BUF_MEM_new()) == NULL) { CONFerr(CONF_F_DEF_LOAD_BIO,ERR_R_BUF_LIB); goto err; } section=(char *)OPENSSL_malloc(10); if (section == NULL) { CONFerr(CONF_F_DEF_LOAD_BIO,ERR_R_MALLOC_FAILURE); goto err; } BUF_strlcpy(section,"default",10); if (_CONF_new_data(conf) == 0) { CONFerr(CONF_F_DEF_LOAD_BIO,ERR_R_MALLOC_FAILURE); goto err; } sv=_CONF_new_section(conf,section); if (sv == NULL) { CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_UNABLE_TO_CREATE_NEW_SECTION); goto err; } section_sk=(STACK_OF(CONF_VALUE) *)sv->value; bufnum=0; again=0; for (;;) { if (!BUF_MEM_grow(buff,bufnum+CONFBUFSIZE)) { CONFerr(CONF_F_DEF_LOAD_BIO,ERR_R_BUF_LIB); goto err; } p= &(buff->data[bufnum]); *p='\0'; BIO_gets(in, p, CONFBUFSIZE-1); p[CONFBUFSIZE-1]='\0'; ii=i=strlen(p); if (i == 0 && !again) break; again=0; while (i > 0) { if ((p[i-1] != '\r') && (p[i-1] != '\n')) break; else i--; } /* we removed some trailing stuff so there is a new * line on the end. */ if (ii && i == ii) again=1; /* long line */ else { p[i]='\0'; eline++; /* another input line */ } /* we now have a line with trailing \r\n removed */ /* i is the number of bytes */ bufnum+=i; v=NULL; /* check for line continuation */ if (bufnum >= 1) { /* If we have bytes and the last char '\\' and * second last char is not '\\' */ p= &(buff->data[bufnum-1]); if (IS_ESC(conf,p[0]) && ((bufnum <= 1) || !IS_ESC(conf,p[-1]))) { bufnum--; again=1; } } if (again) continue; bufnum=0; buf=buff->data; clear_comments(conf, buf); s=eat_ws(conf, buf); if (IS_EOF(conf,*s)) continue; /* blank line */ if (*s == '[') { char *ss; s++; start=eat_ws(conf, s); ss=start; again: end=eat_alpha_numeric(conf, ss); p=eat_ws(conf, end); if (*p != ']') { if (*p != '\0') { ss=p; goto again; } CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_MISSING_CLOSE_SQUARE_BRACKET); goto err; } *end='\0'; if (!str_copy(conf,NULL,§ion,start)) goto err; if ((sv=_CONF_get_section(conf,section)) == NULL) sv=_CONF_new_section(conf,section); if (sv == NULL) { CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_UNABLE_TO_CREATE_NEW_SECTION); goto err; } section_sk=(STACK_OF(CONF_VALUE) *)sv->value; continue; } else {
static int def_load_bio(CONF *conf, BIO *in, long *line) { /* The macro BUFSIZE conflicts with a system macro in VxWorks */ #define CONFBUFSIZE 512 int bufnum = 0, i, ii; BUF_MEM *buff = NULL; char *s, *p, *end; int again; long eline = 0; char btmp[DECIMAL_SIZE(eline) + 1]; CONF_VALUE *v = NULL, *tv; CONF_VALUE *sv = NULL; char *section = NULL, *buf; char *start, *psection, *pname; void *h = (void *)(conf->data); if ((buff = BUF_MEM_new()) == NULL) { CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_BUF_LIB); goto err; } section = (char *)OPENSSL_malloc(10); if (section == NULL) { CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); goto err; } BUF_strlcpy(section, "default", 10); if (_CONF_new_data(conf) == 0) { CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); goto err; } sv = _CONF_new_section(conf, section); if (sv == NULL) { CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_UNABLE_TO_CREATE_NEW_SECTION); goto err; } bufnum = 0; again = 0; for (;;) { if (!BUF_MEM_grow(buff, bufnum + CONFBUFSIZE)) { CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_BUF_LIB); goto err; } p = &(buff->data[bufnum]); *p = '\0'; BIO_gets(in, p, CONFBUFSIZE - 1); p[CONFBUFSIZE - 1] = '\0'; ii = i = sgx_strlen(p); if (i == 0 && !again) break; again = 0; while (i > 0) { if ((p[i - 1] != '\r') && (p[i - 1] != '\n')) break; else i--; } /* * we removed some trailing stuff so there is a new line on the end. */ if (ii && i == ii) again = 1; /* long line */ else { p[i] = '\0'; eline++; /* another input line */ } /* we now have a line with trailing \r\n removed */ /* i is the number of bytes */ bufnum += i; v = NULL; /* check for line continuation */ if (bufnum >= 1) { /* * If we have bytes and the last char '\\' and second last char * is not '\\' */ p = &(buff->data[bufnum - 1]); if (IS_ESC(conf, p[0]) && ((bufnum <= 1) || !IS_ESC(conf, p[-1]))) { bufnum--; again = 1; } } if (again) continue; bufnum = 0; buf = buff->data; clear_comments(conf, buf); s = eat_ws(conf, buf); if (IS_EOF(conf, *s)) continue; /* blank line */ if (*s == '[') { char *ss; s++; start = eat_ws(conf, s); ss = start; again: end = eat_alpha_numeric(conf, ss); p = eat_ws(conf, end); if (*p != ']') { if (*p != '\0' && ss != p) { ss = p; goto again; } CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_MISSING_CLOSE_SQUARE_BRACKET); goto err; } *end = '\0'; if (!str_copy(conf, NULL, §ion, start)) goto err; if ((sv = _CONF_get_section(conf, section)) == NULL) sv = _CONF_new_section(conf, section); if (sv == NULL) { CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_UNABLE_TO_CREATE_NEW_SECTION); goto err; } continue; } else { pname = s; psection = NULL; end = eat_alpha_numeric(conf, s); if ((end[0] == ':') && (end[1] == ':')) { *end = '\0'; end += 2; psection = pname; pname = end; end = eat_alpha_numeric(conf, end); } p = eat_ws(conf, end); if (*p != '=') { CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_MISSING_EQUAL_SIGN); goto err; } *end = '\0'; p++; start = eat_ws(conf, p); while (!IS_EOF(conf, *p)) p++; p--; while ((p != start) && (IS_WS(conf, *p))) p--; p++; *p = '\0'; if (!(v = (CONF_VALUE *)OPENSSL_malloc(sizeof(CONF_VALUE)))) { CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); goto err; } if (psection == NULL) psection = section; v->name = (char *)OPENSSL_malloc(strlen(pname) + 1); v->value = NULL; if (v->name == NULL) { CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); goto err; } BUF_strlcpy(v->name, pname, sgx_strlen(pname) + 1); if (!str_copy(conf, psection, &(v->value), start)) goto err; if (sgx_strcmp(psection, section) != 0) { if ((tv = _CONF_get_section(conf, psection)) == NULL) tv = _CONF_new_section(conf, psection); if (tv == NULL) { CONFerr(CONF_F_DEF_LOAD_BIO, CONF_R_UNABLE_TO_CREATE_NEW_SECTION); goto err; } } else tv = sv; #if 1 if (_CONF_add_string(conf, tv, v) == 0) { CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); goto err; } #else v->section = tv->section; if (!sk_CONF_VALUE_push(ts, v)) { CONFerr(CONF_F_DEF_LOAD_BIO, ERR_R_MALLOC_FAILURE); goto err; } vv = (CONF_VALUE *)lh_insert(conf->data, v); if (vv != NULL) { sk_CONF_VALUE_delete_ptr(ts, vv); OPENSSL_free(vv->name); OPENSSL_free(vv->value); OPENSSL_free(vv); } #endif v = NULL; } } if (buff != NULL) BUF_MEM_free(buff); if (section != NULL) OPENSSL_free(section); return (1); err: if (buff != NULL) BUF_MEM_free(buff); if (section != NULL) OPENSSL_free(section); if (line != NULL) *line = eline; BIO_snprintf(btmp, sizeof btmp, "%ld", eline); ERR_add_error_data(2, "line ", btmp); if ((h != conf->data) && (conf->data != NULL)) { CONF_free(conf->data); conf->data = NULL; } if (v != NULL) { if (v->name != NULL) OPENSSL_free(v->name); if (v->value != NULL) OPENSSL_free(v->value); if (v != NULL) OPENSSL_free(v); } return (0); }
/* * Helper function for validating a DN. This function will validate * a single RDN. If the RDN is valid, 0 will be returned, otherwise * non-zero will be returned. A pointer to the last character processed * will be set in the "last parameter. This will be the end of the RDN * in the valid case, and the illegal character in the invalid case. */ int rdn_validate( const char *begin, const char *end, const char **last ) { int rc = 0; /* Assume RDN is valid */ int numericform = 0; char *separator = NULL; const char *p = begin; /* Find the '=', then use the helpers for descr and numericoid */ if ((separator = PL_strnchr(p, '=', end - begin + 1)) == NULL) { rc = 1; goto exit; } /* Process an attribute type. The 'descr' * form must start with a 'leadkeychar'. */ if (IS_LEADKEYCHAR(*p)) { if ((rc = keystring_validate(p, separator - 1))) { goto exit; } /* See if the 'numericoid' form is being used */ } else if (isdigit(*p)) { numericform = 1; if ((rc = numericoid_validate(p, separator - 1))) { goto exit; } } else { rc = 1; goto exit; } /* Advance the pointer past the '=' and make sure * we're not past the end of the string. */ p = separator + 1; if (p > end) { rc = 1; goto exit; } /* The value must be a 'hexstring' if the 'numericoid' * form of 'attributeType' is used. Per RFC 4514: * * hexstring = SHARP 1*hexpair * hexpair = HEX HEX */ if (numericform) { if ((p == end) || !IS_SHARP(*p)) { rc = 1; goto exit; } p++; /* The value must be a 'string' when the 'descr' form * of 'attributeType' is used. Per RFC 4514: * * string = [ ( leadchar / pair ) [ *( stringchar / pair ) * ( trailchar / pair ) ] ] * * leadchar = LUTF1 / UTFMB * trailchar = TUTF1 / UTFMB * stringchar = SUTF1 / UTFMB * * pair = ESC (ESC / special / hexpair ) * special = escaped / SPACE / SHARP / EQUALS * escaped = DQUOTE / PLUS / COMMA / SEMI / LANGLE / RANGLE * hexpair = HEX HEX */ } else { /* Check the leadchar to see if anything illegal * is there. We need to allow a 'pair' to get * through, so we'll assume that a '\' is the * start of a 'pair' for now. */ if (IS_UTF1(*p) && !IS_ESC(*p) && !IS_LUTF1(*p)) { rc = 1; goto exit; } } /* Loop through string until we find the ',' separator, a '+' * char indicating a multi-value RDN, or we reach the end. */ while ((p <= end) && (*p != ',') && (*p != '+')) { if (numericform) { /* Process a single 'hexpair' */ if ((p == end) || !isxdigit(*p) || !isxdigit(*p + 1)) { rc = 1; goto exit; } p = p + 2; } else { /* Check for a valid 'stringchar'. We handle * multi-byte characters separately. */ if (IS_UTF1(*p)) { /* If we're at the end, check if we have * a valid 'trailchar'. */ if ((p == end) && !IS_TUTF1(*p)) { rc = 1; goto exit; /* Check for a 'pair'. */ } else if (IS_ESC(*p)) { /* We're guaranteed to still have at * least one more character, so lets * take a look at it. */ p++; if (!IS_ESC(*p) && !IS_SPECIAL(*p)) { /* The only thing valid now * is a 'hexpair'. */ if ((p == end) || !isxdigit(*p) ||!isxdigit(*p + 1)) { rc = 1; goto exit; } p++; } /* Only allow 'SUTF1' chars now. */ } else if (!IS_SUTF1(*p)) { rc = 1; goto exit; } p++; } else { /* Validate a single 'UTFMB' (multi-byte) character. */ if (utf8char_validate(p, end, &p ) != 0) { rc = 1; goto exit; } /* Advance the pointer past the multi-byte char. */ p++; } } } /* We'll end up either at the comma, a '+', or one past end. * If we are processing a multi-valued RDN, we recurse to * process the next 'attributeTypeAndValue'. */ if ((p <= end) && (*p == '+')) { /* Make sure that there is something after the '+'. */ if (p == end) { rc = 1; goto exit; } p++; /* Recurse to process the next value. We need to reset p to * ensure that last is set correctly for the original caller. */ rc = rdn_validate( p, end, last ); p = *last + 1; } exit: *last = p - 1; return rc; }