Esempio n. 1
0
static void
check_replay_error(const char *msg, OM_uint32 major, OM_uint32 minor)
{
    OM_uint32 tmpmin, msg_ctx = 0;
    const char *replay = "Request is a replay";
    gss_buffer_desc m;

    if (major != GSS_S_FAILURE) {
        fprintf(stderr, "%s: expected major code GSS_S_FAILURE\n", msg);
        check_gsserr(msg, major, minor);
        exit(1);
    }

    (void)gss_display_status(&tmpmin, minor, GSS_C_MECH_CODE, GSS_C_NULL_OID,
                             &msg_ctx, &m);
    if (m.length != strlen(replay) || memcmp(m.value, replay, m.length) != 0) {
        fprintf(stderr, "%s: expected replay error; got %.*s\n", msg,
                (int)m.length, (char *)m.value);
        exit(1);
    }
    (void)gss_release_buffer(&tmpmin, &m);
}
Esempio n. 2
0
static int
exim_gssapi_error_defer(uschar *store_reset_point,
    OM_uint32 major, OM_uint32 minor,
    const char *format, ...)
{
  va_list ap;
  uschar buffer[STRING_SPRINTF_BUFFER_SIZE];
  OM_uint32 maj_stat, min_stat;
  OM_uint32 msgcontext = 0;
  gss_buffer_desc status_string;

  va_start(ap, format);
  if (!string_vformat(buffer, sizeof(buffer), format, ap))
    log_write(0, LOG_MAIN|LOG_PANIC_DIE,
        "exim_gssapi_error_defer expansion larger than %lu",
        sizeof(buffer));
  va_end(ap);

  auth_defer_msg = NULL;

  do {
    maj_stat = gss_display_status(&min_stat,
        major, GSS_C_GSS_CODE, GSS_C_NO_OID,
        &msgcontext, &status_string);

    if (auth_defer_msg == NULL) {
      auth_defer_msg = string_copy(US status_string.value);
    }

    HDEBUG(D_auth) debug_printf("heimdal %s: %.*s\n",
        buffer, (int)status_string.length, CS status_string.value);
    gss_release_buffer(&min_stat, &status_string);

  } while (msgcontext != 0);

  if (store_reset_point)
    store_reset(store_reset_point);
  return DEFER;
}
Esempio n. 3
0
static void gsslib_display_status_1(const char *m, OM_uint32 code, int type)
{
   OM_uint32 maj_stat, min_stat;
   gss_buffer_desc msg;
   GSSAPI_INT msg_ctx;

   memset((void *)&msg, 0, sizeof(msg));
   msg_ctx = 0;
   while (1) {
      maj_stat = gss_display_status(&min_stat, code,
                                    type, GSS_C_NULL_OID,
                                    &msg_ctx, &msg);
      snprintf(msgptr, sizeof msgbuf - strlen(msgptr), MSG_GSS_APIERRORXY_SS,
               m?m:"<>", (char *)msg.value?(char *)msg.value:"<>");
      msgptr += strlen(msgptr);
      snprintf(msgptr, sizeof msgbuf - strlen(msgptr), "\n");
      (void) gss_release_buffer(&min_stat, &msg);
      msgptr += strlen(msgptr);

      if (!msg_ctx)
         break;
   }
}
Esempio n. 4
0
File: cssp.c Progetto: jeppeter/vbox
static void
cssp_gss_report_error(OM_uint32 code, char *str, OM_uint32 major_status, OM_uint32 minor_status)
{
	OM_uint32 msgctx = 0, ms;
	gss_buffer_desc status_string;

	error("GSS error [%d:%d:%d]: %s\n", (major_status & 0xff000000) >> 24,	// Calling error
	      (major_status & 0xff0000) >> 16,	// Routine error
	      major_status & 0xffff,	// Supplementary info bits
	      str);

	do
	{
		ms = gss_display_status(&minor_status, major_status,
					code, GSS_C_NULL_OID, &msgctx, &status_string);
		if (ms != GSS_S_COMPLETE)
			continue;

		error(" - %s\n", status_string.value);

	}
	while (ms == GSS_S_COMPLETE && msgctx);

}
Esempio n. 5
0
File: gssapi.c Progetto: 1ack/Impala
static int
sasl_gss_seterror_(const sasl_utils_t *utils, OM_uint32 maj, OM_uint32 min,
		   int logonly)
{
    OM_uint32 maj_stat, min_stat;
    gss_buffer_desc msg;
    OM_uint32 msg_ctx;
    int ret;
    char *out = NULL;
    size_t len, curlen = 0;
    const char prefix[] = "GSSAPI Error: ";
    
    len = sizeof(prefix);
    ret = _plug_buf_alloc(utils, &out, &curlen, 256);
    if(ret != SASL_OK) return SASL_OK;
    
    strcpy(out, prefix);
    
    msg_ctx = 0;
    while (1) {
	GSS_LOCK_MUTEX(utils);
	maj_stat = gss_display_status(&min_stat, maj,
				      GSS_C_GSS_CODE, GSS_C_NULL_OID,
				      &msg_ctx, &msg);
	GSS_UNLOCK_MUTEX(utils);
	
	if(GSS_ERROR(maj_stat)) {
	    if (logonly) {
		utils->log(utils->conn, SASL_LOG_FAIL,
			"GSSAPI Failure: (could not get major error message)");
	    } else {
		utils->seterror(utils->conn, 0,
				"GSSAPI Failure "
				"(could not get major error message)");
	    }
	    utils->free(out);
	    return SASL_OK;
	}
	
	len += len + msg.length;
	ret = _plug_buf_alloc(utils, &out, &curlen, len);
	
	if(ret != SASL_OK) {
	    utils->free(out);
	    return SASL_OK;
	}
	
	strcat(out, msg.value);
	
	GSS_LOCK_MUTEX(utils);
	gss_release_buffer(&min_stat, &msg);
	GSS_UNLOCK_MUTEX(utils);
	
	if (!msg_ctx)
	    break;
    }
    
    /* Now get the minor status */
    
    len += 2;
    ret = _plug_buf_alloc(utils, &out, &curlen, len);
    if(ret != SASL_OK) {
	utils->free(out);
	return SASL_NOMEM;
    }
    
    strcat(out, " (");
    
    msg_ctx = 0;
    while (1) {
	GSS_LOCK_MUTEX(utils);
	maj_stat = gss_display_status(&min_stat, min,
				      GSS_C_MECH_CODE, GSS_C_NULL_OID,
				      &msg_ctx, &msg);
	GSS_UNLOCK_MUTEX(utils);
	
	if(GSS_ERROR(maj_stat)) {
	    if (logonly) {
		utils->log(utils->conn, SASL_LOG_FAIL,
			"GSSAPI Failure: (could not get minor error message)");
	    } else {
		utils->seterror(utils->conn, 0,
				"GSSAPI Failure "
				"(could not get minor error message)");
	    }
	    utils->free(out);
	    return SASL_OK;
	}
	
	len += len + msg.length;

	ret = _plug_buf_alloc(utils, &out, &curlen, len);
	if(ret != SASL_OK) {
	    utils->free(out);
	    return SASL_NOMEM;
	}
	
	strcat(out, msg.value);
	
	GSS_LOCK_MUTEX(utils);
	gss_release_buffer(&min_stat, &msg);
	GSS_UNLOCK_MUTEX(utils);
	
	if (!msg_ctx)
	    break;
    }
    
    len += 1;
    ret = _plug_buf_alloc(utils, &out, &curlen, len);
    if(ret != SASL_OK) {
	utils->free(out);
	return SASL_NOMEM;
    }
    
    strcat(out, ")");
    
    if (logonly) {
	utils->log(utils->conn, SASL_LOG_FAIL, out);
    } else {
	utils->seterror(utils->conn, 0, out);
    }
    utils->free(out);

    return SASL_OK;
}
Esempio n. 6
0
DWORD
VMCARESTVerifyKrbAuth(
    PVMCA_AUTHORIZATION_PARAM pAuthorization,
    PVMCA_ACCESS_TOKEN* ppAccessToken
    )
{
    DWORD dwError = 0;
    PSTR pszNegotiate = NULL;
    PSTR pszDecode = NULL;
    PSTR pszUser = NULL;
    char *pszToken = NULL;
    int nLength = 0;
    OM_uint32 major_status;
    OM_uint32 minor_status;
    gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc display_name = GSS_C_EMPTY_BUFFER;
    gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT;
    gss_name_t client_name = GSS_C_NO_NAME;
    static gss_OID_desc gss_spnego_mech_oid_desc =
                                 {6, (void *)"\x2b\x06\x01\x05\x05\x02"};
    static gss_OID gss_spnego_mech_oid = &gss_spnego_mech_oid_desc;
    gss_cred_id_t server_creds;

    pszNegotiate = pAuthorization->pszAuthorizationToken;
    if ( IsNullOrEmptyString(pszNegotiate) )
    {
        dwError = EACCES;
        BAIL_ON_VMREST_ERROR(dwError);
    }

    if (!strcmp(pszNegotiate,"testing"))
    // TODO: REMOVE
    // TODO: DO NOT CHECK IN
    {// Kerberos backdoor for testing
        dwError = VMCARESTMakeKrbAccessToken(ppAccessToken);
        BAIL_ON_VMREST_ERROR(dwError);
        goto cleanup;
    }
    dwError = base64_decode(
                        pszNegotiate,
                        &pszDecode,
                        &nLength
                        );
    BAIL_ON_VMREST_ERROR(dwError);

    dwError = server_acquire_creds(
                            "HTTP",
                            &gss_spnego_mech_oid_desc,
                            &server_creds
                            );
    BAIL_ON_VMREST_ERROR(dwError);

    input_token.length = nLength;
    input_token.value = pszDecode;

    major_status = gss_accept_sec_context(
                                    &minor_status,
                                    &gss_context,
                                    server_creds,
                                    &input_token,
                                    GSS_C_NO_CHANNEL_BINDINGS,
                                    &client_name,
                                    &gss_spnego_mech_oid,
                                    &output_token,
                                    NULL,
                                    NULL,
                                    NULL
                                    );

    if (GSS_ERROR(major_status) )
    {
        //TODO: insert show error
        dwError = EACCES;
        BAIL_ON_VMREST_ERROR(dwError);
    }

    if (output_token.length)
    {
        dwError = make_negotiate_token(&output_token, &pszToken);
        BAIL_ON_VMREST_ERROR(dwError);
    }

    if (major_status == GSS_S_CONTINUE_NEEDED)
    {
        OM_uint32 min2;
        gss_buffer_desc mech_msg = GSS_C_EMPTY_BUFFER;
        gss_buffer_desc gss_msg = GSS_C_EMPTY_BUFFER;
        gss_buffer_desc minor_msg = GSS_C_EMPTY_BUFFER;
        OM_uint32 msg_ctx = 0;
        PSTR pszError = NULL;

        gss_oid_to_str(&min2, gss_spnego_mech_oid, &mech_msg);
        gss_display_status(&min2, major_status, GSS_C_GSS_CODE, gss_spnego_mech_oid, &msg_ctx, &gss_msg);
        gss_display_status(&min2, minor_status, GSS_C_MECH_CODE, gss_spnego_mech_oid, &msg_ctx, &minor_msg);

        VMCAAllocateStringPrintfA(&pszError, "gss_rc[%d:%*s] mech[%*s] minor[%u:%*s]",
            major_status, (int)gss_msg.length,
            (const char *)(gss_msg.value?gss_msg.value:""),
            (int)mech_msg.length,
            (const char *)(mech_msg.value?mech_msg.value:""),
            minor_status, (int)minor_msg.length,
            (const char *)(minor_msg.value?minor_msg.value:""));

        gss_release_buffer(&min2, &mech_msg);
        gss_release_buffer(&min2, &gss_msg);
        gss_release_buffer(&min2, &minor_msg);
    }
    if (major_status == GSS_S_COMPLETE)
    {
        gss_display_name(&minor_status, client_name, &display_name, NULL);

        dwError = VMCAAllocateStringA(display_name.value, &pszUser);
        BAIL_ON_VMREST_ERROR(dwError);
    }

    dwError = VMCARESTMakeKrbAccessToken(ppAccessToken);
    BAIL_ON_VMREST_ERROR(dwError);

cleanup:
    if (pszUser)
    {
        VMCA_SAFE_FREE_MEMORY(pszUser);
    }
    return dwError;

error:
    goto cleanup;
}
/**
 * Return a copy of the short description from the instance data
 * @ingroup globus_gssapi_error_object 
 * 
 * @param error
 *        The error object to retrieve the data from.
 * @return
 *        String containing the short description if it exists, NULL
 *        otherwise.
 */
static
char *
globus_l_error_gssapi_printable(
    globus_object_t *                   error)
{
    OM_uint32	                        minor_status;
    OM_uint32                           message_context;
    gss_buffer_desc                     status_string_desc 
        = GSS_C_EMPTY_BUFFER;
    gss_buffer_t                        status_string = &status_string_desc;
    char *                              msg = NULL;
    char *                              tmp;
    int                                 len = 0;
    globus_l_gssapi_error_data_t *      data;
    
    data = (globus_l_gssapi_error_data_t *)
         globus_object_get_local_instance_data(error);
    
    if(data->is_globus_gsi)
    {
        message_context = 0;
        do
        {
            if(gss_display_status(&minor_status,
                                   data->major_status,
                                   GSS_C_GSS_CODE,
                                   GSS_C_NO_OID,
                                   &message_context,
                                   status_string) == GSS_S_COMPLETE)
            {
                if(status_string->length)
                {
                    if(msg)
                    {
                        tmp = globus_realloc(
                            msg,
                            sizeof(char) * (len + status_string->length + 1));
                    }
                    else
                    {
                        tmp = globus_malloc(
                            sizeof(char) * (status_string->length + 1));
                    }
                    if(tmp)
                    {
                        memcpy(
                            tmp + len,
                            status_string->value,
                            status_string->length);
                        msg = tmp;
                        len += status_string->length;
                    }
                }
                gss_release_buffer(&minor_status, status_string);
            }
        } while(message_context != 0);
        
        if(msg)
        {
            if(msg[len - 1] == '\n')
            {
                len--;
            }
            msg[len] = '\0';
        }
    }
    else
    {
        globus_gss_assist_display_status_str(
            &msg, NULL, data->major_status, data->minor_status, 0);
    }
    
    return msg;
}/* globus_l_error_gssapi_printable */
Esempio n. 8
0
                                 const char *msg,
                                 int maj_stat,
                                 int min_stat)
{
    gss_buffer_desc msg_maj = {
        .length = 0,
    };
    gss_buffer_desc msg_min = {
        .length = 0,
    };
    OM_uint32 dummy_maj, dummy_min;
    OM_uint32 message_context = 0;

    dummy_maj = gss_display_status(&dummy_min,
                                   maj_stat,
                                   GSS_C_GSS_CODE,
                                   GSS_C_NO_OID,
                                   &message_context,
                                   &msg_maj);
    if (dummy_maj != 0) {
        goto out;
    }

    dummy_maj = gss_display_status(&dummy_min,
                                   min_stat,
                                   GSS_C_MECH_CODE,
                                   GSS_C_NO_OID,
                                   &message_context,
                                   &msg_min);
    if (dummy_maj != 0) {
        goto out;
    }
Esempio n. 9
0
static int
gss_auth(void *app_data, char *host)
{

    OM_uint32 maj_stat, min_stat;
    gss_name_t target_name;
    gss_buffer_desc input, output_token;
    int context_established = 0;
    char *p;
    int n;
    gss_channel_bindings_t bindings;
    struct gssapi_data *d = app_data;
    OM_uint32 mech_flags = GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG;

    const char *knames[] = { "ftp", "host", NULL }, **kname = knames;


    if(import_name(*kname++, host, &target_name))
	return AUTH_ERROR;

    input.length = 0;
    input.value = NULL;

    if (ftp_do_gss_bindings) {
	bindings = malloc(sizeof(*bindings));
	if (bindings == NULL)
	    errx(1, "out of memory");

	sockaddr_to_gss_address (myctladdr,
				 &bindings->initiator_addrtype,
				 &bindings->initiator_address);
	sockaddr_to_gss_address (hisctladdr,
				 &bindings->acceptor_addrtype,
				 &bindings->acceptor_address);

	bindings->application_data.length = 0;
	bindings->application_data.value = NULL;
    } else
	bindings = GSS_C_NO_CHANNEL_BINDINGS;

    if (ftp_do_gss_delegate)
	mech_flags |= GSS_C_DELEG_FLAG;

    while(!context_established) {
	maj_stat = gss_init_sec_context(&min_stat,
					GSS_C_NO_CREDENTIAL,
					&d->context_hdl,
					target_name,
					GSS_C_NO_OID,
                                        mech_flags,
					0,
					bindings,
					&input,
					NULL,
					&output_token,
					NULL,
					NULL);
	if (GSS_ERROR(maj_stat)) {
	    OM_uint32 new_stat;
	    OM_uint32 msg_ctx = 0;
	    gss_buffer_desc status_string;

	    d->context_hdl = GSS_C_NO_CONTEXT;

	    gss_release_name(&min_stat, &target_name);

	    if(*kname != NULL) {

		if(import_name(*kname++, host, &target_name)) {
		    if (bindings != GSS_C_NO_CHANNEL_BINDINGS)
			free(bindings);
		    return AUTH_ERROR;
		}
		continue;
	    }

	    if (bindings != GSS_C_NO_CHANNEL_BINDINGS)
		free(bindings);

	    gss_display_status(&new_stat,
			       min_stat,
			       GSS_C_MECH_CODE,
			       GSS_C_NO_OID,
			       &msg_ctx,
			       &status_string);
	    printf("Error initializing security context: %.*s\n",
		   (int)status_string.length,
		   (char*)status_string.value);
	    gss_release_buffer(&new_stat, &status_string);
	    return AUTH_CONTINUE;
	}

	if (input.value) {
	    free(input.value);
	    input.value = NULL;
	    input.length = 0;
	}
	if (output_token.length != 0) {
	    base64_encode(output_token.value, output_token.length, &p);
	    gss_release_buffer(&min_stat, &output_token);
	    n = command("ADAT %s", p);
	    free(p);
	}
	if (GSS_ERROR(maj_stat)) {
	    if (d->context_hdl != GSS_C_NO_CONTEXT)
		gss_delete_sec_context (&min_stat,
					&d->context_hdl,
					GSS_C_NO_BUFFER);
	    break;
	}
	if (maj_stat & GSS_S_CONTINUE_NEEDED) {
	    p = strstr(reply_string, "ADAT=");
	    if(p == NULL){
		printf("Error: expected ADAT in reply. got: %s\n",
		       reply_string);
		if (bindings != GSS_C_NO_CHANNEL_BINDINGS)
		    free(bindings);
		return AUTH_ERROR;
	    } else {
		p+=5;
		input.value = malloc(strlen(p));
		input.length = base64_decode(p, input.value);
	    }
	} else {
	    if(code != 235) {
		printf("Unrecognized response code: %d\n", code);
		if (bindings != GSS_C_NO_CHANNEL_BINDINGS)
		    free(bindings);
		return AUTH_ERROR;
	    }
	    context_established = 1;
	}
    }

    gss_release_name(&min_stat, &target_name);

    if (bindings != GSS_C_NO_CHANNEL_BINDINGS)
	free(bindings);
    if (input.value)
	free(input.value);

    {
	gss_name_t targ_name;

	maj_stat = gss_inquire_context(&min_stat,
				       d->context_hdl,
				       NULL,
				       &targ_name,
				       NULL,
				       NULL,
				       NULL,
				       NULL,
				       NULL);
	if (GSS_ERROR(maj_stat) == 0) {
	    gss_buffer_desc name;
	    maj_stat = gss_display_name (&min_stat,
					 targ_name,
					 &name,
					 NULL);
	    if (GSS_ERROR(maj_stat) == 0) {
		printf("Authenticated to <%.*s>\n",
			(int)name.length,
			(char *)name.value);
		gss_release_buffer(&min_stat, &name);
	    }
	    gss_release_name(&min_stat, &targ_name);
	} else
	    printf("Failed to get gss name of peer.\n");
    }


    return AUTH_OK;
}
Esempio n. 10
0
static int
gss_adat(void *app_data, void *buf, size_t len)
{
    char *p = NULL;
    gss_buffer_desc input_token, output_token;
    OM_uint32 maj_stat, min_stat;
    gss_name_t client_name;
    struct gssapi_data *d = app_data;
    gss_channel_bindings_t bindings;

    if (ftp_do_gss_bindings) {
	bindings = malloc(sizeof(*bindings));
	if (bindings == NULL)
	    errx(1, "out of memory");

	sockaddr_to_gss_address (his_addr,
				 &bindings->initiator_addrtype,
				 &bindings->initiator_address);
	sockaddr_to_gss_address (ctrl_addr,
				 &bindings->acceptor_addrtype,
				 &bindings->acceptor_address);

	bindings->application_data.length = 0;
	bindings->application_data.value = NULL;
    } else
	bindings = GSS_C_NO_CHANNEL_BINDINGS;

    input_token.value = buf;
    input_token.length = len;

    maj_stat = gss_accept_sec_context (&min_stat,
				       &d->context_hdl,
				       GSS_C_NO_CREDENTIAL,
				       &input_token,
				       bindings,
				       &client_name,
				       NULL,
				       &output_token,
				       NULL,
				       NULL,
				       &d->delegated_cred_handle);

    if (bindings != GSS_C_NO_CHANNEL_BINDINGS)
	free(bindings);

    if(output_token.length) {
	if(base64_encode(output_token.value, output_token.length, &p) < 0) {
	    reply(535, "Out of memory base64-encoding.");
	    return -1;
	}
	gss_release_buffer(&min_stat, &output_token);
    }
    if(maj_stat == GSS_S_COMPLETE){
	d->client_name = client_name;
	client_name = GSS_C_NO_NAME;
	if(p)
	    reply(235, "ADAT=%s", p);
	else
	    reply(235, "ADAT Complete");
	sec_complete = 1;

    } else if(maj_stat == GSS_S_CONTINUE_NEEDED) {
	if(p)
	    reply(335, "ADAT=%s", p);
	else
	    reply(335, "OK, need more data");
    } else {
	OM_uint32 new_stat;
	OM_uint32 msg_ctx = 0;
	gss_buffer_desc status_string;
	gss_display_status(&new_stat,
			   min_stat,
			   GSS_C_MECH_CODE,
			   GSS_C_NO_OID,
			   &msg_ctx,
			   &status_string);
	syslog(LOG_ERR, "gss_accept_sec_context: %.*s",
	       (int)status_string.length,
	       (char*)status_string.value);
	gss_release_buffer(&new_stat, &status_string);
	reply(431, "Security resource unavailable");
    }

    if (client_name)
	gss_release_name(&min_stat, &client_name);
    free(p);
    return 0;
}
Esempio n. 11
0
NTSTATUS gssapi_obtain_pac_blob(TALLOC_CTX *mem_ctx,
				gss_ctx_id_t gssapi_context,
				gss_name_t gss_client_name,
				DATA_BLOB *pac_blob)
{
	NTSTATUS status;
	OM_uint32 gss_maj, gss_min;
#ifdef HAVE_GSS_GET_NAME_ATTRIBUTE
/*
 * gss_get_name_attribute() in MIT krb5 1.10.0 can return unintialized pac_display_buffer
 * and later gss_release_buffer() will crash on attempting to release it.
 *
 * So always initialize the buffer descriptors.
 *
 * See following links for more details:
 * http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=658514
 * http://krbdev.mit.edu/rt/Ticket/Display.html?user=guest&pass=guest&id=7087
 */
	gss_buffer_desc pac_buffer = {
		.value = NULL,
		.length = 0
	};
	gss_buffer_desc pac_display_buffer = {
		.value = NULL,
		.length = 0
	};
	gss_buffer_desc pac_name = {
		.value = discard_const("urn:mspac:"),
		.length = sizeof("urn:mspac:")-1
	};
	int more = -1;
	int authenticated = false;
	int complete = false;

	gss_maj = gss_get_name_attribute(
		&gss_min, gss_client_name, &pac_name,
		&authenticated, &complete,
		&pac_buffer, &pac_display_buffer, &more);

	if (gss_maj != 0) {
		gss_OID oid = discard_const(gss_mech_krb5);
		DBG_NOTICE("obtaining PAC via GSSAPI gss_get_name_attribute "
			   "failed: %s\n", gssapi_error_string(mem_ctx,
							       gss_maj, gss_min,
							       oid));
		return NT_STATUS_ACCESS_DENIED;
	} else if (authenticated && complete) {
		/* The PAC blob is returned directly */
		*pac_blob = data_blob_talloc(mem_ctx, pac_buffer.value,
					    pac_buffer.length);

		if (!pac_blob->data) {
			status = NT_STATUS_NO_MEMORY;
		} else {
			status = NT_STATUS_OK;
		}

		gss_maj = gss_release_buffer(&gss_min, &pac_buffer);
		gss_maj = gss_release_buffer(&gss_min, &pac_display_buffer);
		return status;
	} else {
		DEBUG(0, ("obtaining PAC via GSSAPI failed: authenticated: %s, complete: %s, more: %s\n",
			  authenticated ? "true" : "false",
			  complete ? "true" : "false",
			  more ? "true" : "false"));
		return NT_STATUS_ACCESS_DENIED;
	}

#elif defined(HAVE_GSS_INQUIRE_SEC_CONTEXT_BY_OID)
	gss_OID_desc pac_data_oid = {
		.elements = discard_const(EXTRACT_PAC_AUTHZ_DATA_FROM_SEC_CONTEXT_OID),
		.length = EXTRACT_PAC_AUTHZ_DATA_FROM_SEC_CONTEXT_OID_LENGTH
	};

	gss_buffer_set_t set = GSS_C_NO_BUFFER_SET;

	/* If we didn't have the routine to get a verified, validated
	 * PAC (supplied only by MIT at the time of writing), then try
	 * with the Heimdal OID (fetches the PAC directly and always
	 * validates) */
	gss_maj = gss_inquire_sec_context_by_oid(
				&gss_min, gssapi_context,
				&pac_data_oid, &set);

	/* First check for the error MIT gives for an unknown OID */
	if (gss_maj == GSS_S_UNAVAILABLE) {
		DEBUG(1, ("unable to obtain a PAC against this GSSAPI library.  "
			  "GSSAPI secured connections are available only with Heimdal or MIT Kerberos >= 1.8\n"));
	} else if (gss_maj != 0) {
		DEBUG(2, ("obtaining PAC via GSSAPI gss_inqiure_sec_context_by_oid (Heimdal OID) failed: %s\n",
			  gssapi_error_string(mem_ctx, gss_maj, gss_min, gss_mech_krb5)));
	} else {
		if (set == GSS_C_NO_BUFFER_SET) {
			DEBUG(0, ("gss_inquire_sec_context_by_oid returned unknown "
				  "data in results.\n"));
			return NT_STATUS_INTERNAL_ERROR;
		}

		/* The PAC blob is returned directly */
		*pac_blob = data_blob_talloc(mem_ctx, set->elements[0].value,
					    set->elements[0].length);
		if (!pac_blob->data) {
			status = NT_STATUS_NO_MEMORY;
		} else {
			status = NT_STATUS_OK;
		}

		gss_maj = gss_release_buffer_set(&gss_min, &set);
		return status;
	}
#else
	DEBUG(1, ("unable to obtain a PAC against this GSSAPI library.  "
		  "GSSAPI secured connections are available only with Heimdal or MIT Kerberos >= 1.8\n"));
#endif
	return NT_STATUS_ACCESS_DENIED;
}

NTSTATUS gssapi_get_session_key(TALLOC_CTX *mem_ctx,
				gss_ctx_id_t gssapi_context,
				DATA_BLOB *session_key, 
				uint32_t *keytype)
{
	OM_uint32 gss_min, gss_maj;
	gss_buffer_set_t set = GSS_C_NO_BUFFER_SET;

	gss_maj = gss_inquire_sec_context_by_oid(
				&gss_min, gssapi_context,
				&gse_sesskey_inq_oid, &set);
	if (gss_maj) {
		DEBUG(0, ("gss_inquire_sec_context_by_oid failed [%s]\n",
			  gssapi_error_string(mem_ctx,
					      gss_maj,
					      gss_min,
					      discard_const_p(struct gss_OID_desc_struct,
							      gss_mech_krb5))));
		return NT_STATUS_NO_USER_SESSION_KEY;
	}

	if ((set == GSS_C_NO_BUFFER_SET) ||
	    (set->count == 0)) {
#ifdef HAVE_GSSKRB5_GET_SUBKEY
		krb5_keyblock *subkey;
		gss_maj = gsskrb5_get_subkey(&gss_min,
					     gssapi_context,
					     &subkey);
		if (gss_maj != 0) {
			DEBUG(1, ("NO session key for this mech\n"));
			return NT_STATUS_NO_USER_SESSION_KEY;
		}
		if (session_key) {
			*session_key = data_blob_talloc(mem_ctx,
							KRB5_KEY_DATA(subkey), KRB5_KEY_LENGTH(subkey));
		}
		if (keytype) {
			*keytype = KRB5_KEY_TYPE(subkey);
		}
		krb5_free_keyblock(NULL /* should be krb5_context */, subkey);
		return NT_STATUS_OK;
#else
		DEBUG(0, ("gss_inquire_sec_context_by_oid didn't return any session key (and no alternative method available)\n"));
		return NT_STATUS_NO_USER_SESSION_KEY;
#endif
	}

	if (session_key) {
		*session_key = data_blob_talloc(mem_ctx, set->elements[0].value,
						set->elements[0].length);
	}

	if (keytype) {
		int diflen, i;
		const uint8_t *p;

		*keytype = 0;
		if (set->count < 2) {

#ifdef HAVE_GSSKRB5_GET_SUBKEY
			krb5_keyblock *subkey;
			gss_maj = gsskrb5_get_subkey(&gss_min,
						     gssapi_context,
						     &subkey);
			if (gss_maj == 0) {
				*keytype = KRB5_KEY_TYPE(subkey);
				krb5_free_keyblock(NULL /* should be krb5_context */, subkey);
			}
#endif
			gss_maj = gss_release_buffer_set(&gss_min, &set);
	
			return NT_STATUS_OK;

		} else if (memcmp(set->elements[1].value,
				  gse_sesskeytype_oid.elements,
				  gse_sesskeytype_oid.length) != 0) {
			/* Perhaps a non-krb5 session key */
			gss_maj = gss_release_buffer_set(&gss_min, &set);
			return NT_STATUS_OK;
		}
		p = (const uint8_t *)set->elements[1].value + gse_sesskeytype_oid.length;
		diflen = set->elements[1].length - gse_sesskeytype_oid.length;
		if (diflen <= 0) {
			gss_maj = gss_release_buffer_set(&gss_min, &set);
			return NT_STATUS_INVALID_PARAMETER;
		}
		for (i = 0; i < diflen; i++) {
			*keytype = (*keytype << 7) | (p[i] & 0x7f);
			if (i + 1 != diflen && (p[i] & 0x80) == 0) {
				gss_maj = gss_release_buffer_set(&gss_min, &set);
				return NT_STATUS_INVALID_PARAMETER;
			}
		}
	}

	gss_maj = gss_release_buffer_set(&gss_min, &set);
	return NT_STATUS_OK;
}


char *gssapi_error_string(TALLOC_CTX *mem_ctx,
			  OM_uint32 maj_stat, OM_uint32 min_stat,
			  const gss_OID mech)
{
	OM_uint32 disp_min_stat, disp_maj_stat;
	gss_buffer_desc maj_error_message;
	gss_buffer_desc min_error_message;
	char *maj_error_string, *min_error_string;
	OM_uint32 msg_ctx = 0;

	char *ret;

	maj_error_message.value = NULL;
	min_error_message.value = NULL;
	maj_error_message.length = 0;
	min_error_message.length = 0;

	disp_maj_stat = gss_display_status(&disp_min_stat, maj_stat,
					   GSS_C_GSS_CODE, mech,
					   &msg_ctx, &maj_error_message);
	if (disp_maj_stat != 0) {
		maj_error_message.value = NULL;
		maj_error_message.length = 0;
	}
	disp_maj_stat = gss_display_status(&disp_min_stat, min_stat,
					   GSS_C_MECH_CODE, mech,
					   &msg_ctx, &min_error_message);
	if (disp_maj_stat != 0) {
		min_error_message.value = NULL;
		min_error_message.length = 0;
	}

	maj_error_string = talloc_strndup(mem_ctx,
					  (char *)maj_error_message.value,
					  maj_error_message.length);

	min_error_string = talloc_strndup(mem_ctx,
					  (char *)min_error_message.value,
					  min_error_message.length);

	ret = talloc_asprintf(mem_ctx, "%s: %s",
				maj_error_string, min_error_string);

	talloc_free(maj_error_string);
	talloc_free(min_error_string);

	gss_release_buffer(&disp_min_stat, &maj_error_message);
	gss_release_buffer(&disp_min_stat, &min_error_message);

	return ret;
}
Esempio n. 12
0
static int
gss_auth(void *app_data, char *host)
{
    
    OM_uint32 maj_stat, min_stat;
    gss_name_t target_name;
    gss_buffer_desc input, output_token;
    int context_established = 0;
    char *p;
    int n;
    gss_channel_bindings_t bindings;
    struct gss_data *d = app_data;

    const char *knames[] = { "ftp", "host", NULL }, **kname = knames;
	    
    
    if(import_name(*kname++, host, &target_name))
	return AUTH_ERROR;

    input.length = 0;
    input.value = NULL;

    bindings = malloc(sizeof(*bindings));

    sockaddr_to_gss_address (myctladdr,
			     &bindings->initiator_addrtype,
			     &bindings->initiator_address);
    sockaddr_to_gss_address (hisctladdr,
			     &bindings->acceptor_addrtype,
			     &bindings->acceptor_address);

    bindings->application_data.length = 0;
    bindings->application_data.value = NULL;

    while(!context_established) {
       maj_stat = gss_init_sec_context(&min_stat,
					GSS_C_NO_CREDENTIAL,
					&d->context_hdl,
					target_name,
					GSS_C_NO_OID,
                                        GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG
                                          | GSS_C_DELEG_FLAG,
					0,
					bindings,
					&input,
					NULL,
					&output_token,
					NULL,
					NULL);
	if (GSS_ERROR(maj_stat)) {
	    OM_uint32 new_stat;
	    OM_uint32 msg_ctx = 0;
	    gss_buffer_desc status_string;

	    if(min_stat == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN && *kname != NULL) {
		if(import_name(*kname++, host, &target_name))
		    return AUTH_ERROR;
		continue;
	    }
	    
	    gss_display_status(&new_stat,
			       min_stat,
			       GSS_C_MECH_CODE,
			       GSS_C_NO_OID,
			       &msg_ctx,
			       &status_string);
	    printf("Error initializing security context: %s\n", 
		   (char*)status_string.value);
	    gss_release_buffer(&new_stat, &status_string);
	    return AUTH_CONTINUE;
	}

	gss_release_buffer(&min_stat, &input);
	if (output_token.length != 0) {
	    base64_encode(output_token.value, output_token.length, &p);
	    gss_release_buffer(&min_stat, &output_token);
	    n = ftp_cmd("ADAT %s", p);
	    free(p);
	}
	if (GSS_ERROR(maj_stat)) {
	    if (d->context_hdl != GSS_C_NO_CONTEXT)
		gss_delete_sec_context (&min_stat,
					&d->context_hdl,
					GSS_C_NO_BUFFER);
	    break;
	}
	if (maj_stat & GSS_S_CONTINUE_NEEDED) {
	    p = strstr(ftp->reply, "ADAT=");
	    if(p == NULL){
		printf("Error: expected ADAT in reply. got: %s\n",
		       ftp->reply);
		return AUTH_ERROR;
	    } else {
		p+=5;
		input.value = malloc(strlen(p));
		input.length = base64_decode(p, input.value);
	    }
	} else {
	    if(ftp->fullcode != 235) {
		printf("Unrecognized response code: %d\n", ftp->fullcode);
		return AUTH_ERROR;
	    }
	    context_established = 1;
	}
    }
    return AUTH_OK;
}
Esempio n. 13
0
static uint32_t NetSecurityNative_AcquireCredSpNego(uint32_t* minorStatus,
                                                    GssName* desiredName,
                                                    gss_cred_usage_t credUsage,
                                                    GssCredId** outputCredHandle)
{
    assert(minorStatus != NULL);
    assert(desiredName != NULL);
    assert(outputCredHandle != NULL);
    assert(*outputCredHandle == NULL);

#if HAVE_GSS_SPNEGO_MECHANISM
    gss_OID_set_desc gss_mech_spnego_OID_set_desc = {.count = 1, .elements = GSS_SPNEGO_MECHANISM};
#else
    gss_OID_set_desc gss_mech_spnego_OID_set_desc = {.count = 1, .elements = &gss_mech_spnego_OID_desc};
#endif
    uint32_t majorStatus = gss_acquire_cred(
        minorStatus, desiredName, 0, &gss_mech_spnego_OID_set_desc, credUsage, outputCredHandle, NULL, NULL);

    // call gss_set_cred_option with GSS_KRB5_CRED_NO_CI_FLAGS_X to support Kerberos Sign Only option from *nix client against a windows server
#if HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
    if (majorStatus == GSS_S_COMPLETE)
    {
        GssBuffer emptyBuffer = GSS_C_EMPTY_BUFFER;
        majorStatus = gss_set_cred_option(minorStatus, outputCredHandle, GSS_KRB5_CRED_NO_CI_FLAGS_X, &emptyBuffer);
    }
#endif

    return majorStatus;
}

uint32_t
NetSecurityNative_InitiateCredSpNego(uint32_t* minorStatus, GssName* desiredName, GssCredId** outputCredHandle)
{
    return NetSecurityNative_AcquireCredSpNego(minorStatus, desiredName, GSS_C_INITIATE, outputCredHandle);
}

uint32_t NetSecurityNative_DeleteSecContext(uint32_t* minorStatus, GssCtxId** contextHandle)
{
    assert(minorStatus != NULL);
    assert(contextHandle != NULL);

    return gss_delete_sec_context(minorStatus, contextHandle, GSS_C_NO_BUFFER);
}

static uint32_t NetSecurityNative_DisplayStatus(uint32_t* minorStatus,
                                                uint32_t statusValue,
                                                int statusType,
                                                PAL_GssBuffer* outBuffer)
{
    assert(minorStatus != NULL);
    assert(outBuffer != NULL);

    uint32_t messageContext = 0; // Must initialize to 0 before calling gss_display_status.
    GssBuffer gssBuffer = {.length = 0, .value = NULL};
    uint32_t majorStatus =
        gss_display_status(minorStatus, statusValue, statusType, GSS_C_NO_OID, &messageContext, &gssBuffer);

    NetSecurityNative_MoveBuffer(&gssBuffer, outBuffer);
    return majorStatus;
}

uint32_t
NetSecurityNative_DisplayMinorStatus(uint32_t* minorStatus, uint32_t statusValue, PAL_GssBuffer* outBuffer)
{
    return NetSecurityNative_DisplayStatus(minorStatus, statusValue, GSS_C_MECH_CODE, outBuffer);
}

uint32_t
NetSecurityNative_DisplayMajorStatus(uint32_t* minorStatus, uint32_t statusValue, PAL_GssBuffer* outBuffer)
{
    return NetSecurityNative_DisplayStatus(minorStatus, statusValue, GSS_C_GSS_CODE, outBuffer);
}

uint32_t
NetSecurityNative_ImportUserName(uint32_t* minorStatus, char* inputName, uint32_t inputNameLen, GssName** outputName)
{
    assert(minorStatus != NULL);
    assert(inputName != NULL);
    assert(outputName != NULL);
    assert(*outputName == NULL);

    GssBuffer inputNameBuffer = {.length = inputNameLen, .value = inputName};
    return gss_import_name(minorStatus, &inputNameBuffer, GSS_C_NT_USER_NAME, outputName);
}
Esempio n. 14
0
static void ssh_gssapi_log_error(int verb, const char *msg, int maj_stat){
    gss_buffer_desc buffer;
    OM_uint32 dummy, message_context;
    gss_display_status(&dummy,maj_stat,GSS_C_GSS_CODE, GSS_C_NO_OID, &message_context, &buffer);
    SSH_LOG(verb, "GSSAPI(%s): %s", msg, (const char *)buffer.value);
}
Esempio n. 15
0
static char *
gss_mk_err(OM_uint32 maj_stat, OM_uint32 min_stat, const char *preamble)
{
	gss_buffer_desc	 status;
	OM_uint32	 new_stat;
	OM_uint32	 cur_stat;
	OM_uint32	 msg_ctx = 0;
	OM_uint32	 ret;
	int		 type;
	size_t		 newlen;
	char		*str = NULL;
	char		*tmp = NULL;

	cur_stat = maj_stat;
	type = GSS_C_GSS_CODE;

	for (;;) {

		/*
		 * GSS_S_FAILURE produces a rather unhelpful message, so
		 * we skip straight to the mech specific error in this case.
		 */

		if (type == GSS_C_GSS_CODE && cur_stat == GSS_S_FAILURE) {
			type = GSS_C_MECH_CODE;
			cur_stat = min_stat;
		}

		ret = gss_display_status(&new_stat, cur_stat, type,
		    GSS_C_NO_OID, &msg_ctx, &status);

		if (GSS_ERROR(ret))
			return str;	/* XXXrcd: hmmm, not quite?? */

		if (str)
			newlen = strlen(str);
		else
			newlen = strlen(preamble);

		newlen += status.length + 3;

		tmp = str;
		str = malloc(newlen);

		if (!str) {
			gss_release_buffer(&new_stat, &status);
			return tmp;	/* XXXrcd: hmmm, not quite?? */
		}

		snprintf(str, newlen, "%s%s%.*s", tmp?tmp:preamble,
		    tmp?", ":": ", (int)status.length, (char *)status.value);

		gss_release_buffer(&new_stat, &status);
		free(tmp);

		/*
		 * If we are finished processing for maj_stat, then
		 * move onto min_stat.
		 */

		if (msg_ctx == 0 && type == GSS_C_GSS_CODE && min_stat != 0) {
			type = GSS_C_MECH_CODE;
			cur_stat = min_stat;
			continue;
		}

		if (msg_ctx == 0)
			break;
	}

	return str;
}
Esempio n. 16
0
char *auth_gssapi_server (authresponse_t responder,int argc,char *argv[])
{
  char *ret = NIL;
  char tmp[MAILTMPLEN];
  unsigned long maxsize = htonl (AUTH_GSSAPI_C_MAXSIZE);
  int conf;
  OM_uint32 smj,smn,dsmj,dsmn,flags;
  OM_uint32 mctx = 0;
  gss_name_t crname,name;
  gss_OID mech;
  gss_buffer_desc chal,resp,buf;
  gss_cred_id_t crd;
  gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
  gss_qop_t qop = GSS_C_QOP_DEFAULT;
				/* make service name */
  sprintf (tmp,"%s@%s",(char *) mail_parameters (NIL,GET_SERVICENAME,NIL),
	   tcp_serverhost ());
  buf.length = strlen (buf.value = tmp);
				/* acquire credentials */
  if ((gss_import_name (&smn,&buf,GSS_C_NT_HOSTBASED_SERVICE,&crname)) ==
      GSS_S_COMPLETE) {
    if ((smj = gss_acquire_cred (&smn,crname,0,NIL,GSS_C_ACCEPT,&crd,NIL,NIL))
	== GSS_S_COMPLETE) {
      if ((resp.value = (*responder) ("",0,(unsigned long *) &resp.length)) != NULL) {
	do {			/* negotiate authentication */
	  smj = gss_accept_sec_context (&smn,&ctx,crd,&resp,
					GSS_C_NO_CHANNEL_BINDINGS,&name,&mech,
					&chal,&flags,NIL,NIL);
				/* don't need response any more */
	  fs_give ((void **) &resp.value);
	  switch (smj) {	/* how did it go? */
	  case GSS_S_COMPLETE:	/* successful */
	  case GSS_S_CONTINUE_NEEDED:
	    if (chal.value) {	/* send challenge, get next response */
	      resp.value = (*responder) (chal.value,chal.length,
					 (unsigned long *) &resp.length);
	      gss_release_buffer (&smn,&chal);
	    }
	    break;
	  }
	}
	while (resp.value && resp.length && (smj == GSS_S_CONTINUE_NEEDED));

				/* successful exchange? */
	if ((smj == GSS_S_COMPLETE) &&
	    (gss_display_name (&smn,name,&buf,&mech) == GSS_S_COMPLETE)) {
				/* send security and size */
	  memcpy (resp.value = tmp,(void *) &maxsize,resp.length = 4);
	  tmp[0] = AUTH_GSSAPI_P_NONE;
	  if (gss_wrap (&smn,ctx,NIL,qop,&resp,&conf,&chal) == GSS_S_COMPLETE){
	    resp.value = (*responder) (chal.value,chal.length,
				       (unsigned long *) &resp.length);
	    gss_release_buffer (&smn,&chal);
	    if (gss_unwrap (&smn,ctx,&resp,&chal,&conf,&qop)==GSS_S_COMPLETE) {
				/* client request valid */
	      if (chal.value && (chal.length > 4) &&
		  (chal.length < (MAILTMPLEN - 1)) &&
		  memcpy (tmp,chal.value,chal.length) &&
		  (tmp[0] & AUTH_GSSAPI_P_NONE)) {
				/* tie off authorization ID */
		tmp[chal.length] = '\0';
		ret = kerberos_login (tmp+4,buf.value,argc,argv);
	      }
				/* done with user name */
	      gss_release_buffer (&smn,&chal);
	    }
				/* finished with response */
	    fs_give ((void **) &resp.value);
	  }
				/* don't need name buffer any more */
	  gss_release_buffer (&smn,&buf);
	}
				/* don't need client name any more */
	gss_release_name (&smn,&name);
				/* don't need context any more */
	if (ctx != GSS_C_NO_CONTEXT) gss_delete_sec_context (&smn,&ctx,NIL);
      }
				/* finished with credentials */
      gss_release_cred (&smn,&crd);
    }

    else {			/* can't acquire credentials! */
      if (gss_display_name (&dsmn,crname,&buf,&mech) == GSS_S_COMPLETE)
	SERVER_LOG ("Failed to acquire credentials for %s",buf.value);
      if (smj != GSS_S_FAILURE) do
	switch (dsmj = gss_display_status (&dsmn,smj,GSS_C_GSS_CODE,
					   GSS_C_NO_OID,&mctx,&resp)) {
	case GSS_S_COMPLETE:
	  mctx = 0;
	case GSS_S_CONTINUE_NEEDED:
	  SERVER_LOG ("Unknown GSSAPI failure: %s",resp.value);
	  gss_release_buffer (&dsmn,&resp);
	}
      while (dsmj == GSS_S_CONTINUE_NEEDED);
      do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE,
					    GSS_C_NO_OID,&mctx,&resp)) {
      case GSS_S_COMPLETE:
      case GSS_S_CONTINUE_NEEDED:
	SERVER_LOG ("GSSAPI mechanism status: %s",resp.value);
	gss_release_buffer (&dsmn,&resp);
      }
      while (dsmj == GSS_S_CONTINUE_NEEDED);
    }
				/* finished with credentials name */
    gss_release_name (&smn,&crname);
  }
  return ret;			/* return status */
}
Esempio n. 17
0
long auth_gssapi_client_work (authchallenge_t challenger,gss_buffer_desc chal,
			      authrespond_t responder,char *service,NETMBX *mb,
			      void *stream,char *user,kinit_t ki)
{
  char tmp[MAILTMPLEN];
  OM_uint32 smj,smn,dsmj,dsmn;
  OM_uint32 mctx = 0;
  gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
  gss_buffer_desc resp,buf;
  long i;
  int conf;
  gss_qop_t qop;
  gss_name_t crname = NIL;
  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
  void *data;
  long ret = NIL;
  sprintf (tmp,"%s@%s",service,mb->host);
  buf.length = strlen (buf.value = tmp);
				/* get service name */
  if (gss_import_name (&smn,&buf,GSS_C_NT_HOSTBASED_SERVICE,&crname) !=
       GSS_S_COMPLETE) {
    mm_log ("Can't import Kerberos service name",WARN);
    (*responder) (stream,NIL,0);
  }
  else {
    data = (*bn) (BLOCK_SENSITIVE,NIL);
				/* negotiate with KDC */
    smj = gss_init_sec_context (&smn,GSS_C_NO_CREDENTIAL,&ctx,crname,NIL,
				GSS_C_INTEG_FLAG | GSS_C_MUTUAL_FLAG |
				GSS_C_REPLAY_FLAG,0,GSS_C_NO_CHANNEL_BINDINGS,
				GSS_C_NO_BUFFER,NIL,&resp,NIL,NIL);
    (*bn) (BLOCK_NONSENSITIVE,data);

				/* while continuation needed */
    while (smj == GSS_S_CONTINUE_NEEDED) {
      if (chal.value) fs_give ((void **) &chal.value);
				/* send response, get next challenge */
      i = (*responder) (stream,resp.value,resp.length) &&
	(chal.value = (*challenger) (stream,(unsigned long *) &chal.length));
      gss_release_buffer (&smn,&resp);
      if (i) {			/* negotiate continuation with KDC */
	data = (*bn) (BLOCK_SENSITIVE,NIL);
	switch (smj =		/* make sure continuation going OK */
		gss_init_sec_context (&smn,GSS_C_NO_CREDENTIAL,&ctx,
				      crname,GSS_C_NO_OID,GSS_C_INTEG_FLAG |
				      GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,0,
				      GSS_C_NO_CHANNEL_BINDINGS,&chal,NIL,
				      &resp,NIL,NIL)) {
	case GSS_S_CONTINUE_NEEDED:
	case GSS_S_COMPLETE:
	  break;
	default:		/* error, don't need context any more */
	  gss_delete_sec_context (&smn,&ctx,NIL);
	}
	(*bn) (BLOCK_NONSENSITIVE,data);
      }
      else {			/* error in continuation */
	mm_log ("Error in negotiating Kerberos continuation",WARN);
	(*responder) (stream,NIL,0);
				/* don't need context any more */
	gss_delete_sec_context (&smn,&ctx,NIL);
	break;
      }
    }

    switch (smj) {		/* done - deal with final condition */
    case GSS_S_COMPLETE:
      if (chal.value) fs_give ((void **) &chal.value);
				/* get prot mechanisms and max size */
      if ((*responder) (stream,resp.value ? resp.value : "",resp.length) &&
	  (chal.value = (*challenger) (stream,(unsigned long *)&chal.length))&&
	  (gss_unwrap (&smn,ctx,&chal,&resp,&conf,&qop) == GSS_S_COMPLETE) &&
	  (resp.length >= 4) && (*((char *) resp.value) & AUTH_GSSAPI_P_NONE)){
				/* make copy of flags and length */
	memcpy (tmp,resp.value,4);
	gss_release_buffer (&smn,&resp);
				/* no session protection */
	tmp[0] = AUTH_GSSAPI_P_NONE;
				/* install user name */
	strcpy (tmp+4,strcpy (user,mb->user[0] ? mb->user : myusername ()));
	buf.value = tmp; buf.length = strlen (user) + 4;
				/* successful negotiation */
	switch (smj = gss_wrap (&smn,ctx,NIL,qop,&buf,&conf,&resp)) {
	case GSS_S_COMPLETE:
	  if ((*responder) (stream,resp.value,resp.length)) ret = T;
	  gss_release_buffer (&smn,&resp);
	  break;
	default:
	  do switch (dsmj = gss_display_status (&dsmn,smj,GSS_C_GSS_CODE,
						GSS_C_NO_OID,&mctx,&resp)) {
	  case GSS_S_COMPLETE:
	    mctx = 0;
	  case GSS_S_CONTINUE_NEEDED:
	    sprintf (tmp,"Unknown gss_wrap failure: %s",(char *) resp.value);
	    mm_log (tmp,WARN);
	    gss_release_buffer (&dsmn,&resp);
	  }
	  while (dsmj == GSS_S_CONTINUE_NEEDED);
	  do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE,
						GSS_C_NO_OID,&mctx,&resp)) {
	  case GSS_S_COMPLETE:
	  case GSS_S_CONTINUE_NEEDED:
	    sprintf (tmp,"GSSAPI mechanism status: %s",(char *) resp.value);
	    mm_log (tmp,WARN);
	    gss_release_buffer (&dsmn,&resp);
	  }
	  while (dsmj == GSS_S_CONTINUE_NEEDED);
	  (*responder) (stream,NIL,0);
	}
      }
				/* flush final challenge */
      if (chal.value) fs_give ((void **) &chal.value);
				/* don't need context any more */
      gss_delete_sec_context (&smn,&ctx,NIL);
      break;

    case GSS_S_CREDENTIALS_EXPIRED:
      if (chal.value) fs_give ((void **) &chal.value);
				/* retry if application kinits */
      if (ki && (*ki) (mb->host,"Kerberos credentials expired"))
	ret = auth_gssapi_client_work (challenger,chal,responder,service,mb,
				       stream,user,NIL);
      else {			/* application can't kinit */
	sprintf (tmp,"Kerberos credentials expired (try running kinit) for %s",
		 mb->host);
	mm_log (tmp,WARN);
	(*responder) (stream,NIL,0);
      }
      break;
    case GSS_S_FAILURE:
      if (chal.value) fs_give ((void **) &chal.value);
      do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE,
					    GSS_C_NO_OID,&mctx,&resp)) {
      case GSS_S_COMPLETE:	/* end of message, can kinit? */
	if (ki && kerberos_try_kinit (smn) &&
	    (*ki) (mb->host,(char *) resp.value)) {
	  gss_release_buffer (&dsmn,&resp);
	  ret = auth_gssapi_client_work (challenger,chal,responder,service,mb,
					 stream,user,NIL);
	  break;		/* done */
	}
	else (*responder) (stream,NIL,0);
      case GSS_S_CONTINUE_NEEDED:
	sprintf (tmp,kerberos_try_kinit (smn) ?
		 "Kerberos error: %.80s (try running kinit) for %.80s" :
		 "GSSAPI failure: %s for %.80s",(char *) resp.value,mb->host);
	mm_log (tmp,WARN);
	gss_release_buffer (&dsmn,&resp);
      } while (dsmj == GSS_S_CONTINUE_NEEDED);
      break;

    default:			/* miscellaneous errors */
      if (chal.value) fs_give ((void **) &chal.value);
      do switch (dsmj = gss_display_status (&dsmn,smj,GSS_C_GSS_CODE,
					    GSS_C_NO_OID,&mctx,&resp)) {
      case GSS_S_COMPLETE:
	mctx = 0;
      case GSS_S_CONTINUE_NEEDED:
	sprintf (tmp,"Unknown GSSAPI failure: %s",(char *) resp.value);
	mm_log (tmp,WARN);
	gss_release_buffer (&dsmn,&resp);
      }
      while (dsmj == GSS_S_CONTINUE_NEEDED);
      do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE,
					    GSS_C_NO_OID,&mctx,&resp)) {
      case GSS_S_COMPLETE:
      case GSS_S_CONTINUE_NEEDED:
	sprintf (tmp,"GSSAPI mechanism status: %s",(char *) resp.value);
	mm_log (tmp,WARN);
	gss_release_buffer (&dsmn,&resp);
      }
      while (dsmj == GSS_S_CONTINUE_NEEDED);
      (*responder) (stream,NIL,0);
      break;
    }
				/* finished with credentials name */
    if (crname) gss_release_name (&smn,&crname);
  }
  return ret;			/* return status */
}
Esempio n. 18
0
/* Acquire GSSAPI credentials and set up RPC auth flavor. */
static kadm5_ret_t
setup_gss(kadm5_server_handle_t handle, kadm5_config_params *params_in,
          krb5_principal client, krb5_principal server)
{
    OM_uint32 gssstat, minor_stat;
    gss_buffer_desc buf;
    gss_name_t gss_client;
    gss_name_t gss_target;
    gss_cred_id_t gss_client_creds;
    const char *c_ccname_orig;
    char *ccname_orig;

    gss_client_creds = GSS_C_NO_CREDENTIAL;
    ccname_orig = NULL;
    gss_client = gss_target = GSS_C_NO_NAME;

    /* Temporarily use the kadm5 cache. */
    gssstat = gss_krb5_ccache_name(&minor_stat, handle->cache_name,
                                   &c_ccname_orig);
    if (gssstat != GSS_S_COMPLETE)
        goto error;
    if (c_ccname_orig)
        ccname_orig = strdup(c_ccname_orig);
    else
        ccname_orig = 0;

    buf.value = &server;
    buf.length = sizeof(server);
    gssstat = gss_import_name(&minor_stat, &buf,
                              (gss_OID)gss_nt_krb5_principal, &gss_target);
    if (gssstat != GSS_S_COMPLETE)
        goto error;

    if (client != NULL) {
        buf.value = &client;
        buf.length = sizeof(client);
        gssstat = gss_import_name(&minor_stat, &buf,
                                  (gss_OID)gss_nt_krb5_principal, &gss_client);
    } else gss_client = GSS_C_NO_NAME;

    if (gssstat != GSS_S_COMPLETE)
        goto error;

    gssstat = gss_acquire_cred(&minor_stat, gss_client, 0,
                               GSS_C_NULL_OID_SET, GSS_C_INITIATE,
                               &gss_client_creds, NULL, NULL);
    if (gssstat != GSS_S_COMPLETE) {
#if 0 /* for debugging only */
        {
            OM_uint32 maj_status, min_status, message_context = 0;
            gss_buffer_desc status_string;
            do {
                maj_status = gss_display_status(&min_status,
                                                gssstat,
                                                GSS_C_GSS_CODE,
                                                GSS_C_NO_OID,
                                                &message_context,
                                                &status_string);
                if (maj_status == GSS_S_COMPLETE) {
                    fprintf(stderr, "MAJ: %.*s\n",
                            (int) status_string.length,
                            (char *)status_string.value);
                    gss_release_buffer(&min_status, &status_string);
                } else {
                    fprintf(stderr,
                            "MAJ? gss_display_status returns 0x%lx?!\n",
                            (unsigned long) maj_status);
                    message_context = 0;
                }
            } while (message_context != 0);
            do {
                maj_status = gss_display_status(&min_status,
                                                minor_stat,
                                                GSS_C_MECH_CODE,
                                                GSS_C_NO_OID,
                                                &message_context,
                                                &status_string);
                if (maj_status == GSS_S_COMPLETE) {
                    fprintf(stderr, "MIN: %.*s\n",
                            (int) status_string.length,
                            (char *)status_string.value);
                    gss_release_buffer(&min_status, &status_string);
                } else {
                    fprintf(stderr,
                            "MIN? gss_display_status returns 0x%lx?!\n",
                            (unsigned long) maj_status);
                    message_context = 0;
                }
            } while (message_context != 0);
        }
#endif
        goto error;
    }

    /*
     * Do actual creation of RPC auth handle.  Implements auth flavor
     * fallback.
     */
    rpc_auth(handle, params_in, gss_client_creds, gss_target);

error:
    if (gss_client_creds != GSS_C_NO_CREDENTIAL)
        (void) gss_release_cred(&minor_stat, &gss_client_creds);

    if (gss_client)
        gss_release_name(&minor_stat, &gss_client);
    if (gss_target)
        gss_release_name(&minor_stat, &gss_target);

    /* Revert to prior gss_krb5 ccache. */
    if (ccname_orig) {
        gssstat = gss_krb5_ccache_name(&minor_stat, ccname_orig, NULL);
        if (gssstat) {
            return KADM5_GSS_ERROR;
        }
        free(ccname_orig);
    } else {
        gssstat = gss_krb5_ccache_name(&minor_stat, NULL, NULL);
        if (gssstat) {
            return KADM5_GSS_ERROR;
        }
    }

    if (handle->clnt->cl_auth == NULL) {
        return KADM5_GSS_ERROR;
    }
    return 0;
}
Esempio n. 19
0
/*
 * Helper gssapi error functions.
 */
static int check_gss_err(struct SessionHandle *data,
                         OM_uint32 major_status,
                         OM_uint32 minor_status,
                         const char* function)
{
    if (GSS_ERROR(major_status))
    {
        OM_uint32 maj_stat, min_stat;
        OM_uint32 msg_ctx = 0;
        gss_buffer_desc status_string;
        char buf[1024];
        size_t len;

        len = 0;
        msg_ctx = 0;
        while (!msg_ctx)
        {
            /* convert major status code (GSS-API error) to text */
            maj_stat = gss_display_status(&min_stat, major_status,
                                          GSS_C_GSS_CODE,
                                          GSS_C_NULL_OID,
                                          &msg_ctx, &status_string);
            if (maj_stat == GSS_S_COMPLETE)
            {
                if (sizeof(buf) > len + status_string.length + 1)
                {
                    strcpy(buf + len, (char*) status_string.value);
                    len += status_string.length;
                }
                gss_release_buffer(&min_stat, &status_string);
                break;
            }
            gss_release_buffer(&min_stat, &status_string);
        }
        if (sizeof(buf) > len + 3)
        {
            strcpy(buf + len, ".\n");
            len += 2;
        }
        msg_ctx = 0;
        while (!msg_ctx)
        {
            /* convert minor status code (underlying routine error) to text */
            maj_stat = gss_display_status(&min_stat, minor_status,
                                          GSS_C_MECH_CODE,
                                          GSS_C_NULL_OID,
                                          &msg_ctx, &status_string);
            if (maj_stat == GSS_S_COMPLETE)
            {
                if (sizeof(buf) > len + status_string.length)
                {
                    strcpy(buf + len, (char*) status_string.value);
                    len += status_string.length;
                }
                gss_release_buffer(&min_stat, &status_string);
                break;
            }
            gss_release_buffer(&min_stat, &status_string);
        }
        failf(data, "GSSAPI error: %s failed:\n%s\n", function, buf);
        return(1);
    }

    return(0);
}
Esempio n. 20
0
static const char *
gssapi_strerror (OM_uint32 major_status,
                 OM_uint32 minor_status)
{
  static char buffer[1024];
  OM_uint32 major, minor;
  OM_uint32 ctx;
  gss_buffer_desc status;
  char *buf;
  size_t len;
  int had_major;
  int had_minor;

  debug ("gssapi: major_status: %8.8x, minor_status: %8.8x",
         major_status, minor_status);

  buf = buffer;
  len = sizeof (buffer);
  buf[0] = '\0';
  had_major = 0;
  ctx = 0;

  if (major_status != GSS_S_FAILURE || minor_status == 0)
    {
      for (;;)
        {
          major = gss_display_status (&minor, major_status, GSS_C_GSS_CODE,
                                      GSS_C_NO_OID, &ctx, &status);
          if (GSS_ERROR (major))
            break;

          if (had_major)
            build_string (&buf, &len, ": ", 2);
          had_major = 1;

          build_string (&buf, &len, status.value, status.length);
          gss_release_buffer (&minor, &status);

          if (!ctx)
            break;
        }
    }

   ctx = 0;
   had_minor = 0;
   for (;;)
     {
       major = gss_display_status (&minor, minor_status, GSS_C_MECH_CODE,
                                   GSS_C_NULL_OID, &ctx, &status);
       if (GSS_ERROR (major))
         break;

       if (had_minor)
         build_string (&buf, &len, ", ", 2);
       else if (had_major)
         build_string (&buf, &len, " (", 2);
       had_minor = 1;
       build_string (&buf, &len, status.value, status.length);

       gss_release_buffer (&minor, &status);

       if (!ctx)
         break;
     }

   if (had_major && had_minor)
     build_string (&buf, &len, ")", 1);

   return buffer;
}
Esempio n. 21
0
static
DWORD
LwGssGetSingleErrorMessage(
    OUT PSTR* ppszErrorMessage,
    IN OM_uint32 Status,
    IN BOOLEAN IsMajor
    )
{
    DWORD dwError = 0;
    PSTR pszErrorMessage = NULL;
    OM_uint32 majorStatus = 0;
    OM_uint32 minorStatus = 0;
    gss_buffer_desc message = GSS_C_EMPTY_BUFFER;
    OM_uint32 messageContext = 0;
    int statusType = IsMajor ? GSS_C_GSS_CODE : GSS_C_MECH_CODE;

    do {
        majorStatus = gss_display_status(
                            &minorStatus,
                            Status,
                            statusType,
                            GSS_C_NULL_OID,
                            &messageContext,
                            &message);
        if (majorStatus != GSS_S_COMPLETE)
        {
            LW_LOG_ERROR("Call to gss_display_status() failed with "
                         "majorStatus = 0x%08x, minorStatus = 0x%08x",
                         majorStatus, minorStatus);

            dwError = ERROR_INTERNAL_ERROR;
            BAIL_ON_LW_ERROR(dwError);
        }

        if (!pszErrorMessage)
        {
            dwError = LwAllocateString((PSTR)message.value, &pszErrorMessage);
            BAIL_ON_LW_ERROR(dwError);
        }
        else
        {
            PSTR pszNewErrorMessage = NULL;

            dwError = LwAllocateStringPrintf(&pszNewErrorMessage,
                                             "%s; %s",
                                             pszErrorMessage,
                                             (PSTR)message.value);
            BAIL_ON_LW_ERROR(dwError);

            LW_SAFE_FREE_STRING(pszErrorMessage);
            pszErrorMessage = pszNewErrorMessage;
        }

        majorStatus = gss_release_buffer(&minorStatus, &message);
    } while (messageContext);

error:
    if (dwError)
    {
        LW_SAFE_FREE_STRING(pszErrorMessage);
    }

    if (message.value)
    {
        majorStatus = gss_release_buffer(&minorStatus, &message);
    }

    *ppszErrorMessage = pszErrorMessage;

    return dwError;
}