Add a missing \define I accidentally assumed was there in r9592.
[sgt/putty] / misc.c
diff --git a/misc.c b/misc.c
index 37ac0a1..76e5fab 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -99,24 +99,48 @@ prompts_t *new_prompts(void *frontend)
     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);
-    unsigned char *result = snewn(len, unsigned 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);
@@ -176,24 +200,23 @@ char *dupcat(const char *s1, ...)
     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
@@ -241,7 +264,24 @@ char *dupvprintf(const char *fmt, va_list ap)
 #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. */
@@ -597,7 +637,7 @@ void debug_memdump(void *buf, int len, int L)
     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;
     }
@@ -625,3 +665,63 @@ void debug_memdump(void *buf, int len, int L)
 }
 
 #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