return c;
}
+prompts_t *new_prompts(void *frontend)
+{
+ prompts_t *p = snew(prompts_t);
+ p->prompts = NULL;
+ p->n_prompts = 0;
+ p->frontend = frontend;
+ p->data = NULL;
+ p->to_server = TRUE; /* to be on the safe side */
+ p->name = p->instruction = NULL;
+ p->name_reqd = p->instr_reqd = FALSE;
+ return p;
+}
+void add_prompt(prompts_t *p, char *promptstr, int echo)
+{
+ prompt_t *pr = snew(prompt_t);
+ pr->prompt = promptstr;
+ pr->echo = echo;
+ pr->result = NULL;
+ pr->resultsize = 0;
+ p->n_prompts++;
+ p->prompts = sresize(p->prompts, p->n_prompts, prompt_t *);
+ p->prompts[p->n_prompts-1] = pr;
+}
+void prompt_ensure_result_size(prompt_t *pr, int newlen)
+{
+ if ((int)pr->resultsize < newlen) {
+ char *newbuf;
+ newlen = newlen * 5 / 4 + 512; /* avoid too many small allocs */
+
+ /*
+ * We don't use sresize / realloc here, because we will be
+ * storing sensitive stuff like passwords in here, and we want
+ * to make sure that the data doesn't get copied around in
+ * memory without the old copy being destroyed.
+ */
+ newbuf = snewn(newlen, char);
+ memcpy(newbuf, pr->result, pr->resultsize);
+ smemclr(pr->result, pr->resultsize);
+ sfree(pr->result);
+ pr->result = newbuf;
+ pr->resultsize = newlen;
+ }
+}
+void prompt_set_result(prompt_t *pr, const char *newstr)
+{
+ prompt_ensure_result_size(pr, strlen(newstr) + 1);
+ strcpy(pr->result, newstr);
+}
+void free_prompts(prompts_t *p)
+{
+ size_t i;
+ for (i=0; i < p->n_prompts; i++) {
+ prompt_t *pr = p->prompts[i];
+ smemclr(pr->result, pr->resultsize); /* burn the evidence */
+ sfree(pr->result);
+ sfree(pr->prompt);
+ sfree(pr);
+ }
+ sfree(p->prompts);
+ sfree(p->name);
+ sfree(p->instruction);
+ sfree(p);
+}
+
/* ----------------------------------------------------------------------
* String handling routines.
*/
return p;
}
+void burnstr(char *string) /* sfree(str), only clear it first */
+{
+ if (string) {
+ smemclr(string, strlen(string));
+ sfree(string);
+ }
+}
+
/*
* Do an sprintf(), but into a custom-allocated buffer.
*
* Currently I'm doing this via vsnprintf. This has worked so far,
- * but it's not good, because:
- *
- * - vsnprintf is not available on all platforms. There's an ifdef
- * to use `_vsnprintf', which seems to be the local name for it
- * on Windows. Other platforms may lack it completely, in which
- * case it'll be time to rewrite this function in a totally
- * different way.
- *
- * - technically you can't reuse a va_list like this: it is left
- * unspecified whether advancing a va_list pointer modifies its
- * value or something it points to, so on some platforms calling
- * vsnprintf twice on the same va_list might fail hideously. It
- * would be better to use the `va_copy' macro mandated by C99,
- * but that too is not yet ubiquitous.
+ * but it's not good, because vsnprintf is not available on all
+ * platforms. There's an ifdef to use `_vsnprintf', which seems
+ * to be the local name for it on Windows. Other platforms may
+ * lack it completely, in which case it'll be time to rewrite
+ * this function in a totally different way.
*
* The only `properly' portable solution I can think of is to
* implement my own format string scanner, which figures out an
#ifdef _WINDOWS
#define vsnprintf _vsnprintf
#endif
+#ifdef va_copy
+ /* Use the `va_copy' macro mandated by C99, if present.
+ * XXX some environments may have this as __va_copy() */
+ va_list aq;
+ va_copy(aq, ap);
+ len = vsnprintf(buf, size, fmt, aq);
+ va_end(aq);
+#else
+ /* Ugh. No va_copy macro, so do something nasty.
+ * Technically, you can't reuse a va_list like this: it is left
+ * unspecified whether advancing a va_list pointer modifies its
+ * value or something it points to, so on some platforms calling
+ * vsnprintf twice on the same va_list might fail hideously
+ * (indeed, it has been observed to).
+ * XXX the autoconf manual suggests that using memcpy() will give
+ * "maximum portability". */
len = vsnprintf(buf, size, fmt, ap);
+#endif
if (len >= 0 && len < size) {
/* This is the C99-specified criterion for snprintf to have
* been completely successful. */
* - return the current size of the buffer chain in bytes
*/
-#define BUFFER_GRANULE 512
+#define BUFFER_MIN_GRANULE 512
struct bufchain_granule {
struct bufchain_granule *next;
- int buflen, bufpos;
- char buf[BUFFER_GRANULE];
+ char *bufpos, *bufend, *bufmax;
};
void bufchain_init(bufchain *ch)
ch->buffersize += len;
- if (ch->tail && ch->tail->buflen < BUFFER_GRANULE) {
- int copylen = min(len, BUFFER_GRANULE - ch->tail->buflen);
- memcpy(ch->tail->buf + ch->tail->buflen, buf, copylen);
- buf += copylen;
- len -= copylen;
- ch->tail->buflen += copylen;
- }
while (len > 0) {
- int grainlen = min(len, BUFFER_GRANULE);
- struct bufchain_granule *newbuf;
- newbuf = snew(struct bufchain_granule);
- newbuf->bufpos = 0;
- newbuf->buflen = grainlen;
- memcpy(newbuf->buf, buf, grainlen);
- buf += grainlen;
- len -= grainlen;
- if (ch->tail)
- ch->tail->next = newbuf;
- else
- ch->head = ch->tail = newbuf;
- newbuf->next = NULL;
- ch->tail = newbuf;
+ if (ch->tail && ch->tail->bufend < ch->tail->bufmax) {
+ int copylen = min(len, ch->tail->bufmax - ch->tail->bufend);
+ memcpy(ch->tail->bufend, buf, copylen);
+ buf += copylen;
+ len -= copylen;
+ ch->tail->bufend += copylen;
+ }
+ if (len > 0) {
+ int grainlen =
+ max(sizeof(struct bufchain_granule) + len, BUFFER_MIN_GRANULE);
+ struct bufchain_granule *newbuf;
+ newbuf = smalloc(grainlen);
+ newbuf->bufpos = newbuf->bufend =
+ (char *)newbuf + sizeof(struct bufchain_granule);
+ newbuf->bufmax = (char *)newbuf + grainlen;
+ newbuf->next = NULL;
+ if (ch->tail)
+ ch->tail->next = newbuf;
+ else
+ ch->head = newbuf;
+ ch->tail = newbuf;
+ }
}
}
while (len > 0) {
int remlen = len;
assert(ch->head != NULL);
- if (remlen >= ch->head->buflen - ch->head->bufpos) {
- remlen = ch->head->buflen - ch->head->bufpos;
+ if (remlen >= ch->head->bufend - ch->head->bufpos) {
+ remlen = ch->head->bufend - ch->head->bufpos;
tmp = ch->head;
ch->head = tmp->next;
- sfree(tmp);
if (!ch->head)
ch->tail = NULL;
+ sfree(tmp);
} else
ch->head->bufpos += remlen;
ch->buffersize -= remlen;
void bufchain_prefix(bufchain *ch, void **data, int *len)
{
- *len = ch->head->buflen - ch->head->bufpos;
- *data = ch->head->buf + ch->head->bufpos;
+ *len = ch->head->bufend - ch->head->bufpos;
+ *data = ch->head->bufpos;
}
void bufchain_fetch(bufchain *ch, void *data, int len)
int remlen = len;
assert(tmp != NULL);
- if (remlen >= tmp->buflen - tmp->bufpos)
- remlen = tmp->buflen - tmp->bufpos;
- memcpy(data_c, tmp->buf + tmp->bufpos, remlen);
+ if (remlen >= tmp->bufend - tmp->bufpos)
+ remlen = tmp->bufend - tmp->bufpos;
+ memcpy(data_c, tmp->bufpos, remlen);
tmp = tmp->next;
len -= remlen;
if (L) {
int delta;
debug_printf("\t%d (0x%x) bytes:\n", len, len);
- delta = 15 & (int) p;
+ delta = 15 & (unsigned long int) p;
p -= delta;
len += delta;
}
}
#endif /* def DEBUG */
+
+/*
+ * Determine whether or not a Conf represents a session which can
+ * sensibly be launched right now.
+ */
+int conf_launchable(Conf *conf)
+{
+ if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL)
+ return conf_get_str(conf, CONF_serline)[0] != 0;
+ else
+ return conf_get_str(conf, CONF_host)[0] != 0;
+}
+
+char const *conf_dest(Conf *conf)
+{
+ if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL)
+ return conf_get_str(conf, CONF_serline);
+ else
+ return conf_get_str(conf, CONF_host);
+}
+
+#ifndef PLATFORM_HAS_SMEMCLR
+/*
+ * Securely wipe memory.
+ *
+ * The actual wiping is no different from what memset would do: the
+ * point of 'securely' is to try to be sure over-clever compilers
+ * won't optimise away memsets on variables that are about to be freed
+ * or go out of scope. See
+ * https://buildsecurityin.us-cert.gov/bsi-rules/home/g1/771-BSI.html
+ *
+ * Some platforms (e.g. Windows) may provide their own version of this
+ * function.
+ */
+void smemclr(void *b, size_t n) {
+ volatile char *vp;
+
+ if (b && n > 0) {
+ /*
+ * Zero out the memory.
+ */
+ memset(b, 0, n);
+
+ /*
+ * Perform a volatile access to the object, forcing the
+ * compiler to admit that the previous memset was important.
+ *
+ * This while loop should in practice run for zero iterations
+ * (since we know we just zeroed the object out), but in
+ * theory (as far as the compiler knows) it might range over
+ * the whole object. (If we had just written, say, '*vp =
+ * *vp;', a compiler could in principle have 'helpfully'
+ * optimised the memset into only zeroing out the first byte.
+ * This should be robust.)
+ */
+ vp = b;
+ while (*vp) vp++;
+ }
+}
+#endif