gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-anastasis] branch master updated: fix #6532


From: gnunet
Subject: [taler-anastasis] branch master updated: fix #6532
Date: Sun, 14 Feb 2021 23:53:51 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository anastasis.

The following commit(s) were added to refs/heads/master by this push:
     new 5c251da  fix #6532
5c251da is described below

commit 5c251da3b088c75d3ff16192bb9d24175a94798e
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Sun Feb 14 23:53:49 2021 +0100

    fix #6532
---
 contrib/gana                                       |   2 +-
 src/authorization/Makefile.am                      |  21 +-
 .../anastasis_authorization_plugin_email.c         | 375 +++++++++++++++++----
 .../anastasis_authorization_plugin_sms.c           |  15 +-
 src/include/anastasis_redux.h                      |   8 +-
 5 files changed, 331 insertions(+), 90 deletions(-)

diff --git a/contrib/gana b/contrib/gana
index 95a0e41..30748ad 160000
--- a/contrib/gana
+++ b/contrib/gana
@@ -1 +1 @@
-Subproject commit 95a0e418f0b6801e09f2251a4e777ed8906e0f56
+Subproject commit 30748ada3fa0b5d5281dca87b117e774db62a431
diff --git a/src/authorization/Makefile.am b/src/authorization/Makefile.am
index 719258c..b1af53d 100644
--- a/src/authorization/Makefile.am
+++ b/src/authorization/Makefile.am
@@ -21,6 +21,7 @@ libanastasisauthorization_la_LDFLAGS = \
   -lgnunetutil
 
 plugin_LTLIBRARIES = \
+  libanastasis_plugin_authorization_email.la \
   libanastasis_plugin_authorization_file.la \
   libanastasis_plugin_authorization_sms.la
 libanastasis_plugin_authorization_file_la_SOURCES = \
@@ -34,16 +35,16 @@ libanastasis_plugin_authorization_file_la_LDFLAGS = \
   -lgnunetutil \
   $(XLIB)
 
-#libanastasis_plugin_authorization_email_la_SOURCES = \
-#  anastasis_authorization_plugin_email.c
-#libanastasis_plugin_authorization_email_la_LIBADD = \
-#  $(LTLIBINTL)
-#libanastasis_plugin_authorization_email_la_LDFLAGS = \
-#  $(ANASTASIS_PLUGIN_LDFLAGS) \
-#  -ljansson \
-#  -ltalerutil \
-#  -lgnunetutil \
-#  $(XLIB)
+libanastasis_plugin_authorization_email_la_SOURCES = \
+  anastasis_authorization_plugin_email.c
+libanastasis_plugin_authorization_email_la_LIBADD = \
+  $(LTLIBINTL)
+libanastasis_plugin_authorization_email_la_LDFLAGS = \
+  $(ANASTASIS_PLUGIN_LDFLAGS) \
+  -ljansson \
+  -ltalerutil \
+  -lgnunetutil \
+  $(XLIB)
 
 libanastasis_plugin_authorization_sms_la_SOURCES = \
   anastasis_authorization_plugin_sms.c
diff --git a/src/authorization/anastasis_authorization_plugin_email.c 
b/src/authorization/anastasis_authorization_plugin_email.c
index 574fd7f..0f50557 100644
--- a/src/authorization/anastasis_authorization_plugin_email.c
+++ b/src/authorization/anastasis_authorization_plugin_email.c
@@ -19,13 +19,32 @@
  * @author Dominik Meister
  */
 #include "platform.h"
-#include "anastasis-httpd.h"
 #include "anastasis_authorization_plugin.h"
 #include <taler/taler_mhd_lib.h>
 #include <regex.h>
 #include "anastasis_util_lib.h"
 
 
+/**
+ * Saves the State of a authorization plugin.
+ */
+struct Email_Context
+{
+
+  /**
+   * Command which is executed to run the plugin (some bash script or a
+   * command line argument)
+   */
+  char *auth_command;
+
+  /**
+   * Regex for email address validation.
+   */
+  regex_t regex;
+
+};
+
+
 /**
  * Saves the state of a authorization process
  */
@@ -34,27 +53,69 @@ struct ANASTASIS_AUTHORIZATION_State
   /**
    * Public key of the challenge which is authorised
    */
-  const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_public_key;
+  struct ANASTASIS_CRYPTO_TruthUUIDP truth_uuid;
 
   /**
-   * Code which is sent to the user (here saved into a file)
+   * Code which is sent to the user.
    */
   uint64_t code;
 
+  /**
+   * Our plugin context.
+   */
+  struct Email_Context *ctx;
+
+  /**
+   * Function to call when we made progress.
+   */
+  GNUNET_SCHEDULER_TaskCallback trigger;
+
+  /**
+   * Closure for @e trigger.
+   */
+  void *trigger_cls;
+
   /**
    * holds the truth information
    */
   char *email;
 
   /**
-   * closure
+   * Handle to the helper process.
    */
-  void *cls;
+  struct GNUNET_OS_Process *child;
 
   /**
-   * Command which is executed to run the email authentication
+   * Handle to wait for @e child
    */
-  char *auth_command;
+  struct ANASTASIS_ChildWaitHandle *cwh;
+
+  /**
+   * Our client connection, set if suspended.
+   */
+  struct MHD_Connection *connection;
+
+  /**
+   * Message to send.
+   */
+  char *msg;
+
+  /**
+   * Offset of transmission in msg.
+   */
+  size_t msg_off;
+
+  /**
+   * Exit code from helper.
+   */
+  long unsigned int exit_code;
+
+  /**
+   * How did the helper die?
+   */
+  enum GNUNET_OS_ProcessStatusType pst;
+
+
 };
 
 
@@ -82,37 +143,28 @@ email_validate (void *cls,
                 const char *data,
                 size_t data_length)
 {
-  regex_t regex;
+  struct Email_Context *ctx = cls;
   int regex_result;
-  /*FIXME very basic check */
-  const char *regexp = "[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}";
-  char *email = GNUNET_STRINGS_data_to_string_alloc (data,
-                                                     data_length);
-
-  regex_result = regcomp (&regex,
-                          regexp,
-                          REG_EXTENDED);
-  if (0 < regex_result)
-  {
-    GNUNET_break (0);
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Failed to compile regular expression.");
-    regfree (&regex);
-    return GNUNET_NO;
-  }
+  char *phone_number;
 
-  regex_result = regexec (&regex,
-                          email,
+  phone_number = GNUNET_strndup (data,
+                                 data_length);
+  regex_result = regexec (&ctx->regex,
+                          phone_number,
                           0,
                           NULL,
                           0);
+  GNUNET_free (phone_number);
   if (0 != regex_result)
   {
-    regfree (&regex);
+    if (MHD_NO ==
+        TALER_MHD_reply_with_error (connection,
+                                    MHD_HTTP_EXPECTATION_FAILED,
+                                    TALER_EC_ANASTASIS_EMAIL_INVALID,
+                                    NULL))
+      return GNUNET_SYSERR;
     return GNUNET_NO;
   }
-  regfree (&regex);
-  GNUNET_free (email);
   return GNUNET_OK;
 }
 
@@ -122,7 +174,9 @@ email_validate (void *cls,
  * I.e. start to send SMS or e-mail or launch video identification.
  *
  * @param cls closure
- * @param truth_public_key Identifier of the challenge, to be (if possible) 
included in the
+ * @param trigger function to call when we made progress
+ * @param trigger_cls closure for @a trigger
+ * @param truth_uuid Identifier of the challenge, to be (if possible) included 
in the
  *             interaction with the user
  * @param code secret code that the user has to provide back to satisfy the 
challenge in
  *             the main anastasis protocol
@@ -131,25 +185,51 @@ email_validate (void *cls,
  */
 static struct ANASTASIS_AUTHORIZATION_State *
 email_start (void *cls,
-             const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_public_key,
+             GNUNET_SCHEDULER_TaskCallback trigger,
+             void *trigger_cls,
+             const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
              uint64_t code,
-             char *auth_command,
              const void *data,
              size_t data_length)
 {
+  struct Email_Context *ctx = cls;
   struct ANASTASIS_AUTHORIZATION_State *as;
 
   as = GNUNET_new (struct ANASTASIS_AUTHORIZATION_State);
-  as->cls = cls;
-  as->truth_public_key = truth_public_key;
+  as->trigger = trigger;
+  as->trigger_cls = trigger_cls;
+  as->ctx = ctx;
+  as->truth_uuid = *truth_uuid;
   as->code = code;
-  as->auth_command = auth_command;
-  as->email = GNUNET_STRINGS_data_to_string_alloc (data,
-                                                   data_length);
+  as->email = GNUNET_strndup (data,
+                              data_length);
   return as;
 }
 
 
+/**
+ * Function called when our Email helper has terminated.
+ *
+ * @param cls our `struct ANASTASIS_AUHTORIZATION_State`
+ * @param type type of the process
+ * @param exit_code status code of the process
+ */
+static void
+email_done_cb (void *cls,
+               enum GNUNET_OS_ProcessStatusType type,
+               long unsigned int exit_code)
+{
+  struct ANASTASIS_AUTHORIZATION_State *as = cls;
+
+  as->child = NULL;
+  as->cwh = NULL;
+  as->pst = type;
+  as->exit_code = exit_code;
+  MHD_resume_connection (as->connection);
+  as->trigger (as->trigger_cls);
+}
+
+
 /**
  * Begin issuing authentication challenge to user based on @a data.
  * I.e. start to send SMS or e-mail or launch video identification.
@@ -163,44 +243,154 @@ email_process (struct ANASTASIS_AUTHORIZATION_State *as,
                struct MHD_Connection *connection)
 {
   MHD_RESULT mres;
-  struct MHD_Response *resp;
-  char *subject = "Anastasis E-Mail Authentication Service";
-  int p[2];
-  /*FIXME ERROR HANDLING*/
-  int ret = pipe (p);
-
-  pid_t pid = fork ();
-  switch (pid)
+
+  if (NULL == as->msg)
   {
-  case -1:
-    close (p[0]);
-    close (p[1]);
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Error while trying to send email");
-    resp = TALER_MHD_make_error (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
-                                 "Failed to fork process");
-    mres = MHD_queue_response (connection,
-                               MHD_HTTP_INTERNAL_SERVER_ERROR,
-                               resp);
-    MHD_destroy_response (resp);
+    /* First time, start child process and feed pipe */
+    struct GNUNET_DISK_PipeHandle *p;
+    struct GNUNET_DISK_FileHandle *pipe_stdin;
+
+    p = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_RW);
+    if (NULL == p)
+    {
+      mres = TALER_MHD_reply_with_error (connection,
+                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                         
TALER_EC_ANASTASIS_EMAIL_HELPER_EXEC_FAILED,
+                                         "pipe");
+      if (MHD_YES != mres)
+        return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
+      return ANASTASIS_AUTHORIZATION_RES_FAILED;
+    }
+    as->child = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ERR,
+                                         p,
+                                         NULL,
+                                         NULL,
+                                         as->ctx->auth_command,
+                                         as->ctx->auth_command,
+                                         as->email,
+                                         NULL);
+    if (NULL == as->child)
+    {
+      GNUNET_DISK_pipe_close (p);
+      mres = TALER_MHD_reply_with_error (connection,
+                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                         
TALER_EC_ANASTASIS_EMAIL_HELPER_EXEC_FAILED,
+                                         "exec");
+      if (MHD_YES != mres)
+        return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
+      return ANASTASIS_AUTHORIZATION_RES_FAILED;
+    }
+    pipe_stdin = GNUNET_DISK_pipe_detach_end (p,
+                                              GNUNET_DISK_PIPE_END_WRITE);
+    GNUNET_assert (NULL != pipe_stdin);
+    GNUNET_DISK_pipe_close (p);
+    {
+      char *tpk;
+
+      tpk = GNUNET_STRINGS_data_to_string_alloc (
+        &as->truth_uuid,
+        sizeof (as->truth_uuid));
+      GNUNET_asprintf (&as->msg,
+                       "Subject: Anastasis recovery code: #%llu\n\nThis is for 
challenge %s.\n",
+                       (unsigned long long) as->code,
+                       tpk);
+      GNUNET_free (tpk);
+    }
+
+    {
+      const char *off = as->msg;
+      size_t left = strlen (off);
+
+      while (0 != left)
+      {
+        ssize_t ret;
+
+        if (0 == left)
+          break;
+        ret = GNUNET_DISK_file_write (pipe_stdin,
+                                      off,
+                                      left);
+        if (ret <= 0)
+        {
+          mres = TALER_MHD_reply_with_error (connection,
+                                             MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                             
TALER_EC_ANASTASIS_EMAIL_HELPER_EXEC_FAILED,
+                                             "write");
+          if (MHD_YES != mres)
+            return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
+          return ANASTASIS_AUTHORIZATION_RES_FAILED;
+        }
+        as->msg_off += ret;
+        off += ret;
+        left -= ret;
+      }
+      GNUNET_DISK_file_close (pipe_stdin);
+    }
+    as->cwh = ANASTASIS_wait_child (as->child,
+                                    &email_done_cb,
+                                    as);
+    as->connection = connection;
+    MHD_suspend_connection (connection);
+    return ANASTASIS_AUTHORIZATION_RES_SUSPENDED;
+  }
+  if (NULL != as->cwh)
+  {
+    /* Spurious call, why are we here? */
+    GNUNET_break (0);
+    MHD_suspend_connection (connection);
+    return ANASTASIS_AUTHORIZATION_RES_SUSPENDED;
+  }
+  if ( (GNUNET_OS_PROCESS_EXITED != as->pst) ||
+       (0 != as->exit_code) )
+  {
+    char es[32];
+
+    GNUNET_snprintf (es,
+                     sizeof (es),
+                     "%u/%d",
+                     (unsigned int) as->exit_code,
+                     as->pst);
+    mres = TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                       
TALER_EC_ANASTASIS_EMAIL_HELPER_COMMAND_FAILED,
+                                       es);
     if (MHD_YES != mres)
       return ANASTASIS_AUTHORIZATION_RES_FAILED_REPLY_FAILED;
     return ANASTASIS_AUTHORIZATION_RES_FAILED;
-  case 0:
-    dup2 (p[0],0);
-    close (p[1]);
-    execlp (as->auth_command, subject, as->email, NULL);
-    close (p[0]);
-    char buff[21];
-    sprintf (buff, "%lu", as->code);
-    ret = write (p[1], buff, strlen (buff));
-    close (p[1]);
-
-    break;
-  default:
-    /*FIXME */
-    break;
   }
+
+  /* Build HTTP response */
+  {
+    struct MHD_Response *resp;
+    size_t reply_len;
+    char *reply;
+    const char *at;
+    size_t len;
+
+    /* FIXME: i18n based on language preferences of the client */
+    /* FIXME: Reply in JSON if requested by client */
+    at = strchr (as->email, '@');
+    if (NULL == at)
+      len = 0;
+    else
+      len = at - as->email;
+    reply_len = GNUNET_asprintf (&reply,
+                                 "Recovery TAN send to email %.*s@DOMAIN",
+                                 (unsigned int) len,
+                                 as->email);
+    resp = MHD_create_response_from_buffer (reply_len,
+                                            reply,
+                                            MHD_RESPMEM_MUST_COPY);
+    GNUNET_free (reply);
+    TALER_MHD_add_global_headers (resp);
+    mres = MHD_queue_response (connection,
+                               MHD_HTTP_FORBIDDEN,
+                               resp);
+    MHD_destroy_response (resp);
+  }
+
+  if (MHD_YES != mres)
+    return ANASTASIS_AUTHORIZATION_RES_SUCCESS_REPLY_FAILED;
   return ANASTASIS_AUTHORIZATION_RES_SUCCESS;
 }
 
@@ -213,6 +403,20 @@ email_process (struct ANASTASIS_AUTHORIZATION_State *as,
 static void
 email_cleanup (struct ANASTASIS_AUTHORIZATION_State *as)
 {
+  if (NULL != as->cwh)
+  {
+    ANASTASIS_wait_child_cancel (as->cwh);
+    as->cwh = NULL;
+  }
+  if (NULL != as->child)
+  {
+    (void) GNUNET_OS_process_kill (as->child,
+                                   SIGKILL);
+    GNUNET_break (GNUNET_OK ==
+                  GNUNET_OS_process_wait (as->child));
+    as->child = NULL;
+  }
+  GNUNET_free (as->msg);
   GNUNET_free (as->email);
   GNUNET_free (as);
 }
@@ -229,7 +433,29 @@ libanastasis_plugin_authorization_email_init (void *cls)
 {
   struct ANASTASIS_AuthorizationPlugin *plugin;
   struct GNUNET_CONFIGURATION_Handle *cfg = cls;
+  struct Email_Context *ctx;
+
+  ctx = GNUNET_new (struct Email_Context);
+  {
+    int regex_result;
+    const char *regexp = "[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}";
+
+    regex_result = regcomp (&ctx->regex,
+                            regexp,
+                            REG_EXTENDED);
+    if (0 < regex_result)
+    {
+      GNUNET_break (0);
+      GNUNET_free (ctx);
+      return NULL;
+    }
+  }
+
   plugin = GNUNET_new (struct ANASTASIS_AuthorizationPlugin);
+  plugin->code_validity_period = GNUNET_TIME_UNIT_DAYS;
+  plugin->code_rotation_period = GNUNET_TIME_UNIT_HOURS;
+  plugin->code_retransmission_frequency = GNUNET_TIME_UNIT_MINUTES;
+  plugin->cls = ctx;
   plugin->validate = &email_validate;
   plugin->start = &email_start;
   plugin->process = &email_process;
@@ -239,11 +465,13 @@ libanastasis_plugin_authorization_email_init (void *cls)
       GNUNET_CONFIGURATION_get_value_string (cfg,
                                              "authorization-email",
                                              "COMMAND",
-                                             &plugin->auth_command))
+                                             &ctx->auth_command))
   {
     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
                                "authorization-email",
                                "COMMAND");
+    regfree (&ctx->regex);
+    GNUNET_free (ctx);
     GNUNET_free (plugin);
     return NULL;
   }
@@ -261,6 +489,11 @@ void *
 libanastasis_plugin_authorization_email_done (void *cls)
 {
   struct ANASTASIS_AuthorizationPlugin *plugin = cls;
+  struct Email_Context *ctx = plugin->cls;
+
+  GNUNET_free (ctx->auth_command);
+  regfree (&ctx->regex);
+  GNUNET_free (ctx);
   GNUNET_free (plugin);
   return NULL;
 }
diff --git a/src/authorization/anastasis_authorization_plugin_sms.c 
b/src/authorization/anastasis_authorization_plugin_sms.c
index a2075fd..0dbdf89 100644
--- a/src/authorization/anastasis_authorization_plugin_sms.c
+++ b/src/authorization/anastasis_authorization_plugin_sms.c
@@ -26,7 +26,7 @@
 
 
 /**
- * Saves the State of a authorization process
+ * Saves the State of a authorization plugin.
  */
 struct SMS_Context
 {
@@ -53,7 +53,7 @@ struct ANASTASIS_AUTHORIZATION_State
   /**
    * Public key of the challenge which is authorised
    */
-  struct ANASTASIS_CRYPTO_TruthUUIDP truth_public_key;
+  struct ANASTASIS_CRYPTO_TruthUUIDP truth_uuid;
 
   /**
    * Code which is sent to the user (here sent via SMS)
@@ -175,7 +175,7 @@ sms_validate (void *cls,
  * @param cls closure with a `struct SMS_Context`
  * @param trigger function to call when we made progress
  * @param trigger_cls closure for @a trigger
- * @param truth_public_key Identifier of the challenge, to be (if possible) 
included in the
+ * @param truth_uuid Identifier of the challenge, to be (if possible) included 
in the
  *             interaction with the user
  * @param code secret code that the user has to provide back to satisfy the 
challenge in
  *             the main anastasis protocol
@@ -186,7 +186,7 @@ static struct ANASTASIS_AUTHORIZATION_State *
 sms_start (void *cls,
            GNUNET_SCHEDULER_TaskCallback trigger,
            void *trigger_cls,
-           const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_public_key,
+           const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
            uint64_t code,
            const void *data,
            size_t data_length)
@@ -198,7 +198,7 @@ sms_start (void *cls,
   as->trigger = trigger;
   as->trigger_cls = trigger_cls;
   as->ctx = ctx;
-  as->truth_public_key = *truth_public_key;
+  as->truth_uuid = *truth_uuid;
   as->code = code;
   as->phone_number = GNUNET_strndup (data,
                                      data_length);
@@ -287,8 +287,8 @@ sms_process (struct ANASTASIS_AUTHORIZATION_State *as,
       char *tpk;
 
       tpk = GNUNET_STRINGS_data_to_string_alloc (
-        &as->truth_public_key,
-        sizeof (as->truth_public_key));
+        &as->truth_uuid,
+        sizeof (as->truth_uuid));
       GNUNET_asprintf (&as->msg,
                        "#%llu\nAnastasis\n%s",
                        (unsigned long long) as->code,
@@ -467,6 +467,7 @@ libanastasis_plugin_authorization_sms_init (void *cls)
     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
                                "authorization-sms",
                                "SMSAUTH_COMMAND");
+    regfree (&ctx->regex);
     GNUNET_free (ctx);
     GNUNET_free (plugin);
     return NULL;
diff --git a/src/include/anastasis_redux.h b/src/include/anastasis_redux.h
index c43cb84..c8241da 100644
--- a/src/include/anastasis_redux.h
+++ b/src/include/anastasis_redux.h
@@ -118,6 +118,7 @@ ANASTASIS_generic_state_to_string (enum 
ANASTASIS_GenericState gs);
 enum ANASTASIS_BackupState
 ANASTASIS_backup_state_from_string (const char *state_string);
 
+
 /**
  * Returns the string value of a state.
  *
@@ -137,6 +138,7 @@ ANASTASIS_backup_state_to_string (enum 
ANASTASIS_BackupState bs);
 enum ANASTASIS_RecoveryState
 ANASTASIS_recovery_state_from_string (const char *state_string);
 
+
 /**
  * Returns the string value of a state.
  *
@@ -181,7 +183,6 @@ ANASTASIS_recovery_start (const struct 
GNUNET_CONFIGURATION_Handle *cfg);
  * @param cls closure
  * @param error error code, #TALER_EC_NONE if @a new_bs is the new successful 
state
  * @param new_state the new state of the operation (client should 
json_incref() to keep an alias)
- * @param error error code
  */
 typedef void
 (*ANASTASIS_ActionCallback)(
@@ -196,6 +197,11 @@ typedef void
 struct ANASTASIS_ReduxAction;
 
 
+/**
+ * Cancel ongoing redux action.
+ *
+ * @param ra action to cancel
+ */
 void
 ANASTASIS_redux_action_cancel (struct ANASTASIS_ReduxAction *ra);
 

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]