p->name_reqd = p->instr_reqd = FALSE;
return p;
}
-void add_prompt(prompts_t *p, char *promptstr, int echo, size_t len)
+void add_prompt(prompts_t *p, char *promptstr, int echo)
{
prompt_t *pr = snew(prompt_t);
- char *result = snewn(len, char);
pr->prompt = promptstr;
pr->echo = echo;
- pr->result = result;
- pr->result_len = len;
+ 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];
- memset(pr->result, 0, pr->result_len); /* burn the evidence */
+ smemclr(pr->result, pr->resultsize); /* burn the evidence */
sfree(pr->result);
sfree(pr->prompt);
sfree(pr);
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.
*
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