Example #1
0
int
main(int argc, char *argv[])
{
    OM_uint32 minor, major;
    gss_key_value_set_desc store;
    gss_buffer_desc buf;
    gss_name_t service = GSS_C_NO_NAME;
    gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
    int i, e;

    if (argc < 2 || ((argc - 3) % 2)) {
        usage(argv[0]);
        exit(1);
    }

    store.count = (argc - 3) / 2;
    store.elements = calloc(store.count,
                            sizeof(struct gss_key_value_element_struct));
    if (!store.elements) {
        fprintf(stderr, "OOM\n");
        exit(1);
    }

    if (argc > 2) {
        if (strcmp(argv[2], "--cred_store") != 0) {
            usage(argv[0]);
            exit(1);
        }

        for (i = 3, e = 0; i < argc; i += 2, e++) {
            store.elements[e].key = argv[i];
            store.elements[e].value = argv[i + 1];
            continue;
        }
    }

    /* First acquire default creds and try to store them in the cred store. */

    major = gss_acquire_cred(&minor, GSS_C_NO_NAME, 0, GSS_C_NO_OID_SET,
                             GSS_C_INITIATE, &cred, NULL, NULL);
    if (major) {
        print_status("gss_acquire_cred(default user creds) failed",
                     major, minor);
        goto out;
    }

    major = gss_store_cred_into(&minor, cred, GSS_C_INITIATE,
                                GSS_C_NO_OID, 1, 0, &store, NULL, NULL);
    if (major) {
        print_status("gss_store_cred_in_store(default user creds) failed",
                     major, minor);
        goto out;
    }

    gss_release_cred(&minor, &cred);

    /* Then try to acquire creds from store. */

    buf.value = argv[1];
    buf.length = strlen(argv[1]);

    major = gss_import_name(&minor, &buf,
                            (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME,
                            &service);
    if (major) {
        print_status("gss_import_name(principal) failed", major, minor);
        goto out;
    }

    major = gss_acquire_cred_from(&minor, service,
                                  0, GSS_C_NO_OID_SET, GSS_C_BOTH,
                                  &store, &cred, NULL, NULL);
    if (major) {
        print_status("gss_acquire_cred_from_store(principal) failed",
                     major, minor);
        goto out;
    }

    fprintf(stdout, "Cred Store Success\n");

    major = 0;

out:
    gss_release_name(&minor, &service);
    gss_release_cred(&minor, &cred);
    free(store.elements);
    return major;
}
Example #2
0
OM_uint32
gss_inquire_context(OM_uint32 *minor_status,
    const gss_ctx_id_t context_handle,
    gss_name_t *src_name,
    gss_name_t *targ_name,
    OM_uint32 *lifetime_rec,
    gss_OID *mech_type,
    OM_uint32 *ctx_flags,
    int *locally_initiated,
    int *open)
{
	OM_uint32 major_status;
	struct _gss_context *ctx = (struct _gss_context *) context_handle;
	struct _gss_mech_switch *m = ctx->gc_mech;
	struct _gss_name *name;
	gss_name_t src_mn, targ_mn;

	if (locally_initiated)
		*locally_initiated = 0;
	if (open)
		*open = 0;
	if (lifetime_rec)
		*lifetime_rec = 0;

	if (src_name)
		*src_name = GSS_C_NO_NAME;
	if (targ_name)
		*targ_name = GSS_C_NO_NAME;
	if (mech_type)
		*mech_type = GSS_C_NO_OID;
	src_mn = targ_mn = GSS_C_NO_NAME;

	major_status = m->gm_inquire_context(minor_status,
	    ctx->gc_ctx,
	    src_name ? &src_mn : NULL,
	    targ_name ? &targ_mn : NULL,
	    lifetime_rec,
	    mech_type,
	    ctx_flags,
	    locally_initiated,
	    open);

	if (major_status != GSS_S_COMPLETE) {
		_gss_mg_error(m, major_status, *minor_status);
		return (major_status);
	}

	if (src_name) {
		name = _gss_make_name(m, src_mn);
		if (!name) {
			if (mech_type)
				*mech_type = GSS_C_NO_OID;
			m->gm_release_name(minor_status, &src_mn);
			*minor_status = 0;
			return (GSS_S_FAILURE);
		}
		*src_name = (gss_name_t) name;
	}

	if (targ_name) {
		name = _gss_make_name(m, targ_mn);
		if (!name) {
			if (mech_type)
				*mech_type = GSS_C_NO_OID;
			if (src_name)
				gss_release_name(minor_status, src_name);
			m->gm_release_name(minor_status, &src_mn);
			minor_status = 0;
			return (GSS_S_FAILURE);
		}
		*targ_name = (gss_name_t) name;
	}

	return (GSS_S_COMPLETE);
}
Example #3
0
CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
                                      struct connectdata *conn)
{
  struct SessionHandle *data = conn->data;
  curl_socket_t sock = conn->sock[sockindex];
  CURLcode code;
  ssize_t actualread;
  ssize_t written;
  int result;
  long timeout;
  OM_uint32 gss_major_status, gss_minor_status, gss_status;
  OM_uint32 gss_ret_flags;
  int gss_conf_state, gss_enc;
  gss_buffer_desc  service = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc  gss_send_token = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc  gss_recv_token = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc  gss_w_token = GSS_C_EMPTY_BUFFER;
  gss_buffer_desc* gss_token = GSS_C_NO_BUFFER;
  gss_name_t       server = GSS_C_NO_NAME;
  gss_name_t       gss_client_name = GSS_C_NO_NAME;
  u_short          us_length;
  char             *user=NULL;
  unsigned char socksreq[4]; /* room for gssapi exchange header only */
  char *serviceptr = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE];

  /* get timeout */
  timeout = Curl_timeleft(conn, NULL, TRUE);

  /*   GSSAPI request looks like
   * +----+------+-----+----------------+
   * |VER | MTYP | LEN |     TOKEN      |
   * +----+------+----------------------+
   * | 1  |  1   |  2  | up to 2^16 - 1 |
   * +----+------+-----+----------------+
   */

  /* prepare service name */
  if (strchr(serviceptr,'/')) {
    service.value = malloc(strlen(serviceptr));
    if(!service.value)
      return CURLE_OUT_OF_MEMORY;
    service.length = strlen(serviceptr);
    memcpy(service.value, serviceptr, service.length);

    gss_major_status = gss_import_name(&gss_minor_status, &service,
                                       (gss_OID) GSS_C_NULL_OID, &server);
  }
  else {
    service.value = malloc(strlen(serviceptr) +strlen(conn->proxy.name)+2);
    if(!service.value)
      return CURLE_OUT_OF_MEMORY;
    service.length = strlen(serviceptr) +strlen(conn->proxy.name)+1;
    snprintf(service.value, service.length+1, "%[email protected]%s",
             serviceptr, conn->proxy.name);

    gss_major_status = gss_import_name(&gss_minor_status, &service,
                                       gss_nt_service_name, &server);
  }

  gss_release_buffer(&gss_status, &service); /* clear allocated memory */

  if(check_gss_err(data,gss_major_status,
                   gss_minor_status,"gss_import_name()")) {
    failf(data, "Failed to create service name.");
    gss_release_name(&gss_status, &server);
    return CURLE_COULDNT_CONNECT;
  }

  /* As long as we need to keep sending some context info, and there's no  */
  /* errors, keep sending it...                                            */
  for(;;) {
    gss_major_status = gss_init_sec_context(&gss_minor_status,
                                            GSS_C_NO_CREDENTIAL,
                                            &gss_context, server,
                                            GSS_C_NULL_OID,
                                            GSS_C_MUTUAL_FLAG |
                                            GSS_C_REPLAY_FLAG,
                                            0,
                                            NULL,
                                            gss_token,
                                            NULL,
                                            &gss_send_token,
                                            &gss_ret_flags,
                                            NULL);

    if(gss_token != GSS_C_NO_BUFFER)
      gss_release_buffer(&gss_status, &gss_recv_token);
    if(check_gss_err(data,gss_major_status,
                     gss_minor_status,"gss_init_sec_context")) {
      gss_release_name(&gss_status, &server);
      gss_release_buffer(&gss_status, &gss_recv_token);
      gss_release_buffer(&gss_status, &gss_send_token);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      failf(data, "Failed to initial GSSAPI token.");
      return CURLE_COULDNT_CONNECT;
    }

    if(gss_send_token.length != 0) {
      socksreq[0] = 1;    /* gssapi subnegotiation version */
      socksreq[1] = 1;    /* authentication message type */
      us_length = htons((short)gss_send_token.length);
      memcpy(socksreq+2,&us_length,sizeof(short));

      code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
      if((code != CURLE_OK) || (4 != written)) {
        failf(data, "Failed to send GSSAPI authentication request.");
        gss_release_name(&gss_status, &server);
        gss_release_buffer(&gss_status, &gss_recv_token);
        gss_release_buffer(&gss_status, &gss_send_token);
        gss_delete_sec_context(&gss_status, &gss_context, NULL);
        return CURLE_COULDNT_CONNECT;
      }

      code = Curl_write_plain(conn, sock, (char *)gss_send_token.value,
                              gss_send_token.length, &written);

      if((code != CURLE_OK) || ((ssize_t)gss_send_token.length != written)) {
        failf(data, "Failed to send GSSAPI authentication token.");
        gss_release_name(&gss_status, &server);
        gss_release_buffer(&gss_status, &gss_recv_token);
        gss_release_buffer(&gss_status, &gss_send_token);
        gss_delete_sec_context(&gss_status, &gss_context, NULL);
        return CURLE_COULDNT_CONNECT;
      }

    }

    gss_release_buffer(&gss_status, &gss_send_token);
    gss_release_buffer(&gss_status, &gss_recv_token);
    if(gss_major_status != GSS_S_CONTINUE_NEEDED) break;

    /* analyse response */

    /*   GSSAPI response looks like
     * +----+------+-----+----------------+
     * |VER | MTYP | LEN |     TOKEN      |
     * +----+------+----------------------+
     * | 1  |  1   |  2  | up to 2^16 - 1 |
     * +----+------+-----+----------------+
     */

    result=Curl_blockread_all(conn, sock, (char *)socksreq, 4,
                              &actualread, timeout);
    if(result != CURLE_OK || actualread != 4) {
      failf(data, "Failed to receive GSSAPI authentication response.");
      gss_release_name(&gss_status, &server);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }

    /* ignore the first (VER) byte */
    if(socksreq[1] == 255) { /* status / message type */
      failf(data, "User was rejected by the SOCKS5 server (%d %d).",
            socksreq[0], socksreq[1]);
      gss_release_name(&gss_status, &server);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }

    if(socksreq[1] != 1) { /* status / messgae type */
      failf(data, "Invalid GSSAPI authentication response type (%d %d).",
            socksreq[0], socksreq[1]);
      gss_release_name(&gss_status, &server);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }

    memcpy(&us_length, socksreq+2, sizeof(short));
    us_length = ntohs(us_length);

    gss_recv_token.length=us_length;
    gss_recv_token.value=malloc(us_length);
    if(!gss_recv_token.value) {
      failf(data,
            "Could not allocate memory for GSSAPI authentication "
            "response token.");
      gss_release_name(&gss_status, &server);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_OUT_OF_MEMORY;
    }

    result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
                              gss_recv_token.length,
                              &actualread, timeout);

    if(result != CURLE_OK || actualread != us_length) {
      failf(data, "Failed to receive GSSAPI authentication token.");
      gss_release_name(&gss_status, &server);
      gss_release_buffer(&gss_status, &gss_recv_token);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }

    gss_token = &gss_recv_token;
  }

  gss_release_name(&gss_status, &server);

  /* Everything is good so far, user was authenticated! */
  gss_major_status = gss_inquire_context (&gss_minor_status, gss_context,
                                          &gss_client_name, NULL, NULL, NULL,
                                          NULL, NULL, NULL);
  if(check_gss_err(data,gss_major_status,
                   gss_minor_status,"gss_inquire_context")) {
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    gss_release_name(&gss_status, &gss_client_name);
    failf(data, "Failed to determine user name.");
    return CURLE_COULDNT_CONNECT;
  }
  gss_major_status = gss_display_name(&gss_minor_status, gss_client_name,
                                      &gss_send_token, NULL);
  if(check_gss_err(data,gss_major_status,
                   gss_minor_status,"gss_display_name")) {
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    gss_release_name(&gss_status, &gss_client_name);
    gss_release_buffer(&gss_status, &gss_send_token);
    failf(data, "Failed to determine user name.");
    return CURLE_COULDNT_CONNECT;
  }
  user=malloc(gss_send_token.length+1);
  if(!user) {
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    gss_release_name(&gss_status, &gss_client_name);
    gss_release_buffer(&gss_status, &gss_send_token);
    return CURLE_OUT_OF_MEMORY;
  }

  memcpy(user, gss_send_token.value, gss_send_token.length);
  user[gss_send_token.length] = '\0';
  gss_release_name(&gss_status, &gss_client_name);
  gss_release_buffer(&gss_status, &gss_send_token);
  infof(data, "SOCKS5 server authencticated user %s with gssapi.\n",user);
  free(user);
  user=NULL;

  /* Do encryption */
  socksreq[0] = 1;    /* gssapi subnegotiation version */
  socksreq[1] = 2;    /* encryption message type */

  gss_enc = 0; /* no data protection */
  /* do confidentiality protection if supported */
  if(gss_ret_flags & GSS_C_CONF_FLAG)
    gss_enc = 2;
  /* else do integrity protection */
  else if(gss_ret_flags & GSS_C_INTEG_FLAG)
    gss_enc = 1;

  infof(data, "SOCKS5 server supports gssapi %s data protection.\n",
        (gss_enc==0)?"no":((gss_enc==1)?"integrity":"confidentiality"));
  /* force for the moment to no data protection */
  gss_enc = 0;
  /*
   * Sending the encryption type in clear seems wrong. It should be
   * protected with gss_seal()/gss_wrap(). See RFC1961 extract below
   * The NEC reference implementations on which this is based is
   * therefore at fault
   *
   *  +------+------+------+.......................+
   *  + ver  | mtyp | len  |   token               |
   *  +------+------+------+.......................+
   *  + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets |
   *  +------+------+------+.......................+
   *
   *   Where:
   *
   *  - "ver" is the protocol version number, here 1 to represent the
   *    first version of the SOCKS/GSS-API protocol
   *
   *  - "mtyp" is the message type, here 2 to represent a protection
   *    -level negotiation message
   *
   *  - "len" is the length of the "token" field in octets
   *
   *  - "token" is the GSS-API encapsulated protection level
   *
   * The token is produced by encapsulating an octet containing the
   * required protection level using gss_seal()/gss_wrap() with conf_req
   * set to FALSE.  The token is verified using gss_unseal()/
   * gss_unwrap().
   *
   */
  if(data->set.socks5_gssapi_nec) {
    us_length = htons((short)1);
    memcpy(socksreq+2,&us_length,sizeof(short));
  }
  else {
    gss_send_token.length = 1;
    gss_send_token.value = malloc(1);
    if(!gss_send_token.value) {
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_OUT_OF_MEMORY;
    }
    memcpy(gss_send_token.value, &gss_enc, 1);

    gss_major_status = gss_wrap(&gss_minor_status, gss_context, 0,
                                GSS_C_QOP_DEFAULT, &gss_send_token,
                                &gss_conf_state, &gss_w_token);

    if(check_gss_err(data,gss_major_status,gss_minor_status,"gss_wrap")) {
      gss_release_buffer(&gss_status, &gss_send_token);
      gss_release_buffer(&gss_status, &gss_w_token);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      failf(data, "Failed to wrap GSSAPI encryption value into token.");
      return CURLE_COULDNT_CONNECT;
    }
    gss_release_buffer(&gss_status, &gss_send_token);

    us_length = htons((short)gss_w_token.length);
    memcpy(socksreq+2,&us_length,sizeof(short));
  }

  code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
  if((code != CURLE_OK) || (4 != written)) {
    failf(data, "Failed to send GSSAPI encryption request.");
    gss_release_buffer(&gss_status, &gss_w_token);
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    return CURLE_COULDNT_CONNECT;
  }

  if(data->set.socks5_gssapi_nec) {
    memcpy(socksreq, &gss_enc, 1);
    code = Curl_write_plain(conn, sock, socksreq, 1, &written);
    if((code != CURLE_OK) || ( 1 != written)) {
      failf(data, "Failed to send GSSAPI encryption type.");
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }
  } else {
    code = Curl_write_plain(conn, sock, (char *)gss_w_token.value,
                            gss_w_token.length, &written);
    if((code != CURLE_OK) || ((ssize_t)gss_w_token.length != written)) {
      failf(data, "Failed to send GSSAPI encryption type.");
      gss_release_buffer(&gss_status, &gss_w_token);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }
    gss_release_buffer(&gss_status, &gss_w_token);
  }

  result=Curl_blockread_all(conn, sock, (char *)socksreq, 4,
                            &actualread, timeout);
  if(result != CURLE_OK || actualread != 4) {
    failf(data, "Failed to receive GSSAPI encryption response.");
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    return CURLE_COULDNT_CONNECT;
  }

  /* ignore the first (VER) byte */
  if(socksreq[1] == 255) { /* status / message type */
    failf(data, "User was rejected by the SOCKS5 server (%d %d).",
          socksreq[0], socksreq[1]);
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    return CURLE_COULDNT_CONNECT;
  }

  if(socksreq[1] != 2) { /* status / messgae type */
    failf(data, "Invalid GSSAPI encryption response type (%d %d).",
          socksreq[0], socksreq[1]);
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    return CURLE_COULDNT_CONNECT;
  }

  memcpy(&us_length, socksreq+2, sizeof(short));
  us_length = ntohs(us_length);

  gss_recv_token.length= us_length;
  gss_recv_token.value=malloc(gss_recv_token.length);
  if(!gss_recv_token.value) {
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    return CURLE_OUT_OF_MEMORY;
  }
  result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
                            gss_recv_token.length,
                            &actualread, timeout);

  if(result != CURLE_OK || actualread != us_length) {
    failf(data, "Failed to receive GSSAPI encryptrion type.");
    gss_release_buffer(&gss_status, &gss_recv_token);
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    return CURLE_COULDNT_CONNECT;
  }

  if(!data->set.socks5_gssapi_nec) {
    gss_major_status = gss_unwrap(&gss_minor_status, gss_context,
                                  &gss_recv_token, &gss_w_token,
                                  0, GSS_C_QOP_DEFAULT);

    if(check_gss_err(data,gss_major_status,gss_minor_status,"gss_unwrap")) {
      gss_release_buffer(&gss_status, &gss_recv_token);
      gss_release_buffer(&gss_status, &gss_w_token);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      failf(data, "Failed to unwrap GSSAPI encryption value into token.");
      return CURLE_COULDNT_CONNECT;
    }
    gss_release_buffer(&gss_status, &gss_recv_token);

    if(gss_w_token.length != 1) {
      failf(data, "Invalid GSSAPI encryption response length (%d).",
            gss_w_token.length);
      gss_release_buffer(&gss_status, &gss_w_token);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }

    memcpy(socksreq,gss_w_token.value,gss_w_token.length);
    gss_release_buffer(&gss_status, &gss_w_token);
  }
  else {
    if(gss_recv_token.length != 1) {
      failf(data, "Invalid GSSAPI encryption response length (%d).",
            gss_recv_token.length);
      gss_release_buffer(&gss_status, &gss_recv_token);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      return CURLE_COULDNT_CONNECT;
    }

    memcpy(socksreq,gss_recv_token.value,gss_recv_token.length);
    gss_release_buffer(&gss_status, &gss_recv_token);
  }

  infof(data, "SOCKS5 access with%s protection granted.\n",
        (socksreq[0]==0)?"out gssapi data":
        ((socksreq[0]==1)?" gssapi integrity":" gssapi confidentiality"));

  conn->socks5_gssapi_enctype = socksreq[0];
  if(socksreq[0] == 0)
    gss_delete_sec_context(&gss_status, &gss_context, NULL);

  return CURLE_OK;
}
Example #4
0
/*
 * Create a new client struct from a file descriptor and establish a GSS-API
 * context as a specified service with an incoming client and fills out the
 * client struct.  Returns a new client struct on success and NULL on failure,
 * logging an appropriate error message.
 */
struct client *
server_new_client(int fd, gss_cred_id_t creds)
{
    struct client *client;
    struct sockaddr_storage ss;
    socklen_t socklen;
    size_t length;
    char *buffer;
    gss_buffer_desc send_tok, recv_tok, name_buf;
    gss_name_t name = GSS_C_NO_NAME;
    gss_OID doid;
    OM_uint32 major = 0;
    OM_uint32 minor = 0;
    OM_uint32 acc_minor, time_rec;
    int flags, status;
    static const OM_uint32 req_gss_flags
        = (GSS_C_MUTUAL_FLAG | GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG);

    /* Create and initialize a new client struct. */
    client = xcalloc(1, sizeof(struct client));
    client->fd = fd;
    client->context = GSS_C_NO_CONTEXT;

    /* Fill in hostname and IP address. */
    socklen = sizeof(ss);
    if (getpeername(fd, (struct sockaddr *) &ss, &socklen) != 0) {
        syswarn("cannot get peer address");
        goto fail;
    }
    length = INET6_ADDRSTRLEN;
    buffer = xmalloc(length);
    client->ipaddress = buffer;
    status = getnameinfo((struct sockaddr *) &ss, socklen, buffer, length,
                         NULL, 0, NI_NUMERICHOST);
    if (status != 0) {
        syswarn("cannot translate IP address of client: %s",
                gai_strerror(status));
        goto fail;
    }
    length = NI_MAXHOST;
    buffer = xmalloc(length);
    status = getnameinfo((struct sockaddr *) &ss, socklen, buffer, length,
                         NULL, 0, NI_NAMEREQD);
    if (status == 0)
        client->hostname = buffer;
    else
        free(buffer);

    /* Accept the initial (worthless) token. */
    status = token_recv(client->fd, &flags, &recv_tok, TOKEN_MAX_LENGTH,
                        TIMEOUT);
    if (status != TOKEN_OK) {
        warn_token("receiving initial token", status, major, minor);
        goto fail;
    }
    free(recv_tok.value);
    if (flags == (TOKEN_NOOP | TOKEN_CONTEXT_NEXT | TOKEN_PROTOCOL))
        client->protocol = 2;
    else if (flags == (TOKEN_NOOP | TOKEN_CONTEXT_NEXT))
        client->protocol = 1;
    else {
        warn("bad token flags %d in initial token", flags);
        goto fail;
    }

    /* Now, do the real work of negotiating the context. */
    do {
        status = token_recv(client->fd, &flags, &recv_tok, TOKEN_MAX_LENGTH,
                            TIMEOUT);
        if (status != TOKEN_OK) {
            warn_token("receiving context token", status, major, minor);
            goto fail;
        }
        if (flags == TOKEN_CONTEXT)
            client->protocol = 1;
        else if (flags != (TOKEN_CONTEXT | TOKEN_PROTOCOL)) {
            warn("bad token flags %d in context token", flags);
            free(recv_tok.value);
            goto fail;
        }
        debug("received context token (size=%lu)",
              (unsigned long) recv_tok.length);
        major = gss_accept_sec_context(&acc_minor, &client->context, creds,
                    &recv_tok, GSS_C_NO_CHANNEL_BINDINGS, &name, &doid,
                    &send_tok, &client->flags, &time_rec, NULL);
        free(recv_tok.value);

        /* Send back a token if we need to. */
        if (send_tok.length != 0) {
            debug("sending context token (size=%lu)",
                  (unsigned long) send_tok.length);
            flags = TOKEN_CONTEXT;
            if (client->protocol > 1)
                flags |= TOKEN_PROTOCOL;
            status = token_send(client->fd, flags, &send_tok, TIMEOUT);
            if (status != TOKEN_OK) {
                warn_token("sending context token", status, major, minor);
                gss_release_buffer(&minor, &send_tok);
                goto fail;
            }
            gss_release_buffer(&minor, &send_tok);
        }

        /* Bail out if we lose. */
        if (major != GSS_S_COMPLETE && major != GSS_S_CONTINUE_NEEDED) {
            warn_gssapi("while accepting context", major, acc_minor);
            goto fail;
        }
        if (major == GSS_S_CONTINUE_NEEDED)
            debug("continue needed while accepting context");
    } while (major == GSS_S_CONTINUE_NEEDED);

    /* Make sure that the appropriate context flags are set. */
    if (client->protocol > 1) {
        if ((client->flags & req_gss_flags) != req_gss_flags) {
            warn("client did not negotiate appropriate GSS-API flags");
            goto fail;
        }
    }

    /* Based on the protocol, set up the callbacks. */
    if (client->protocol == 1) {
        client->setup = server_v1_command_setup;
        client->finish = server_v1_send_output;
        client->error = server_v1_send_error;
    } else {
        client->setup = server_v2_command_setup;
        client->finish = server_v2_command_finish;
        client->error = server_v2_send_error;
    }

    /* Get the display version of the client name and store it. */
    major = gss_display_name(&minor, name, &name_buf, &doid);
    if (major != GSS_S_COMPLETE) {
        warn_gssapi("while displaying client name", major, minor);
        goto fail;
    }
    gss_release_name(&minor, &name);
    if (gss_oid_equal(doid, GSS_C_NT_ANONYMOUS))
        client->anonymous = true;
    client->user = xstrndup(name_buf.value, name_buf.length);
    client->expires = time(NULL) + time_rec;
    gss_release_buffer(&minor, &name_buf);
    return client;

fail:
    if (client->context != GSS_C_NO_CONTEXT)
        gss_delete_sec_context(&minor, &client->context, GSS_C_NO_BUFFER);
    if (name != GSS_C_NO_NAME)
        gss_release_name(&minor, &name);
    free(client->ipaddress);
    free(client->hostname);
    free(client);
    return NULL;
}
Example #5
0
int
_gsasl_gssapi_server_start (Gsasl_session * sctx, void **mech_data)
{
  _Gsasl_gssapi_server_state *state;
  OM_uint32 maj_stat, min_stat;
  gss_name_t server;
  gss_buffer_desc bufdesc;
  const char *service;
  const char *hostname;

  service = gsasl_property_get (sctx, GSASL_SERVICE);
  if (!service)
    return GSASL_NO_SERVICE;

  hostname = gsasl_property_get (sctx, GSASL_HOSTNAME);
  if (!hostname)
    return GSASL_NO_HOSTNAME;

  /* FIXME: Use asprintf. */

  bufdesc.length = strlen (service) + strlen ("@") + strlen (hostname) + 1;
  bufdesc.value = malloc (bufdesc.length);
  if (bufdesc.value == NULL)
    return GSASL_MALLOC_ERROR;

  sprintf (bufdesc.value, "%[email protected]%s", service, hostname);

  state = (_Gsasl_gssapi_server_state *) malloc (sizeof (*state));
  if (state == NULL)
    {
      free (bufdesc.value);
      return GSASL_MALLOC_ERROR;
    }

  maj_stat = gss_import_name (&min_stat, &bufdesc, GSS_C_NT_HOSTBASED_SERVICE,
			      &server);
  free (bufdesc.value);
  if (GSS_ERROR (maj_stat))
    {
      free (state);
      return GSASL_GSSAPI_IMPORT_NAME_ERROR;
    }

  maj_stat = gss_acquire_cred (&min_stat, server, 0,
			       GSS_C_NULL_OID_SET, GSS_C_ACCEPT,
			       &state->cred, NULL, NULL);
  gss_release_name (&min_stat, &server);

  if (GSS_ERROR (maj_stat))
    {
      free (state);
      return GSASL_GSSAPI_ACQUIRE_CRED_ERROR;
    }

  state->step = 0;
  state->context = GSS_C_NO_CONTEXT;
  state->client = NULL;
  *mech_data = state;

  return GSASL_OK;
}
Example #6
0
/** @internal
 * @brief handles an user authentication using GSSAPI
 */
int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n_oid, ssh_string *oids){
    char service_name[]="host";
    gss_buffer_desc name_buf;
    gss_name_t server_name; /* local server fqdn */
    OM_uint32 maj_stat, min_stat;
    unsigned int i;
    char *ptr;
    gss_OID_set supported; /* oids supported by server */
    gss_OID_set both_supported; /* oids supported by both client and server */
    gss_OID_set selected; /* oid selected for authentication */
    int present=0;
    int oid_count=0;
    struct gss_OID_desc_struct oid;
    int rc;

    if (ssh_callbacks_exists(session->server_callbacks, gssapi_select_oid_function)){
        ssh_string oid_s = session->server_callbacks->gssapi_select_oid_function(session,
                user, n_oid, oids,
                session->server_callbacks->userdata);
        if (oid_s != NULL){
            if (ssh_gssapi_init(session) == SSH_ERROR)
                return SSH_ERROR;
            session->gssapi->state = SSH_GSSAPI_STATE_RCV_TOKEN;
            rc = ssh_gssapi_send_response(session, oid_s);
            ssh_string_free(oid_s);
            return rc;
        } else {
            return ssh_auth_reply_default(session,0);
        }
    }
    gss_create_empty_oid_set(&min_stat, &both_supported);

    maj_stat = gss_indicate_mechs(&min_stat, &supported);
    for (i=0; i < supported->count; ++i){
        ptr = ssh_get_hexa(supported->elements[i].elements, supported->elements[i].length);
        SSH_LOG(SSH_LOG_DEBUG, "Supported mech %d: %s\n", i, ptr);
        free(ptr);
    }

    for (i=0 ; i< n_oid ; ++i){
        unsigned char *oid_s = (unsigned char *) ssh_string_data(oids[i]);
        size_t len = ssh_string_len(oids[i]);
        if(len < 2 || oid_s[0] != SSH_OID_TAG || ((size_t)oid_s[1]) != len - 2){
            SSH_LOG(SSH_LOG_WARNING,"GSSAPI: received invalid OID");
            continue;
        }
        oid.elements = &oid_s[2];
        oid.length = len - 2;
        gss_test_oid_set_member(&min_stat,&oid,supported,&present);
        if(present){
            gss_add_oid_set_member(&min_stat,&oid,&both_supported);
            oid_count++;
        }
    }
    gss_release_oid_set(&min_stat, &supported);
    if (oid_count == 0){
        SSH_LOG(SSH_LOG_PROTOCOL,"GSSAPI: no OID match");
        ssh_auth_reply_default(session, 0);
        gss_release_oid_set(&min_stat, &both_supported);
        return SSH_OK;
    }
    /* from now we have room for context */
    if (ssh_gssapi_init(session) == SSH_ERROR)
        return SSH_ERROR;

    name_buf.value = service_name;
    name_buf.length = strlen(name_buf.value) + 1;
    maj_stat = gss_import_name(&min_stat, &name_buf,
            (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &server_name);
    if (maj_stat != GSS_S_COMPLETE) {
        SSH_LOG(0, "importing name %d, %d", maj_stat, min_stat);
        ssh_gssapi_log_error(0, "importing name", maj_stat);
        return -1;
    }

    maj_stat = gss_acquire_cred(&min_stat, server_name, 0,
            both_supported, GSS_C_ACCEPT,
            &session->gssapi->server_creds, &selected, NULL);
    gss_release_name(&min_stat, &server_name);
    gss_release_oid_set(&min_stat, &both_supported);

    if (maj_stat != GSS_S_COMPLETE) {
        SSH_LOG(0, "error acquiring credentials %d, %d", maj_stat, min_stat);
        ssh_gssapi_log_error(0, "acquiring creds", maj_stat);
        ssh_auth_reply_default(session,0);
        return SSH_ERROR;
    }

    SSH_LOG(0, "acquiring credentials %d, %d", maj_stat, min_stat);

    /* finding which OID from client we selected */
    for (i=0 ; i< n_oid ; ++i){
        unsigned char *oid_s = (unsigned char *) ssh_string_data(oids[i]);
        size_t len = ssh_string_len(oids[i]);
        if(len < 2 || oid_s[0] != SSH_OID_TAG || ((size_t)oid_s[1]) != len - 2){
            SSH_LOG(SSH_LOG_WARNING,"GSSAPI: received invalid OID");
            continue;
        }
        oid.elements = &oid_s[2];
        oid.length = len - 2;
        gss_test_oid_set_member(&min_stat,&oid,selected,&present);
        if(present){
            SSH_LOG(SSH_LOG_PACKET, "Selected oid %d", i);
            break;
        }
    }
    session->gssapi->mech.length = oid.length;
    session->gssapi->mech.elements = malloc(oid.length);
    if (session->gssapi->mech.elements == NULL){
        ssh_set_error_oom(session);
        return SSH_ERROR;
    }
    memcpy(session->gssapi->mech.elements, oid.elements, oid.length);
    gss_release_oid_set(&min_stat, &selected);
    session->gssapi->user = strdup(user);
    session->gssapi->service = service_name;
    session->gssapi->state = SSH_GSSAPI_STATE_RCV_TOKEN;
    return ssh_gssapi_send_response(session, oids[i]);
}
Example #7
0
int
_gsasl_gssapi_server_step (Gsasl_session * sctx,
			   void *mech_data,
			   const char *input, size_t input_len,
			   char **output, size_t * output_len)
{
  _Gsasl_gssapi_server_state *state = mech_data;
  gss_buffer_desc bufdesc1, bufdesc2;
  OM_uint32 maj_stat, min_stat;
  gss_buffer_desc client_name;
  gss_OID mech_type;
  char tmp[4];
  int res;

  *output = NULL;
  *output_len = 0;

  switch (state->step)
    {
    case 0:
      if (input_len == 0)
	{
	  res = GSASL_NEEDS_MORE;
	  break;
	}
      state->step++;
      /* fall through */

    case 1:
      bufdesc1.value = (void *) input;
      bufdesc1.length = input_len;
      if (state->client)
	{
	  gss_release_name (&min_stat, &state->client);
	  state->client = GSS_C_NO_NAME;
	}

      maj_stat = gss_accept_sec_context (&min_stat,
					 &state->context,
					 state->cred,
					 &bufdesc1,
					 GSS_C_NO_CHANNEL_BINDINGS,
					 &state->client,
					 &mech_type,
					 &bufdesc2, NULL, NULL, NULL);
      if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
	return GSASL_GSSAPI_ACCEPT_SEC_CONTEXT_ERROR;

      *output = malloc (bufdesc2.length);
      if (!*output)
	return GSASL_MALLOC_ERROR;
      memcpy (*output, bufdesc2.value, bufdesc2.length);
      *output_len = bufdesc2.length;

      maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
      if (GSS_ERROR (maj_stat))
	return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;

      if (maj_stat == GSS_S_COMPLETE)
	state->step++;

      res = GSASL_NEEDS_MORE;
      break;

    case 2:
      memset (tmp, 0xFF, 4);
      tmp[0] = GSASL_QOP_AUTH;
      bufdesc1.length = 4;
      bufdesc1.value = tmp;
      maj_stat = gss_wrap (&min_stat, state->context, 0, GSS_C_QOP_DEFAULT,
			   &bufdesc1, NULL, &bufdesc2);
      if (GSS_ERROR (maj_stat))
	return GSASL_GSSAPI_WRAP_ERROR;

      *output = malloc (bufdesc2.length);
      if (!*output)
	return GSASL_MALLOC_ERROR;
      memcpy (*output, bufdesc2.value, bufdesc2.length);
      *output_len = bufdesc2.length;

      maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
      if (GSS_ERROR (maj_stat))
	return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;

      state->step++;
      res = GSASL_NEEDS_MORE;
      break;

    case 3:
      bufdesc1.value = (void *) input;
      bufdesc1.length = input_len;
      maj_stat = gss_unwrap (&min_stat, state->context, &bufdesc1,
			     &bufdesc2, NULL, NULL);
      if (GSS_ERROR (maj_stat))
	return GSASL_GSSAPI_UNWRAP_ERROR;

      /* [RFC 2222 section 7.2.1]:
         The client passes this token to GSS_Unwrap and interprets the
         first octet of resulting cleartext as a bit-mask specifying
         the security layers supported by the server and the second
         through fourth octets as the maximum size output_message to
         send to the server.  The client then constructs data, with
         the first octet containing the bit-mask specifying the
         selected security layer, the second through fourth octets
         containing in network byte order the maximum size
         output_message the client is able to receive, and the
         remaining octets containing the authorization identity.  The
         client passes the data to GSS_Wrap with conf_flag set to
         FALSE, and responds with the generated output_message.  The
         client can then consider the server authenticated. */

      if ((((char *) bufdesc2.value)[0] & GSASL_QOP_AUTH) == 0)
	{
	  /* Integrity or privacy unsupported */
	  maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
	  return GSASL_GSSAPI_UNSUPPORTED_PROTECTION_ERROR;
	}

      gsasl_property_set_raw (sctx, GSASL_AUTHZID,
			      bufdesc2.value + 4, bufdesc2.length - 4);

      maj_stat = gss_display_name (&min_stat, state->client,
				   &client_name, &mech_type);
      if (GSS_ERROR (maj_stat))
	return GSASL_GSSAPI_DISPLAY_NAME_ERROR;

      gsasl_property_set_raw (sctx, GSASL_GSSAPI_DISPLAY_NAME,
			      client_name.value, client_name.length);

      maj_stat = gss_release_buffer (&min_stat, &bufdesc2);
      if (GSS_ERROR (maj_stat))
	return GSASL_GSSAPI_RELEASE_BUFFER_ERROR;

      res = gsasl_callback (NULL, sctx, GSASL_VALIDATE_GSSAPI);

      state->step++;
      break;

    default:
      res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
      break;
    }

  return res;
}
Example #8
0
int authenticate_gss_client_step(gss_client_state* state, const char* challenge)
{
    OM_uint32 maj_stat;
    OM_uint32 min_stat;
    gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
    int ret = AUTH_GSS_CONTINUE;
    
    // Always clear out the old response
    if (state->response != NULL)
    {
        free(state->response);
        state->response = NULL;
    }
    
    // If there is a challenge (data from the server) we need to give it to GSS
    if (challenge && *challenge)
    {
        size_t len;
        input_token.value = base64_decode(challenge, &len);
        input_token.length = len;
    }
    
    // Do GSSAPI step
    Py_BEGIN_ALLOW_THREADS
    maj_stat = gss_init_sec_context(&min_stat,
                                    state->client_creds,
                                    &state->context,
                                    state->server_name,
                                    GSS_C_NO_OID,
                                    (OM_uint32)state->gss_flags,
                                    0,
                                    GSS_C_NO_CHANNEL_BINDINGS,
                                    &input_token,
                                    NULL,
                                    &output_token,
                                    NULL,
                                    NULL);
    Py_END_ALLOW_THREADS
    
    if ((maj_stat != GSS_S_COMPLETE) && (maj_stat != GSS_S_CONTINUE_NEEDED))
    {
        set_gss_error(maj_stat, min_stat);
        ret = AUTH_GSS_ERROR;
        goto end;
    }
    
    ret = (maj_stat == GSS_S_COMPLETE) ? AUTH_GSS_COMPLETE : AUTH_GSS_CONTINUE;
    // Grab the client response to send back to the server
    if (output_token.length)
    {
        state->response = base64_encode((const unsigned char *)output_token.value, output_token.length);;
        maj_stat = gss_release_buffer(&min_stat, &output_token);
    }
    
    // Try to get the user name if we have completed all GSS operations
    if (ret == AUTH_GSS_COMPLETE)
    {
        gss_name_t gssuser = GSS_C_NO_NAME;
        maj_stat = gss_inquire_context(&min_stat, state->context, &gssuser, NULL, NULL, NULL,  NULL, NULL, NULL);
        if (GSS_ERROR(maj_stat))
        {
            set_gss_error(maj_stat, min_stat);
            ret = AUTH_GSS_ERROR;
            goto end;
        }
        
        gss_buffer_desc name_token;
        name_token.length = 0;
        maj_stat = gss_display_name(&min_stat, gssuser, &name_token, NULL);
        if (GSS_ERROR(maj_stat))
        {
            if (name_token.value)
                gss_release_buffer(&min_stat, &name_token);
            gss_release_name(&min_stat, &gssuser);
            
            set_gss_error(maj_stat, min_stat);
            ret = AUTH_GSS_ERROR;
            goto end;
        }
        else
        {
            state->username = (char *)malloc(name_token.length + 1);
            strncpy(state->username, (char*) name_token.value, name_token.length);
            state->username[name_token.length] = 0;
            gss_release_buffer(&min_stat, &name_token);
            gss_release_name(&min_stat, &gssuser);
        }
    }
end:
    if (output_token.value)
        gss_release_buffer(&min_stat, &output_token);
    if (input_token.value)
        free(input_token.value);
    return ret;
}
Example #9
0
int authenticate_gss_client_init(const char* service, const char* principal, long int gss_flags, gss_client_state* state)
{
    OM_uint32 maj_stat;
    OM_uint32 min_stat;
    gss_buffer_desc name_token = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc principal_token = GSS_C_EMPTY_BUFFER;
    int ret = AUTH_GSS_COMPLETE;
    
    state->server_name = GSS_C_NO_NAME;
    state->context = GSS_C_NO_CONTEXT;
    state->gss_flags = gss_flags;
    state->client_creds = GSS_C_NO_CREDENTIAL;
    state->username = NULL;
    state->response = NULL;
    
    // Import server name first
    name_token.length = strlen(service);
    name_token.value = (char *)service;
    
    maj_stat = gss_import_name(&min_stat, &name_token, gss_krb5_nt_service_name, &state->server_name);
    
    if (GSS_ERROR(maj_stat))
    {
        set_gss_error(maj_stat, min_stat);
        ret = AUTH_GSS_ERROR;
        goto end;
    }
    
    // Get credential for principal
    if (principal && *principal)
    {
        gss_name_t name;
        principal_token.length = strlen(principal);
        principal_token.value = (char *)principal;

        maj_stat = gss_import_name(&min_stat, &principal_token, GSS_C_NT_USER_NAME, &name);
        if (GSS_ERROR(maj_stat))
        {
            set_gss_error(maj_stat, min_stat);
            ret = AUTH_GSS_ERROR;
	    goto end;
        }

        maj_stat = gss_acquire_cred(&min_stat, name, GSS_C_INDEFINITE, GSS_C_NO_OID_SET, GSS_C_INITIATE, 
                                    &state->client_creds, NULL, NULL);
        if (GSS_ERROR(maj_stat))
        {
            set_gss_error(maj_stat, min_stat);
            ret = AUTH_GSS_ERROR;
	    goto end;
        }

        maj_stat = gss_release_name(&min_stat, &name);
        if (GSS_ERROR(maj_stat))
        {
	    set_gss_error(maj_stat, min_stat);
            ret = AUTH_GSS_ERROR;
            goto end;
        }

      }

end:
    return ret;
}
Example #10
0
isc_result_t
dst_gssapi_acceptctx(gss_cred_id_t cred,
                     isc_region_t *intoken, isc_buffer_t **outtoken,
                     gss_ctx_id_t *ctxout, dns_name_t *principal,
                     isc_mem_t *mctx)
{
#ifdef GSSAPI
    isc_region_t r;
    isc_buffer_t namebuf;
    gss_buffer_desc gnamebuf = GSS_C_EMPTY_BUFFER, gintoken,
                    gouttoken = GSS_C_EMPTY_BUFFER;
    OM_uint32 gret, minor;
    gss_ctx_id_t context = GSS_C_NO_CONTEXT;
    gss_name_t gname = NULL;
    isc_result_t result;
    char buf[1024];

    REQUIRE(outtoken != NULL && *outtoken == NULL);

    log_cred(cred);

    REGION_TO_GBUFFER(*intoken, gintoken);

    if (*ctxout == NULL)
        context = GSS_C_NO_CONTEXT;
    else
        context = *ctxout;

    gret = gss_accept_sec_context(&minor, &context, cred, &gintoken,
                                  GSS_C_NO_CHANNEL_BINDINGS, &gname,
                                  NULL, &gouttoken, NULL, NULL, NULL);

    result = ISC_R_FAILURE;

    switch (gret) {
    case GSS_S_COMPLETE:
        result = ISC_R_SUCCESS;
        break;
    case GSS_S_CONTINUE_NEEDED:
        result = DNS_R_CONTINUE;
        break;
    case GSS_S_DEFECTIVE_TOKEN:
    case GSS_S_DEFECTIVE_CREDENTIAL:
    case GSS_S_BAD_SIG:
    case GSS_S_DUPLICATE_TOKEN:
    case GSS_S_OLD_TOKEN:
    case GSS_S_NO_CRED:
    case GSS_S_CREDENTIALS_EXPIRED:
    case GSS_S_BAD_BINDINGS:
    case GSS_S_NO_CONTEXT:
    case GSS_S_BAD_MECH:
    case GSS_S_FAILURE:
        result = DNS_R_INVALIDTKEY;
    /* fall through */
    default:
        gss_log(3, "failed gss_accept_sec_context: %s",
                gss_error_tostring(gret, minor, buf, sizeof(buf)));
        return (result);
    }

    if (gouttoken.length > 0) {
        RETERR(isc_buffer_allocate(mctx, outtoken, gouttoken.length));
        GBUFFER_TO_REGION(gouttoken, r);
        RETERR(isc_buffer_copyregion(*outtoken, &r));
        (void)gss_release_buffer(&minor, &gouttoken);
    }

    if (gret == GSS_S_COMPLETE) {
        gret = gss_display_name(&minor, gname, &gnamebuf, NULL);
        if (gret != GSS_S_COMPLETE) {
            gss_log(3, "failed gss_display_name: %s",
                    gss_error_tostring(gret, minor,
                                       buf, sizeof(buf)));
            RETERR(ISC_R_FAILURE);
        }

        /*
         * Compensate for a bug in Solaris8's implementation
         * of gss_display_name().  Should be harmless in any
         * case, since principal names really should not
         * contain null characters.
         */
        if (gnamebuf.length > 0 &&
                ((char *)gnamebuf.value)[gnamebuf.length - 1] == '\0')
            gnamebuf.length--;

        gss_log(3, "gss-api source name (accept) is %.*s",
                (int)gnamebuf.length, (char *)gnamebuf.value);

        GBUFFER_TO_REGION(gnamebuf, r);
        isc_buffer_init(&namebuf, r.base, r.length);
        isc_buffer_add(&namebuf, r.length);

        RETERR(dns_name_fromtext(principal, &namebuf, dns_rootname,
                                 0, NULL));

        if (gnamebuf.length != 0) {
            gret = gss_release_buffer(&minor, &gnamebuf);
            if (gret != GSS_S_COMPLETE)
                gss_log(3, "failed gss_release_buffer: %s",
                        gss_error_tostring(gret, minor, buf,
                                           sizeof(buf)));
        }
    }

    *ctxout = context;

out:
    if (gname != NULL) {
        gret = gss_release_name(&minor, &gname);
        if (gret != GSS_S_COMPLETE)
            gss_log(3, "failed gss_release_name: %s",
                    gss_error_tostring(gret, minor, buf,
                                       sizeof(buf)));
    }

    return (result);
#else
    UNUSED(cred);
    UNUSED(intoken);
    UNUSED(outtoken);
    UNUSED(ctxout);
    UNUSED(principal);
    UNUSED(mctx);

    return (ISC_R_NOTIMPLEMENTED);
#endif
}
Example #11
0
isc_result_t
dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken,
                   isc_buffer_t *outtoken, gss_ctx_id_t *gssctx)
{
#ifdef GSSAPI
    isc_region_t r;
    isc_buffer_t namebuf;
    gss_name_t gname;
    OM_uint32 gret, minor, ret_flags, flags;
    gss_buffer_desc gintoken, *gintokenp, gouttoken = GSS_C_EMPTY_BUFFER;
    isc_result_t result;
    gss_buffer_desc gnamebuf;
    unsigned char array[DNS_NAME_MAXTEXT + 1];
    char buf[1024];

    /* Client must pass us a valid gss_ctx_id_t here */
    REQUIRE(gssctx != NULL);

    isc_buffer_init(&namebuf, array, sizeof(array));
    name_to_gbuffer(name, &namebuf, &gnamebuf);

    /* Get the name as a GSS name */
    gret = gss_import_name(&minor, &gnamebuf, GSS_C_NO_OID, &gname);
    if (gret != GSS_S_COMPLETE) {
        result = ISC_R_FAILURE;
        goto out;
    }

    if (intoken != NULL) {
        /* Don't call gss_release_buffer for gintoken! */
        REGION_TO_GBUFFER(*intoken, gintoken);
        gintokenp = &gintoken;
    } else {
        gintokenp = NULL;
    }

    /*
     * Note that we don't set GSS_C_SEQUENCE_FLAG as Windows DNS
     * servers don't like it.
     */
    flags = GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG |
            GSS_C_INTEG_FLAG;

    gret = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, gssctx,
                                gname, GSS_SPNEGO_MECHANISM, flags,
                                0, NULL, gintokenp,
                                NULL, &gouttoken, &ret_flags, NULL);

    if (gret != GSS_S_COMPLETE && gret != GSS_S_CONTINUE_NEEDED) {
        gss_log(3, "Failure initiating security context");
        gss_log(3, "%s", gss_error_tostring(gret, minor,
                                            buf, sizeof(buf)));
        result = ISC_R_FAILURE;
        goto out;
    }

    /*
     * XXXSRA Not handled yet: RFC 3645 3.1.1: check ret_flags
     * MUTUAL and INTEG flags, fail if either not set.
     */

    /*
     * RFC 2744 states the a valid output token has a non-zero length.
     */
    if (gouttoken.length != 0) {
        GBUFFER_TO_REGION(gouttoken, r);
        RETERR(isc_buffer_copyregion(outtoken, &r));
        (void)gss_release_buffer(&minor, &gouttoken);
    }
    (void)gss_release_name(&minor, &gname);

    if (gret == GSS_S_COMPLETE)
        result = ISC_R_SUCCESS;
    else
        result = DNS_R_CONTINUE;

out:
    return (result);
#else
    UNUSED(name);
    UNUSED(intoken);
    UNUSED(outtoken);
    UNUSED(gssctx);

    return (ISC_R_NOTIMPLEMENTED);
#endif
}