static int copy_headers(void *in_ch, const char *key, const char *value) { char **ch = in_ch; strcpy(*ch, FIELD_SEPARATOR); *ch += strlen(FIELD_SEPARATOR); *ch = copy_and_escape(*ch, key); strcpy(*ch, KEYVAL_SEPARATOR); *ch += strlen(KEYVAL_SEPARATOR); *ch = copy_and_escape(*ch, value); return 1; }
/* Ask the gpg-agent to clear the passphrase for the cache ID CACHEID. */ int simple_pwclear (const char *cacheid) { char line[500]; char *p; /* We need not more than 50 characters for the command and the terminating nul. */ if (strlen (cacheid) * 3 > sizeof (line) - 50) return SPWQ_PROTOCOL_ERROR; strcpy (line, "CLEAR_PASSPHRASE "); p = line + 17; p = copy_and_escape (p, cacheid); *p++ = '\n'; *p++ = '\0'; return simple_query (line); }
static const char * escnonprint_internal (const char *str, char escape, int base) { static int ringpos; /* current ring position */ int nprcnt; assert (base == 8 || base == 16); nprcnt = count_nonprint (str); if (nprcnt == 0) /* If there are no non-printable chars in STR, don't bother copying anything, just return STR. */ return str; { /* Set up a pointer to the current ring position, so we can write simply r->X instead of ring[ringpos].X. */ struct ringel *r = ring + ringpos; /* Every non-printable character is replaced with the escape char and three (or two, depending on BASE) *additional* chars. Size must also include the length of the original string and one additional char for the terminating \0. */ int needed_size = strlen (str) + 1 + (base == 8 ? 3 * nprcnt : 2 * nprcnt); /* If the current buffer is uninitialized or too small, (re)allocate it. */ if (r->buffer == NULL || r->size < needed_size) { r->buffer = xrealloc (r->buffer, needed_size); r->size = needed_size; } copy_and_escape (str, r->buffer, escape, base); ringpos = (ringpos + 1) % RING_SIZE; return r->buffer; } }
/* Ask the gpg-agent for a passphrase and present the user with a DESCRIPTION, a PROMPT and optionally with a TRYAGAIN extra text. If a CACHEID is not NULL it is used to locate the passphrase in in the cache and store it under this ID. If OPT_CHECK is true gpg-agent is asked to apply some checks on the passphrase security. If ERRORCODE is not NULL it should point a variable receiving an errorcode; this error code might be 0 if the user canceled the operation. The function returns NULL to indicate an error. */ char * simple_pwquery (const char *cacheid, const char *tryagain, const char *prompt, const char *description, int opt_check, int *errorcode) { int fd = -1; int nread; char *result = NULL; char *pw = NULL; char *p; int rc, i; rc = agent_open (&fd); if (rc) goto leave; if (!cacheid) cacheid = "X"; if (!tryagain) tryagain = "X"; if (!prompt) prompt = "X"; if (!description) description = "X"; { char *line; /* We allocate 3 times the needed space so that there is enough space for escaping. */ line = spwq_malloc (15 + 10 + 3*strlen (cacheid) + 1 + 3*strlen (tryagain) + 1 + 3*strlen (prompt) + 1 + 3*strlen (description) + 1 + 2); if (!line) { rc = SPWQ_OUT_OF_CORE; goto leave; } strcpy (line, "GET_PASSPHRASE "); p = line+15; if (opt_check) p = stpcpy (p, "--check "); p = copy_and_escape (p, cacheid); *p++ = ' '; p = copy_and_escape (p, tryagain); *p++ = ' '; p = copy_and_escape (p, prompt); *p++ = ' '; p = copy_and_escape (p, description); *p++ = '\n'; rc = writen (fd, line, p - line); spwq_free (line); if (rc) goto leave; } /* get response */ pw = spwq_secure_malloc (500); nread = readline (fd, pw, 499); if (nread < 0) { rc = -nread; goto leave; } if (nread < 3) { rc = SPWQ_PROTOCOL_ERROR; goto leave; } if (pw[0] == 'O' && pw[1] == 'K' && pw[2] == ' ') { /* we got a passphrase - convert it back from hex */ size_t pwlen = 0; for (i=3; i < nread && hexdigitp (pw+i); i+=2) pw[pwlen++] = xtoi_2 (pw+i); pw[pwlen] = 0; /* make a C String */ result = pw; pw = NULL; } else if ((nread > 7 && !memcmp (pw, "ERR 111", 7) && (pw[7] == ' ' || pw[7] == '\n') ) || ((nread > 4 && !memcmp (pw, "ERR ", 4) && (strtoul (pw+4, NULL, 0) & 0xffff) == 99)) ) { /* 111 is the old Assuan code for canceled which might still be in use by old installations. 99 is GPG_ERR_CANCELED as used by modern gpg-agents; 0xffff is used to mask out the error source. */ #ifdef SPWQ_USE_LOGGING log_info (_("canceled by user\n") ); #endif *errorcode = 0; /* Special error code to indicate Cancel. */ } else if (nread > 4 && !memcmp (pw, "ERR ", 4)) { switch ( (strtoul (pw+4, NULL, 0) & 0xffff) ) { case 85: rc = SPWQ_NO_PIN_ENTRY; break; default: rc = SPWQ_GENERAL_ERROR; break; } } else { #ifdef SPWQ_USE_LOGGING log_error (_("problem with the agent\n")); #endif rc = SPWQ_ERR_RESPONSE; } leave: if (errorcode) *errorcode = rc; if (fd != -1) close (fd); if (pw) spwq_secure_free (pw); return result; }
/* Run a quality inquiry for PASSPHRASE of LENGTH. (We need LENGTH because not all backends might be able to return a proper C-string.). Returns: A value between -100 and 100 to give an estimate of the passphrase's quality. Negative values are use if the caller won't even accept that passphrase. Note that we expect just one data line which should not be escaped in any represent a numeric signed decimal value. Extra data is currently ignored but should not be send at all. */ int pinentry_inq_quality (pinentry_t pin, const char *passphrase, size_t length) { ASSUAN_CONTEXT ctx = pin->ctx_assuan; const char prefix[] = "INQUIRE QUALITY "; char *command; char *line; size_t linelen; int gotvalue = 0; int value = 0; int rc; if (!ctx) return 0; /* Can't run the callback. */ if (length > 300) length = 300; /* Limit so that it definitely fits into an Assuan line. */ command = secmem_malloc (strlen (prefix) + 3*length + 1); if (!command) return 0; strcpy (command, prefix); copy_and_escape (command + strlen(command), passphrase, length); rc = assuan_write_line (ctx, command); secmem_free (command); if (rc) { fprintf (stderr, "ASSUAN WRITE LINE failed: rc=%d\n", rc); return 0; } for (;;) { do { rc = assuan_read_line (ctx, &line, &linelen); if (rc) { fprintf (stderr, "ASSUAN READ LINE failed: rc=%d\n", rc); return 0; } } while (*line == '#' || !linelen); if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D' && (!line[3] || line[3] == ' ')) break; /* END command received*/ if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N' && (!line[3] || line[3] == ' ')) break; /* CAN command received*/ if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' && (!line[3] || line[3] == ' ')) break; /* ERR command received*/ if (line[0] != 'D' || line[1] != ' ' || linelen < 3 || gotvalue) continue; gotvalue = 1; value = atoi (line+2); } if (value < -100) value = -100; else if (value > 100) value = 100; return value; }