grpc_auth_context *grpc_call_auth_context(grpc_call *call) {
  void *sec_ctx = grpc_call_context_get(call, GRPC_CONTEXT_SECURITY);
  if (sec_ctx == NULL) return NULL;
  return grpc_call_is_client(call)
             ? GRPC_AUTH_CONTEXT_REF(
                   ((grpc_client_security_context *)sec_ctx)->auth_context,
                   "grpc_call_auth_context client")
             : GRPC_AUTH_CONTEXT_REF(
                   ((grpc_server_security_context *)sec_ctx)->auth_context,
                   "grpc_call_auth_context server");
}
Beispiel #2
0
static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *user_data,
                            grpc_security_status status,
                            grpc_auth_context *auth_context) {
    grpc_security_handshake *h = user_data;
    tsi_frame_protector *protector;
    tsi_result result;
    if (status != GRPC_SECURITY_OK) {
        security_handshake_done(
            exec_ctx, h,
            grpc_error_set_int(GRPC_ERROR_CREATE("Error checking peer."),
                               GRPC_ERROR_INT_SECURITY_STATUS, status));
        return;
    }
    h->auth_context = GRPC_AUTH_CONTEXT_REF(auth_context, "handshake");
    result =
        tsi_handshaker_create_frame_protector(h->handshaker, NULL, &protector);
    if (result != TSI_OK) {
        security_handshake_done(
            exec_ctx, h,
            grpc_set_tsi_error_result(
                GRPC_ERROR_CREATE("Frame protector creation failed"), result));
        return;
    }
    h->secure_endpoint =
        grpc_secure_endpoint_create(protector, h->wrapped_endpoint,
                                    h->left_overs.slices, h->left_overs.count);
    h->left_overs.count = 0;
    h->left_overs.length = 0;
    security_handshake_done(exec_ctx, h, GRPC_ERROR_NONE);
    return;
}
/* Constructor for channel_data */
static void init_channel_elem(grpc_exec_ctx *exec_ctx,
                              grpc_channel_element *elem,
                              grpc_channel_element_args *args) {
  grpc_security_connector *sc =
      grpc_find_security_connector_in_args(args->channel_args);
  grpc_auth_context *auth_context =
      grpc_find_auth_context_in_args(args->channel_args);

  /* grab pointers to our data from the channel element */
  channel_data *chand = elem->channel_data;

  /* The first and the last filters tend to be implemented differently to
     handle the case that there's no 'next' filter to call on the up or down
     path */
  GPR_ASSERT(!args->is_last);
  GPR_ASSERT(sc != NULL);
  GPR_ASSERT(auth_context != NULL);

  /* initialize members */
  chand->security_connector =
      (grpc_channel_security_connector *)GRPC_SECURITY_CONNECTOR_REF(
          sc, "client_auth_filter");
  chand->auth_context =
      GRPC_AUTH_CONTEXT_REF(auth_context, "client_auth_filter");
}
void build_auth_metadata_context(grpc_security_connector *sc,
                                 grpc_auth_context *auth_context,
                                 call_data *calld) {
  char *service = gpr_strdup(grpc_mdstr_as_c_string(calld->method));
  char *last_slash = strrchr(service, '/');
  char *method_name = NULL;
  char *service_url = NULL;
  reset_auth_metadata_context(&calld->auth_md_context);
  if (last_slash == NULL) {
    gpr_log(GPR_ERROR, "No '/' found in fully qualified method name");
    service[0] = '\0';
  } else if (last_slash == service) {
    /* No service part in fully qualified method name: will just be "/". */
    service[1] = '\0';
  } else {
    *last_slash = '\0';
    method_name = gpr_strdup(last_slash + 1);
  }
  if (method_name == NULL) method_name = gpr_strdup("");
  gpr_asprintf(&service_url, "%s://%s%s",
               sc->url_scheme == NULL ? "" : sc->url_scheme,
               grpc_mdstr_as_c_string(calld->host), service);
  calld->auth_md_context.service_url = service_url;
  calld->auth_md_context.method_name = method_name;
  calld->auth_md_context.channel_auth_context =
      GRPC_AUTH_CONTEXT_REF(auth_context, "grpc_auth_metadata_context");
  gpr_free(service);
}
Beispiel #5
0
/* Constructor for channel_data */
static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx,
                                     grpc_channel_element *elem,
                                     grpc_channel_element_args *args) {
  grpc_security_connector *sc =
      grpc_security_connector_find_in_args(args->channel_args);
  if (sc == NULL) {
    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
        "Security connector missing from client auth filter args");
  }
  grpc_auth_context *auth_context =
      grpc_find_auth_context_in_args(args->channel_args);
  if (auth_context == NULL) {
    return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
        "Auth context missing from client auth filter args");
  }

  /* grab pointers to our data from the channel element */
  channel_data *chand = elem->channel_data;

  /* The first and the last filters tend to be implemented differently to
     handle the case that there's no 'next' filter to call on the up or down
     path */
  GPR_ASSERT(!args->is_last);

  /* initialize members */
  chand->security_connector =
      (grpc_channel_security_connector *)GRPC_SECURITY_CONNECTOR_REF(
          sc, "client_auth_filter");
  chand->auth_context =
      GRPC_AUTH_CONTEXT_REF(auth_context, "client_auth_filter");
  return GRPC_ERROR_NONE;
}
Beispiel #6
0
grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained) {
  grpc_auth_context *ctx = gpr_zalloc(sizeof(grpc_auth_context));
  gpr_ref_init(&ctx->refcount, 1);
  if (chained != NULL) {
    ctx->chained = GRPC_AUTH_CONTEXT_REF(chained, "chained");
    ctx->peer_identity_property_name =
        ctx->chained->peer_identity_property_name;
  }
  return ctx;
}
Beispiel #7
0
/* Called either:
     - in response to an API call (or similar) from above, to send something
     - a network event (or similar) from below, to receive something
   op contains type and call direction information, in addition to the data
   that is being sent or received. */
static void auth_start_transport_op(grpc_exec_ctx *exec_ctx,
                                    grpc_call_element *elem,
                                    grpc_transport_stream_op *op) {
  /* grab pointers to our data from the call element */
  call_data *calld = elem->call_data;
  channel_data *chand = elem->channel_data;
  grpc_linked_mdelem *l;
  grpc_client_security_context *sec_ctx = NULL;

  if (calld->security_context_set == 0 &&
      op->cancel_with_status == GRPC_STATUS_OK) {
    calld->security_context_set = 1;
    GPR_ASSERT(op->context);
    if (op->context[GRPC_CONTEXT_SECURITY].value == NULL) {
      op->context[GRPC_CONTEXT_SECURITY].value =
          grpc_client_security_context_create();
      op->context[GRPC_CONTEXT_SECURITY].destroy =
          grpc_client_security_context_destroy;
    }
    sec_ctx = op->context[GRPC_CONTEXT_SECURITY].value;
    GRPC_AUTH_CONTEXT_UNREF(sec_ctx->auth_context, "client auth filter");
    sec_ctx->auth_context =
        GRPC_AUTH_CONTEXT_REF(chand->auth_context, "client_auth_filter");
  }

  if (op->send_initial_metadata != NULL) {
    for (l = op->send_initial_metadata->list.head; l != NULL; l = l->next) {
      grpc_mdelem *md = l->md;
      /* Pointer comparison is OK for md_elems created from the same context.
       */
      if (md->key == GRPC_MDSTR_AUTHORITY) {
        if (calld->host != NULL) GRPC_MDSTR_UNREF(calld->host);
        calld->host = GRPC_MDSTR_REF(md->value);
      } else if (md->key == GRPC_MDSTR_PATH) {
        if (calld->method != NULL) GRPC_MDSTR_UNREF(calld->method);
        calld->method = GRPC_MDSTR_REF(md->value);
      }
    }
    if (calld->host != NULL) {
      const char *call_host = grpc_mdstr_as_c_string(calld->host);
      calld->op = *op; /* Copy op (originates from the caller's stack). */
      grpc_channel_security_connector_check_call_host(
          exec_ctx, chand->security_connector, call_host, chand->auth_context,
          on_host_checked, elem);
      return; /* early exit */
    }
  }

  /* pass control down the stack */
  grpc_call_next_op(exec_ctx, elem, op);
}
Beispiel #8
0
/* Constructor for channel_data */
static void init_channel_elem(grpc_exec_ctx *exec_ctx,
                              grpc_channel_element *elem,
                              grpc_channel_element_args *args) {
  grpc_auth_context *auth_context =
      grpc_find_auth_context_in_args(args->channel_args);
  grpc_server_credentials *creds =
      grpc_find_server_credentials_in_args(args->channel_args);
  /* grab pointers to our data from the channel element */
  channel_data *chand = elem->channel_data;

  GPR_ASSERT(!args->is_last);
  GPR_ASSERT(auth_context != NULL);
  GPR_ASSERT(creds != NULL);

  /* initialize members */
  chand->auth_context =
      GRPC_AUTH_CONTEXT_REF(auth_context, "server_auth_filter");
  chand->creds = grpc_server_credentials_ref(creds);
}
Beispiel #9
0
static void *auth_context_pointer_arg_copy(void *p) {
  return GRPC_AUTH_CONTEXT_REF(p, "auth_context_pointer_arg");
}
Beispiel #10
0
/* Called either:
     - in response to an API call (or similar) from above, to send something
     - a network event (or similar) from below, to receive something
   op contains type and call direction information, in addition to the data
   that is being sent or received. */
static void auth_start_transport_op(grpc_exec_ctx *exec_ctx,
                                    grpc_call_element *elem,
                                    grpc_transport_stream_op *op) {
  /* grab pointers to our data from the call element */
  call_data *calld = elem->call_data;
  channel_data *chand = elem->channel_data;
  grpc_linked_mdelem *l;
  size_t i;
  grpc_client_security_context *sec_ctx = NULL;

  if (calld->security_context_set == 0 &&
      op->cancel_with_status == GRPC_STATUS_OK) {
    calld->security_context_set = 1;
    GPR_ASSERT(op->context);
    if (op->context[GRPC_CONTEXT_SECURITY].value == NULL) {
      op->context[GRPC_CONTEXT_SECURITY].value =
          grpc_client_security_context_create();
      op->context[GRPC_CONTEXT_SECURITY].destroy =
          grpc_client_security_context_destroy;
    }
    sec_ctx = op->context[GRPC_CONTEXT_SECURITY].value;
    GRPC_AUTH_CONTEXT_UNREF(sec_ctx->auth_context, "client auth filter");
    sec_ctx->auth_context = GRPC_AUTH_CONTEXT_REF(
        chand->security_connector->base.auth_context, "client_auth_filter");
  }

  if (op->bind_pollset != NULL) {
    calld->pollset = op->bind_pollset;
  }

  if (op->send_ops != NULL && !calld->sent_initial_metadata) {
    size_t nops = op->send_ops->nops;
    grpc_stream_op *ops = op->send_ops->ops;
    for (i = 0; i < nops; i++) {
      grpc_stream_op *sop = &ops[i];
      if (sop->type != GRPC_OP_METADATA) continue;
      calld->op_md_idx = i;
      calld->sent_initial_metadata = 1;
      for (l = sop->data.metadata.list.head; l != NULL; l = l->next) {
        grpc_mdelem *md = l->md;
        /* Pointer comparison is OK for md_elems created from the same context.
         */
        if (md->key == chand->authority_string) {
          if (calld->host != NULL) GRPC_MDSTR_UNREF(calld->host);
          calld->host = GRPC_MDSTR_REF(md->value);
        } else if (md->key == chand->path_string) {
          if (calld->method != NULL) GRPC_MDSTR_UNREF(calld->method);
          calld->method = GRPC_MDSTR_REF(md->value);
        }
      }
      if (calld->host != NULL) {
        grpc_security_status status;
        const char *call_host = grpc_mdstr_as_c_string(calld->host);
        calld->op = *op; /* Copy op (originates from the caller's stack). */
        status = grpc_channel_security_connector_check_call_host(
            exec_ctx, chand->security_connector, call_host, on_host_checked,
            elem);
        if (status != GRPC_SECURITY_OK) {
          if (status == GRPC_SECURITY_ERROR) {
            char *error_msg;
            gpr_asprintf(&error_msg,
                         "Invalid host %s set in :authority metadata.",
                         call_host);
            bubble_up_error(exec_ctx, elem, GRPC_STATUS_INVALID_ARGUMENT,
                            error_msg);
            gpr_free(error_msg);
          }
          return; /* early exit */
        }
      }
      send_security_metadata(exec_ctx, elem, op);
      return; /* early exit */
    }
  }

  /* pass control down the stack */
  grpc_call_next_op(exec_ctx, elem, op);
}
Beispiel #11
0
/* Called either:
     - in response to an API call (or similar) from above, to send something
     - a network event (or similar) from below, to receive something
   op contains type and call direction information, in addition to the data
   that is being sent or received. */
static void auth_start_transport_op(grpc_exec_ctx *exec_ctx,
                                    grpc_call_element *elem,
                                    grpc_transport_stream_op *op) {
  GPR_TIMER_BEGIN("auth_start_transport_op", 0);

  /* grab pointers to our data from the call element */
  call_data *calld = elem->call_data;
  channel_data *chand = elem->channel_data;
  grpc_linked_mdelem *l;
  grpc_client_security_context *sec_ctx = NULL;

  if (calld->security_context_set == 0 && op->cancel_error == GRPC_ERROR_NONE) {
    calld->security_context_set = 1;
    GPR_ASSERT(op->context);
    if (op->context[GRPC_CONTEXT_SECURITY].value == NULL) {
      op->context[GRPC_CONTEXT_SECURITY].value =
          grpc_client_security_context_create();
      op->context[GRPC_CONTEXT_SECURITY].destroy =
          grpc_client_security_context_destroy;
    }
    sec_ctx = op->context[GRPC_CONTEXT_SECURITY].value;
    GRPC_AUTH_CONTEXT_UNREF(sec_ctx->auth_context, "client auth filter");
    sec_ctx->auth_context =
        GRPC_AUTH_CONTEXT_REF(chand->auth_context, "client_auth_filter");
  }

  if (op->send_initial_metadata != NULL) {
    for (l = op->send_initial_metadata->list.head; l != NULL; l = l->next) {
      grpc_mdelem md = l->md;
      /* Pointer comparison is OK for md_elems created from the same context.
       */
      if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_AUTHORITY)) {
        if (calld->have_host) {
          grpc_slice_unref_internal(exec_ctx, calld->host);
        }
        calld->host = grpc_slice_ref_internal(GRPC_MDVALUE(md));
        calld->have_host = true;
      } else if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_PATH)) {
        if (calld->have_method) {
          grpc_slice_unref_internal(exec_ctx, calld->method);
        }
        calld->method = grpc_slice_ref_internal(GRPC_MDVALUE(md));
        calld->have_method = true;
      }
    }
    if (calld->have_host) {
      char *call_host = grpc_slice_to_c_string(calld->host);
      calld->op = *op; /* Copy op (originates from the caller's stack). */
      grpc_channel_security_connector_check_call_host(
          exec_ctx, chand->security_connector, call_host, chand->auth_context,
          on_host_checked, elem);
      gpr_free(call_host);
      GPR_TIMER_END("auth_start_transport_op", 0);
      return; /* early exit */
    }
  }

  /* pass control down the stack */
  grpc_call_next_op(exec_ctx, elem, op);
  GPR_TIMER_END("auth_start_transport_op", 0);
}
Beispiel #12
0
static void auth_start_transport_stream_op_batch(
    grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
    grpc_transport_stream_op_batch *batch) {
  GPR_TIMER_BEGIN("auth_start_transport_stream_op_batch", 0);

  /* grab pointers to our data from the call element */
  call_data *calld = elem->call_data;
  channel_data *chand = elem->channel_data;

  if (batch->cancel_stream) {
    while (true) {
      // Decode the original cancellation state.
      gpr_atm original_state = gpr_atm_acq_load(&calld->cancellation_state);
      grpc_error *cancel_error = GRPC_ERROR_NONE;
      grpc_closure *func = NULL;
      decode_cancel_state(original_state, &func, &cancel_error);
      // If we had already set a cancellation error, there's nothing
      // more to do.
      if (cancel_error != GRPC_ERROR_NONE) break;
      // If there's a cancel func, call it.
      // Note that even if the cancel func has been changed by some
      // other thread between when we decoded it and now, it will just
      // be a no-op.
      cancel_error = GRPC_ERROR_REF(batch->payload->cancel_stream.cancel_error);
      if (func != NULL) {
        GRPC_CLOSURE_SCHED(exec_ctx, func, GRPC_ERROR_REF(cancel_error));
      }
      // Encode the new error into cancellation state.
      if (gpr_atm_full_cas(&calld->cancellation_state, original_state,
                           encode_cancel_state_error(cancel_error))) {
        break;  // Success.
      }
      // The cas failed, so try again.
    }
  } else {
    /* double checked lock over security context to ensure it's set once */
    if (gpr_atm_acq_load(&calld->security_context_set) == 0) {
      gpr_mu_lock(&calld->security_context_mu);
      if (gpr_atm_acq_load(&calld->security_context_set) == 0) {
        GPR_ASSERT(batch->payload->context != NULL);
        if (batch->payload->context[GRPC_CONTEXT_SECURITY].value == NULL) {
          batch->payload->context[GRPC_CONTEXT_SECURITY].value =
              grpc_client_security_context_create();
          batch->payload->context[GRPC_CONTEXT_SECURITY].destroy =
              grpc_client_security_context_destroy;
        }
        grpc_client_security_context *sec_ctx =
            batch->payload->context[GRPC_CONTEXT_SECURITY].value;
        GRPC_AUTH_CONTEXT_UNREF(sec_ctx->auth_context, "client auth filter");
        sec_ctx->auth_context =
            GRPC_AUTH_CONTEXT_REF(chand->auth_context, "client_auth_filter");
        gpr_atm_rel_store(&calld->security_context_set, 1);
      }
      gpr_mu_unlock(&calld->security_context_mu);
    }
  }

  if (batch->send_initial_metadata) {
    for (grpc_linked_mdelem *l = batch->payload->send_initial_metadata
                                     .send_initial_metadata->list.head;
         l != NULL; l = l->next) {
      grpc_mdelem md = l->md;
      /* Pointer comparison is OK for md_elems created from the same context.
       */
      if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_AUTHORITY)) {
        if (calld->have_host) {
          grpc_slice_unref_internal(exec_ctx, calld->host);
        }
        calld->host = grpc_slice_ref_internal(GRPC_MDVALUE(md));
        calld->have_host = true;
      } else if (grpc_slice_eq(GRPC_MDKEY(md), GRPC_MDSTR_PATH)) {
        if (calld->have_method) {
          grpc_slice_unref_internal(exec_ctx, calld->method);
        }
        calld->method = grpc_slice_ref_internal(GRPC_MDVALUE(md));
        calld->have_method = true;
      }
    }
    if (calld->have_host) {
      grpc_error *cancel_error = set_cancel_func(elem, cancel_check_call_host);
      if (cancel_error != GRPC_ERROR_NONE) {
        grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, batch,
                                                           cancel_error);
      } else {
        char *call_host = grpc_slice_to_c_string(calld->host);
        batch->handler_private.extra_arg = elem;
        grpc_error *error = GRPC_ERROR_NONE;
        if (grpc_channel_security_connector_check_call_host(
                exec_ctx, chand->security_connector, call_host,
                chand->auth_context,
                GRPC_CLOSURE_INIT(&calld->closure, on_host_checked, batch,
                                  grpc_schedule_on_exec_ctx),
                &error)) {
          // Synchronous return; invoke on_host_checked() directly.
          on_host_checked(exec_ctx, batch, error);
          GRPC_ERROR_UNREF(error);
        }
        gpr_free(call_host);
      }
      GPR_TIMER_END("auth_start_transport_stream_op_batch", 0);
      return; /* early exit */
    }
  }

  /* pass control down the stack */
  grpc_call_next_op(exec_ctx, elem, batch);
  GPR_TIMER_END("auth_start_transport_stream_op_batch", 0);
}