Merge branch 'develop'

master v0.3.1
Damien Goutte-Gattat 8 years ago
commit 68351d6418
  1. 6
      NEWS
  2. 2
      configure.ac
  3. 6
      man/scdtotp.1.in
  4. 87
      src/gpg-util.c
  5. 25
      src/scdtotp.c

@ -1,3 +1,9 @@
Changes in scdtools 0.3.1
* Add the -w, --window option to scdtotp.
* Programs may now start GPG-Agent if needed.
Changes in scdtools 0.3.0
* Rename project to scdtools.

@ -1,6 +1,6 @@
dnl Configure template for the scdrand package
AC_INIT([scdtools], [0.3.0],
AC_INIT([scdtools], [0.3.1],
[dgouttegattat@incenp.org])
AC_CONFIG_SRCDIR([configure.ac])
AC_CONFIG_MACRO_DIR([m4])

@ -11,6 +11,8 @@ scdtotp \- Generate one-time passwords from an OpenPGP smartcard
.IR seconds ]
.RB [ \-p | --period
.IR seconds ]
.RB [ \-w | --window
.IR N ]
.RB [ \-d | --digits
.IR N ]
.RB [ \-m | --mac-algo
@ -47,6 +49,10 @@ instead of current time.
Force a period of \fiN\fR seconds. The default period
is 30 seconds, unless specified otherwise on the card.
.TP
.BR -w ", " --window " " \fiN\fR
Generate password for \fiN\fR time window around the
current time.
.TP
.BR -d ", " --digits " " \fiN\fR
Output a password of
.I N

@ -27,52 +27,31 @@
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <gcrypt.h>
#include "gpg-util.h"
/*
* Wrap call to asprintf to make sure that when a memory allocation
* error occurs, errno is set to ENOMEM and the string pointer is
* set to NULL.
*/
static int
do_asprintf(char **strp, const char *fmt, ...)
{
int n;
va_list ap;
va_start(ap, fmt);
if ( (n = vasprintf(strp, fmt, ap)) == -1 ) {
errno = ENOMEM;
*strp = NULL;
}
va_end(ap);
return n;
}
/*
* Find the socket of GnuPG Agent. First look for the GPG_AGENT_INFO
* environment variable, and if unset look for the standard socket
* in GnuPG's home directory.
* environment variable, if unset look for the standard socket in
* GnuPG's home directory, if not found use gpg-connect-agent.
*
* The socket name is stored in a newly allocated buffer that should
* be freed by the caller.
*
* May return NULL upon memory allocation error, or if the user's
* home directory cannot be found.
* Return NULL if the socket could not be found.
*/
static char *
get_agent_socket_name(void)
{
char *env_info, *socket_name;
struct passwd *pwd;
char *env_info, *socket_name = NULL;
/* First look for GPG_AGENT_INFO in the environment. */
if ( (env_info = getenv("GPG_AGENT_INFO")) ) {
if ( (socket_name = strdup(env_info)) ) {
char *colon_index;
@ -80,23 +59,49 @@ get_agent_socket_name(void)
/*
* GPG_AGENT_INFO should be of the form
* "path_to_socket:x:y", where x is the PID
* of the GnuPG Agent and y is the protocol
* version (currently 1).
* of the GnuPG Agent process and y is the
* protocol version (currently 1).
*/
if ( (colon_index = strchr(socket_name, ':')) )
*colon_index = '\0';
}
}
else if ( (env_info = getenv("GNUPGHOME")) )
do_asprintf(&socket_name, "%s/S.gpg-agent", env_info);
else if ( (env_info = getenv("HOME")) )
do_asprintf(&socket_name, "%s/.gnupg/S.gpg-agent", env_info);
else if ( (pwd = getpwuid(getuid())) )
do_asprintf(&socket_name, "%s/.gnupg/S.gpg-agent", pwd->pw_dir);
else
/* No way to get the user's home directory?
* Can that ever happen? */
socket_name = NULL;
else {
/* Then look for the standard socket. */
char buf[255] = "";
struct passwd *pwd;
struct stat st;
if ( (env_info = getenv("GNUPGHOME")) )
snprintf(buf, sizeof(buf), "%s/S.gpg-agent", env_info);
else if ( (env_info = getenv("HOME")) )
snprintf(buf, sizeof(buf), "%s/.gnupg/S.gpg-agent", env_info);
else if ( (pwd = getpwuid(getuid())) )
snprintf(buf, sizeof(buf), "%s/.gnupg/S.gpg-agent", pwd->pw_dir);
/* Check whether the socket does exist. */
if ( *buf && stat(buf, &st) != -1 && S_ISSOCK(st.st_mode) )
socket_name = strdup(buf);
else {
/*
* Finally, try to ask the agent directly. This method could
* replace the two above, but since it requires spawning a
* new process, we use it only as a fallback. We expect that
* most of the time, the agent should already be running when
* our programs are called, and thus the socket would already
* exist and be found by the above code.
*/
FILE *f;
f = popen("gpg-connect-agent 'GETINFO socket_name' /bye", "r");
if ( f ) {
if ( fscanf(f, "D %254s\nOK\n", buf) == 1 )
socket_name = strdup(buf);
pclose(f);
}
}
}
return socket_name;
}

@ -52,6 +52,8 @@ found in a OpenPGP smartcard.\n\
puts("\
-t, --time SECONDS Generate OTP for the specified time\n\
(in seconds) instead of current time.\n\
-w, --window N Generate OTP for N time windows around\n\
the current time.\n\
");
printf("\
@ -293,8 +295,8 @@ get_uinteger_or_die(const char *arg)
int
main(int argc, char **argv)
{
int c;
unsigned algo, period, digits, privatedo, value;
int c, n;
unsigned algo, period, digits, privatedo, value, window;
time_t secs;
gcry_error_t e;
otp_t *otp;
@ -303,6 +305,7 @@ main(int argc, char **argv)
{ "help", 0, NULL, 'h' },
{ "version", 0, NULL, 'v' },
{ "time", 1, NULL, 't' },
{ "window", 1, NULL, 'w' },
{ "period", 1, NULL, 'p' },
{ "digits", 1, NULL, 'd' },
{ "mac-algo", 1, NULL, 'm' },
@ -314,8 +317,9 @@ main(int argc, char **argv)
secs = time(NULL);
algo = period = digits = UNSET_PARAM;
privatedo = DEFAULT_PRIVATE_DO;
value = window = 0;
while ( (c = getopt_long(argc, argv, "hvt:p:d:m:n:",
while ( (c = getopt_long(argc, argv, "hvt:w:p:d:m:n:",
options, NULL)) != -1 ) {
switch ( c ) {
case 'h':
@ -360,6 +364,10 @@ main(int argc, char **argv)
if ( privatedo < 1 || privatedo > 4 )
errx(EXIT_FAILURE, "DO number must be 1, 2, 3, or 4");
break;
case 'w':
window = get_uinteger_or_die(optarg);
break;
}
}
@ -390,11 +398,14 @@ main(int argc, char **argv)
if ( digits == UNSET_PARAM )
digits = otp->digits;
if ( (e = generate_totp(algo, otp->secret, otp->length, secs,
period, digits, &value)) )
errx(EXIT_FAILURE, "Cannot generate OTP: %s", gcry_strerror(e));
for ( n = -window; n < (signed) window + 1; n++ ) {
if ( (e = generate_totp(algo, otp->secret, otp->length,
secs + (n * (signed)period),
period, digits, &value)) )
errx(EXIT_FAILURE, "Cannot generate OTP: %s", gcry_strerror(e));
print_otp(value, digits);
print_otp(value, digits);
}
return EXIT_SUCCESS;
}

Loading…
Cancel
Save