/* Perform the simple query QUERY (which must be new-line and 0 terminated) and return the error code. */ int simple_query (const char *query) { int fd = -1; int nread; char response[500]; int rc; rc = agent_open (&fd); if (rc) goto leave; rc = writen (fd, query, strlen (query)); if (rc) goto leave; /* get response */ nread = readline (fd, response, 499); if (nread < 0) { rc = -nread; goto leave; } if (nread < 3) { rc = SPWQ_PROTOCOL_ERROR; goto leave; } if (response[0] == 'O' && response[1] == 'K') /* OK, do nothing. */; else if ((nread > 7 && !memcmp (response, "ERR 111", 7) && (response[7] == ' ' || response[7] == '\n') ) || ((nread > 4 && !memcmp (response, "ERR ", 4) && (strtoul (response+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 } else { #ifdef SPWQ_USE_LOGGING log_error (_("problem with the agent\n")); #endif rc = SPWQ_ERR_RESPONSE; } leave: if (fd != -1) close (fd); return rc; }
/* 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; }
/* Perform the simple query QUERY (which must be new-line and 0 terminated) and return the error code. */ int simple_query (const char *query) { int fd = -1; int nread; char response[500]; int have = 0; int rc; rc = agent_open (&fd); if (rc) goto leave; rc = writen (fd, query, strlen (query)); if (rc) goto leave; while (1) { if (! have || ! strchr (response, '\n')) /* get response */ { nread = readline (fd, &response[have], sizeof (response) - 1 /* NUL */ - have); if (nread < 0) { rc = -nread; goto leave; } have += nread; if (have < 3) { rc = SPWQ_PROTOCOL_ERROR; goto leave; } response[have] = 0; } if (response[0] == 'O' && response[1] == 'K') /* OK, do nothing. */; else if ((nread > 7 && !memcmp (response, "ERR 111", 7) && (response[7] == ' ' || response[7] == '\n') ) || ((nread > 4 && !memcmp (response, "ERR ", 4) && (strtoul (response+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 } else if (response[0] == 'S' && response[1] == ' ') { char *nextline; int consumed; nextline = strchr (response, '\n'); if (! nextline) /* Point to the NUL. */ nextline = &response[have]; else /* Move past the \n. */ nextline ++; consumed = (size_t) nextline - (size_t) response; /* Skip any additional newlines. */ while (consumed < have && response[consumed] == '\n') consumed ++; have -= consumed; if (have) memmove (response, &response[consumed], have + 1); continue; } else { #ifdef SPWQ_USE_LOGGING log_error (_("problem with the agent (unexpected response \"%s\")\n"), response); #endif rc = SPWQ_ERR_RESPONSE; } break; } leave: if (fd != -1) close (fd); return rc; }