diff --git a/includes/form.inc b/includes/form.inc
index ee5d194c65e7923ab1c72ce65e6f14df91e72d9e..44954953d48ade4a425d643f90002a9359a168e6 100644
--- a/includes/form.inc
+++ b/includes/form.inc
@@ -39,7 +39,9 @@
 /**
  * Retrieves a form from a builder function, passes it on for
  * processing, and renders the form or redirects to its destination
- * as appropriate.
+ * as appropriate. In multi-step form scenerios, it handles properly
+ * processing the values using the previous step's form definition,
+ * then rendering the requested step for display.
  *
  * @param $form_id
  *   The unique string identifying the desired form. If a function
@@ -54,12 +56,61 @@
  *   The rendered form.
  */
 function drupal_get_form($form_id) {
-  $args = func_get_args();
-  $form = call_user_func_array('drupal_retrieve_form', $args);
-  drupal_process_form($form_id, $form);
-  return drupal_render_form($form_id, $form);
+  // In multi-step form scenerios, the incoming $_POST values are not
+  // necessarily intended for the current form. We need to build
+  // a copy of the previously built form for validation and processing,
+  // then go on to the one that was requested if everything works.
+
+  $form_build_id = md5(mt_rand());
+  if (isset($_POST['form_build_id']) && isset($_SESSION['form'][$_POST['form_build_id']])) {
+    // There's a previously stored multi-step form. We should handle
+    // IT first.
+    $stored = TRUE;
+    $args = $_SESSION['form'][$_POST['form_build_id']];
+    $form = call_user_func_array('drupal_retrieve_form', $args);
+  }
+  else {
+    // We're coming in fresh; build things as they would be. If the
+    // form's #multistep flag is set, store the build parameters so
+    // the same form can be reconstituted for validation.
+    $args = func_get_args();
+    $form = call_user_func_array('drupal_retrieve_form', $args);
+    if (isset($form['#multistep']) && $form['#multistep']) {
+      $_SESSION['form'][$form_build_id] = $args;
+      $form['#build_id'] = $form_build_id;
+    }
+    $stored = FALSE;
+  }
+
+  // Process the form, submit it, and store any errors if necessary.
+  drupal_process_form($args[0], $form);
+
+  if ($stored && !form_get_errors()) {
+    // If it's a stored form and there were no errors, we processed the
+    // stored form successfully. Now we need to build the form that was
+    // actually requested. We always pass in the current $_POST values
+    // to the builder function, as values from one stage of a multistep
+    // form can determine how subsequent steps are displayed.
+    $args = func_get_args();
+    $args[] = $_POST['edit'];
+    $form = call_user_func_array('drupal_retrieve_form', $args);
+    unset($_SESSION['form'][$_POST['form_build_id']]);
+    if (isset($form['#multistep']) && $form['#multistep']) {
+      $_SESSION['form'][$form_build_id] = $args;
+      $form['#build_id'] = $form_build_id;
+    }
+    // If we're in this part of the code, $_POST['edit'] always contains
+    // values from the previously submitted form. Unset it to avoid
+    // any accidental submission of doubled data, then process the form
+    // to prep it for rendering.
+    unset($_POST['edit']);
+    drupal_process_form($args[0], $form);
+  }
+
+  return drupal_render_form($args[0], $form);
 }
 
+
 /**
  * Retrieves the structured array that defines a given form.
  *
@@ -158,6 +209,17 @@ function drupal_prepare_form($form_id, &$form) {
     $form['#programmed'] = TRUE;
   }
 
+  // In multi-step form scenerios, this id is used to identify
+  // a unique instance of a particular form for retrieval.
+  if (isset($form['#build_id'])) {
+    $form['form_build_id'] = array(
+      '#type' => 'hidden',
+      '#value' => $form['#build_id'],
+      '#id' => $form['#build_id'],
+      '#name' => 'form_build_id',
+    );
+  }
+
   // If $base is set, it is used in place of $form_id when constructing validation,
   // submission, and theming functions. Useful for mapping many similar or duplicate
   // forms with different $form_ids to the same processing functions.