static char * getFullStateJSON(void) { char separator = '{'; size_t alloc = INITIAL_ALLOC; char * state; int i, s; Pgn * pgn; size_t remain = alloc; size_t l; time_t now = time(0); state = malloc(alloc); for (l = 0, i = 0; i < maxPgnList; i++) { pgn = *pgnList[i]; MAKE_SPACE(100 + strlen(pgn->p_description)); snprintf(state + l, remain, "%c\"%u\":\n {\"description\":\"%s\"\n" , separator , pgn->p_prn , pgn->p_description ); INC_L_REMAIN; for (s = 0; s < pgn->p_maxSrc; s++) { Message * m = &pgn->p_message[s]; if (m->m_time >= now) { MAKE_SPACE(strlen(m->m_text) + 32); snprintf(state + l, remain, " ,\"%u%s%s\":%s" , m->m_src , m->m_key2 ? "_" : "" , m->m_key2 ? m->m_key2 : "" , m->m_text ); INC_L_REMAIN; } } strcpy(state + l, " }\n"); INC_L_REMAIN; separator = ','; } if (separator == ',') { strcpy(state + l, "}\n"); } else { strcpy(state + l, "\n"); } logDebug("state %d bytes\n", strlen(state)); return state; }
char * entry2str_wrap( Entry *e, int *len, ber_len_t wrap ) { Attribute *a; struct berval *bv; int i; ber_len_t tmplen; assert( e != NULL ); /* * In string format, an entry looks like this: * dn: <dn>\n * [<attr>: <value>\n]* */ ecur = ebuf; /* put the dn */ if ( e->e_dn != NULL ) { /* put "dn: <dn>" */ tmplen = e->e_name.bv_len; MAKE_SPACE( LDIF_SIZE_NEEDED( 2, tmplen )); ldif_sput_wrap( &ecur, LDIF_PUT_VALUE, "dn", e->e_dn, tmplen, wrap ); } /* put the attributes */ for ( a = e->e_attrs; a != NULL; a = a->a_next ) { /* put "<type>:[:] <value>" line for each value */ for ( i = 0; a->a_vals[i].bv_val != NULL; i++ ) { bv = &a->a_vals[i]; tmplen = a->a_desc->ad_cname.bv_len; MAKE_SPACE( LDIF_SIZE_NEEDED( tmplen, bv->bv_len )); ldif_sput_wrap( &ecur, LDIF_PUT_VALUE, a->a_desc->ad_cname.bv_val, bv->bv_val, bv->bv_len, wrap ); } } MAKE_SPACE( 1 ); *ecur = '\0'; *len = ecur - ebuf; return( ebuf ); }
/**************** * Scan the provided buffer and return the S expression in our internal * format. Returns a newly allocated expression. If erroff is not NULL and * a parsing error has occurred, the offset into buffer will be returned. * If ARGFLAG is true, the function supports some printf like * expressions. * These are: * %m - MPI * %s - string (no autoswitch to secure allocation) * %d - integer stored as string (no autoswitch to secure allocation) * %b - memory buffer; this takes _two_ arguments: an integer with the * length of the buffer and a pointer to the buffer. * %S - Copy an gcry_sexp_t here. The S-expression needs to be a * regular one, starting with a parenthesis. * (no autoswitch to secure allocation) * all other format elements are currently not defined and return an error. * this includes the "%%" sequence becauce the percent sign is not an * allowed character. * FIXME: We should find a way to store the secure-MPIs not in the string * but as reference to somewhere - this can help us to save huge amounts * of secure memory. The problem is, that if only one element is secure, all * other elements are automagicaly copied to secure memory too, so the most * common operation gcry_sexp_cdr_mpi() will always return a secure MPI * regardless whether it is needed or not. */ static gcry_error_t vsexp_sscan (gcry_sexp_t *retsexp, size_t *erroff, const char *buffer, size_t length, int argflag, void **arg_list, va_list arg_ptr) { gcry_err_code_t err = 0; static const char tokenchars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789-./_:*+="; const char *p; size_t n; const char *digptr = NULL; const char *quoted = NULL; const char *tokenp = NULL; const char *hexfmt = NULL; const char *base64 = NULL; const char *disphint = NULL; const char *percent = NULL; int hexcount = 0; int quoted_esc = 0; int datalen = 0; size_t dummy_erroff; struct make_space_ctx c; int arg_counter = 0; int level = 0; if (!erroff) erroff = &dummy_erroff; /* Depending on whether ARG_LIST is non-zero or not, this macro gives us the next argument, either from the variable argument list as specified by ARG_PTR or from the argument array ARG_LIST. */ #define ARG_NEXT(storage, type) \ do \ { \ if (!arg_list) \ storage = va_arg (arg_ptr, type); \ else \ storage = *((type *) (arg_list[arg_counter++])); \ } \ while (0) /* The MAKE_SPACE macro is used before each store operation to ensure that the buffer is large enough. It requires a global context named C and jumps out to the label LEAVE on error! It also sets ERROFF using the variables BUFFER and P. */ #define MAKE_SPACE(n) do { \ gpg_err_code_t _ms_err = make_space (&c, (n)); \ if (_ms_err) \ { \ err = _ms_err; \ *erroff = p - buffer; \ goto leave; \ } \ } while (0) /* The STORE_LEN macro is used to store the length N at buffer P. */ #define STORE_LEN(p,n) do { \ DATALEN ashort = (n); \ memcpy ( (p), &ashort, sizeof(ashort) ); \ (p) += sizeof (ashort); \ } while (0) /* We assume that the internal representation takes less memory than the provided one. However, we add space for one extra datalen so that the code which does the ST_CLOSE can use MAKE_SPACE */ c.allocated = length + sizeof(DATALEN); if (buffer && length && gcry_is_secure (buffer)) c.sexp = gcry_malloc_secure (sizeof *c.sexp + c.allocated - 1); else c.sexp = gcry_malloc (sizeof *c.sexp + c.allocated - 1); if (!c.sexp) { err = gpg_err_code_from_errno (errno); *erroff = 0; goto leave; } c.pos = c.sexp->d; for (p = buffer, n = length; n; p++, n--) { if (tokenp && !hexfmt) { if (strchr (tokenchars, *p)) continue; else { datalen = p - tokenp; MAKE_SPACE (datalen); *c.pos++ = ST_DATA; STORE_LEN (c.pos, datalen); memcpy (c.pos, tokenp, datalen); c.pos += datalen; tokenp = NULL; } } if (quoted) { if (quoted_esc) { switch (*p) { case 'b': case 't': case 'v': case 'n': case 'f': case 'r': case '"': case '\'': case '\\': quoted_esc = 0; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': if (!((n > 2) && (p[1] >= '0') && (p[1] <= '7') && (p[2] >= '0') && (p[2] <= '7'))) { *erroff = p - buffer; /* Invalid octal value. */ err = GPG_ERR_SEXP_BAD_QUOTATION; goto leave; } p += 2; n -= 2; quoted_esc = 0; break; case 'x': if (!((n > 2) && hexdigitp (p+1) && hexdigitp (p+2))) { *erroff = p - buffer; /* Invalid hex value. */ err = GPG_ERR_SEXP_BAD_QUOTATION; goto leave; } p += 2; n -= 2; quoted_esc = 0; break; case '\r': /* ignore CR[,LF] */ if (n && (p[1] == '\n')) { p++; n--; } quoted_esc = 0; break; case '\n': /* ignore LF[,CR] */ if (n && (p[1] == '\r')) { p++; n--; } quoted_esc = 0; break; default: *erroff = p - buffer; /* Invalid quoted string escape. */ err = GPG_ERR_SEXP_BAD_QUOTATION; goto leave; } } else if (*p == '\\') quoted_esc = 1; else if (*p == '\"') { /* Keep it easy - we know that the unquoted string will never be larger. */ unsigned char *save; size_t len; quoted++; /* Skip leading quote. */ MAKE_SPACE (p - quoted); *c.pos++ = ST_DATA; save = c.pos; STORE_LEN (c.pos, 0); /* Will be fixed up later. */ len = unquote_string (quoted, p - quoted, c.pos); c.pos += len; STORE_LEN (save, len); quoted = NULL; } } else if (hexfmt) { if (isxdigit (*p)) hexcount++; else if (*p == '#') { if ((hexcount & 1)) { *erroff = p - buffer; err = GPG_ERR_SEXP_ODD_HEX_NUMBERS; goto leave; } datalen = hexcount / 2; MAKE_SPACE (datalen); *c.pos++ = ST_DATA; STORE_LEN (c.pos, datalen); for (hexfmt++; hexfmt < p; hexfmt++) { int tmpc; if (whitespacep (hexfmt)) continue; tmpc = hextonibble (*(const unsigned char*)hexfmt); for (hexfmt++; hexfmt < p && whitespacep (hexfmt); hexfmt++) ; if (hexfmt < p) { tmpc *= 16; tmpc += hextonibble (*(const unsigned char*)hexfmt); } *c.pos++ = tmpc; } hexfmt = NULL; } else if (!whitespacep (p)) { *erroff = p - buffer; err = GPG_ERR_SEXP_BAD_HEX_CHAR; goto leave; } } else if (base64) { if (*p == '|') base64 = NULL; } else if (digptr) { if (digitp (p)) ; else if (*p == ':') { datalen = atoi (digptr); /* FIXME: check for overflow. */ digptr = NULL; if (datalen > n - 1) { *erroff = p - buffer; /* Buffer too short. */ err = GPG_ERR_SEXP_STRING_TOO_LONG; goto leave; } /* Make a new list entry. */ MAKE_SPACE (datalen); *c.pos++ = ST_DATA; STORE_LEN (c.pos, datalen); memcpy (c.pos, p + 1, datalen); c.pos += datalen; n -= datalen; p += datalen; } else if (*p == '\"') { digptr = NULL; /* We ignore the optional length. */ quoted = p; quoted_esc = 0; } else if (*p == '#') { digptr = NULL; /* We ignore the optional length. */ hexfmt = p; hexcount = 0; } else if (*p == '|') { digptr = NULL; /* We ignore the optional length. */ base64 = p; } else { *erroff = p - buffer; err = GPG_ERR_SEXP_INV_LEN_SPEC; goto leave; } } else if (percent) { if (*p == 'm' || *p == 'M') { /* Insert an MPI. */ gcry_mpi_t m; size_t nm = 0; int mpifmt = *p == 'm'? GCRYMPI_FMT_STD: GCRYMPI_FMT_USG; ARG_NEXT (m, gcry_mpi_t); if (gcry_mpi_get_flag (m, GCRYMPI_FLAG_OPAQUE)) { void *mp; unsigned int nbits; mp = gcry_mpi_get_opaque (m, &nbits); nm = (nbits+7)/8; if (mp && nm) { MAKE_SPACE (nm); if (!gcry_is_secure (c.sexp->d) && gcry_mpi_get_flag (m, GCRYMPI_FLAG_SECURE)) { /* We have to switch to secure allocation. */ gcry_sexp_t newsexp; byte *newhead; newsexp = gcry_malloc_secure (sizeof *newsexp + c.allocated - 1); if (!newsexp) { err = gpg_err_code_from_errno (errno); goto leave; } newhead = newsexp->d; memcpy (newhead, c.sexp->d, (c.pos - c.sexp->d)); c.pos = newhead + (c.pos - c.sexp->d); gcry_free (c.sexp); c.sexp = newsexp; } *c.pos++ = ST_DATA; STORE_LEN (c.pos, nm); memcpy (c.pos, mp, nm); c.pos += nm; } } else { if (gcry_mpi_print (mpifmt, NULL, 0, &nm, m)) BUG (); MAKE_SPACE (nm); if (!gcry_is_secure (c.sexp->d) && gcry_mpi_get_flag ( m, GCRYMPI_FLAG_SECURE)) { /* We have to switch to secure allocation. */ gcry_sexp_t newsexp; byte *newhead; newsexp = gcry_malloc_secure (sizeof *newsexp + c.allocated - 1); if (!newsexp) { err = gpg_err_code_from_errno (errno); goto leave; } newhead = newsexp->d; memcpy (newhead, c.sexp->d, (c.pos - c.sexp->d)); c.pos = newhead + (c.pos - c.sexp->d); gcry_free (c.sexp); c.sexp = newsexp; } *c.pos++ = ST_DATA; STORE_LEN (c.pos, nm); if (gcry_mpi_print (mpifmt, c.pos, nm, &nm, m)) BUG (); c.pos += nm; } } else if (*p == 's') { /* Insert an string. */ const char *astr; size_t alen; ARG_NEXT (astr, const char *); alen = strlen (astr); MAKE_SPACE (alen); *c.pos++ = ST_DATA; STORE_LEN (c.pos, alen); memcpy (c.pos, astr, alen); c.pos += alen; } else if (*p == 'b') { /* Insert a memory buffer. */ const char *astr; int alen; ARG_NEXT (alen, int); ARG_NEXT (astr, const char *); MAKE_SPACE (alen); if (alen && !gcry_is_secure (c.sexp->d) && gcry_is_secure (astr)) { /* We have to switch to secure allocation. */ gcry_sexp_t newsexp; byte *newhead; newsexp = gcry_malloc_secure (sizeof *newsexp + c.allocated - 1); if (!newsexp) { err = gpg_err_code_from_errno (errno); goto leave; } newhead = newsexp->d; memcpy (newhead, c.sexp->d, (c.pos - c.sexp->d)); c.pos = newhead + (c.pos - c.sexp->d); gcry_free (c.sexp); c.sexp = newsexp; } *c.pos++ = ST_DATA; STORE_LEN (c.pos, alen); memcpy (c.pos, astr, alen); c.pos += alen; } else if (*p == 'd') { /* Insert an integer as string. */ int aint; size_t alen; char buf[35]; ARG_NEXT (aint, int); sprintf (buf, "%d", aint); alen = strlen (buf); MAKE_SPACE (alen); *c.pos++ = ST_DATA; STORE_LEN (c.pos, alen); memcpy (c.pos, buf, alen); c.pos += alen; } else if (*p == 'u') { /* Insert an unsigned integer as string. */ unsigned int aint; size_t alen; char buf[35]; ARG_NEXT (aint, unsigned int); sprintf (buf, "%u", aint); alen = strlen (buf); MAKE_SPACE (alen); *c.pos++ = ST_DATA; STORE_LEN (c.pos, alen); memcpy (c.pos, buf, alen); c.pos += alen; } else if (*p == 'S') { /* Insert a gcry_sexp_t. */ gcry_sexp_t asexp; size_t alen, aoff; ARG_NEXT (asexp, gcry_sexp_t); alen = get_internal_buffer (asexp, &aoff); if (alen) { MAKE_SPACE (alen); memcpy (c.pos, asexp->d + aoff, alen); c.pos += alen; } } else { *erroff = p - buffer; /* Invalid format specifier. */ err = GPG_ERR_SEXP_INV_LEN_SPEC; goto leave; } percent = NULL; } else if (*p == '(') { if (disphint) { *erroff = p - buffer; /* Open display hint. */ err = GPG_ERR_SEXP_UNMATCHED_DH; goto leave; } MAKE_SPACE (0); *c.pos++ = ST_OPEN; level++; } else if (*p == ')') { /* Walk up. */ if (disphint) { *erroff = p - buffer; /* Open display hint. */ err = GPG_ERR_SEXP_UNMATCHED_DH; goto leave; } MAKE_SPACE (0); *c.pos++ = ST_CLOSE; level--; } else if (*p == '\"') { quoted = p; quoted_esc = 0; } else if (*p == '#') { hexfmt = p; hexcount = 0; } else if (*p == '|') base64 = p; else if (*p == '[') { if (disphint) { *erroff = p - buffer; /* Open display hint. */ err = GPG_ERR_SEXP_NESTED_DH; goto leave; } disphint = p; } else if (*p == ']') { if (!disphint) { *erroff = p - buffer; /* Open display hint. */ err = GPG_ERR_SEXP_UNMATCHED_DH; goto leave; } disphint = NULL; } else if (digitp (p)) { if (*p == '0') { /* A length may not begin with zero. */ *erroff = p - buffer; err = GPG_ERR_SEXP_ZERO_PREFIX; goto leave; } digptr = p; } else if (strchr (tokenchars, *p)) tokenp = p; else if (whitespacep (p)) ; else if (*p == '{') { /* fixme: handle rescanning: we can do this by saving our current state and start over at p+1 -- Hmmm. At this point here we are in a well defined state, so we don't need to save it. Great. */ *erroff = p - buffer; err = GPG_ERR_SEXP_UNEXPECTED_PUNC; goto leave; } else if (strchr ("&\\", *p)) { /* Reserved punctuation. */ *erroff = p - buffer; err = GPG_ERR_SEXP_UNEXPECTED_PUNC; goto leave; } else if (argflag && (*p == '%')) percent = p; else { /* Bad or unavailable. */ *erroff = p - buffer; err = GPG_ERR_SEXP_BAD_CHARACTER; goto leave; } } MAKE_SPACE (0); *c.pos++ = ST_STOP; if (level && !err) err = GPG_ERR_SEXP_UNMATCHED_PAREN; leave: if (err) { /* Error -> deallocate. */ if (c.sexp) { /* Extra paranoid wipe on error. */ if (gcry_is_secure (c.sexp)) wipememory (c.sexp, sizeof (struct gcry_sexp) + c.allocated - 1); gcry_free (c.sexp); } /* This might be expected by existing code... */ *retsexp = NULL; } else *retsexp = normalize (c.sexp); return gcry_error (err); #undef MAKE_SPACE #undef STORE_LEN }