Beispiel #1
0
static void test_cread_attrs(void)
{
    SCHANNEL_CRED schannel_cred;
    SECURITY_STATUS status;
    CredHandle cred;

    status = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND,
            NULL, NULL, NULL, NULL, &cred, NULL);
    ok(status == SEC_E_OK, "AcquireCredentialsHandleA failed: %x\n", status);

    test_supported_protocols(&cred, 0);
    test_supported_algs(&cred);

    status = pQueryCredentialsAttributesA(&cred, SECPKG_ATTR_SUPPORTED_PROTOCOLS, NULL);
    ok(status == SEC_E_INTERNAL_ERROR, "QueryCredentialsAttributes failed: %08x, expected SEC_E_INTERNAL_ERROR\n", status);

    status = pQueryCredentialsAttributesA(&cred, SECPKG_ATTR_SUPPORTED_ALGS, NULL);
    ok(status == SEC_E_INTERNAL_ERROR, "QueryCredentialsAttributes failed: %08x, expected SEC_E_INTERNAL_ERROR\n", status);

    pFreeCredentialsHandle(&cred);

    init_cred(&schannel_cred);
    schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT;
    status = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND,
            NULL, &schannel_cred, NULL, NULL, &cred, NULL);
    ok(status == SEC_E_OK, "AcquireCredentialsHandleA failed: %x\n", status);

    test_supported_protocols(&cred, SP_PROT_TLS1_CLIENT);
    test_supported_algs(&cred);

    pFreeCredentialsHandle(&cred);
}
Beispiel #2
0
/*
 * Create new allocation.
 */
PJ_DEF(pj_status_t) pj_turn_allocation_create(pj_turn_transport *transport,
					      const pj_sockaddr_t *src_addr,
					      unsigned src_addr_len,
					      const pj_stun_rx_data *rdata,
					      pj_stun_session *srv_sess,
					      pj_turn_allocation **p_alloc)
{
    pj_turn_srv *srv = transport->listener->server;
    const pj_stun_msg *msg = rdata->msg;
    pj_pool_t *pool;
    alloc_request req;
    pj_turn_allocation *alloc;
    pj_stun_session_cb sess_cb;
    char str_tmp[80];
    pj_status_t status;

    /* Parse ALLOCATE request */
    status = parse_allocate_req(&req, srv_sess, rdata, src_addr, src_addr_len);
    if (status != PJ_SUCCESS)
	return status;

    pool = pj_pool_create(srv->core.pf, "alloc%p", 1000, 1000, NULL);

    /* Init allocation structure */
    alloc = PJ_POOL_ZALLOC_T(pool, pj_turn_allocation);
    alloc->pool = pool;
    alloc->obj_name = pool->obj_name;
    alloc->relay.tp.sock = PJ_INVALID_SOCKET;
    alloc->server = transport->listener->server;

    alloc->bandwidth = req.bandwidth;

    /* Set transport */
    alloc->transport = transport;
    pj_turn_transport_add_ref(transport, alloc);

    alloc->hkey.tp_type = transport->listener->tp_type;
    pj_memcpy(&alloc->hkey.clt_addr, src_addr, src_addr_len);

    status = pj_lock_create_recursive_mutex(pool, alloc->obj_name,
					    &alloc->lock);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    /* Create peer hash table */
    alloc->peer_table = pj_hash_create(pool, PEER_TABLE_SIZE);

    /* Create channel hash table */
    alloc->ch_table = pj_hash_create(pool, PEER_TABLE_SIZE);

    /* Print info */
    pj_ansi_strcpy(alloc->info,
		   pj_turn_tp_type_name(transport->listener->tp_type));
    alloc->info[3] = ':';
    pj_sockaddr_print(src_addr, alloc->info+4, sizeof(alloc->info)-4, 3);

    /* Create STUN session to handle STUN communication with client */
    pj_bzero(&sess_cb, sizeof(sess_cb));
    sess_cb.on_send_msg = &stun_on_send_msg;
    sess_cb.on_rx_request = &stun_on_rx_request;
    sess_cb.on_rx_indication = &stun_on_rx_indication;
    status = pj_stun_session_create(&srv->core.stun_cfg, alloc->obj_name,
				    &sess_cb, PJ_FALSE, NULL, &alloc->sess);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    /* Attach to STUN session */
    pj_stun_session_set_user_data(alloc->sess, alloc);

    /* Init authentication credential */
    status = init_cred(alloc, msg);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    /* Attach authentication credential to STUN session */
    pj_stun_session_set_credential(alloc->sess, PJ_STUN_AUTH_LONG_TERM,
				   &alloc->cred);

    /* Create the relay resource */
    status = create_relay(srv, alloc, msg, &req, &alloc->relay);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    /* Register this allocation */
    pj_turn_srv_register_allocation(srv, alloc);

    /* Respond to ALLOCATE request */
    status = send_allocate_response(alloc, srv_sess, transport, rdata);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Done */
    pj_sockaddr_print(&alloc->relay.hkey.addr, str_tmp,
		      sizeof(str_tmp), 3);
    PJ_LOG(4,(alloc->obj_name, "Client %s created, relay addr=%s:%s",
	      alloc->info, pj_turn_tp_type_name(req.tp_type), str_tmp));

    /* Success */
    *p_alloc = alloc;
    return PJ_SUCCESS;

on_error:
    /* Send reply to the ALLOCATE request */
    pj_strerror(status, str_tmp, sizeof(str_tmp));
    pj_stun_session_respond(srv_sess, rdata, PJ_STUN_SC_BAD_REQUEST, str_tmp,
			    transport, PJ_TRUE, src_addr, src_addr_len);

    /* Cleanup */
    destroy_allocation(alloc);
    return status;
}
Beispiel #3
0
static void test_communication(void)
{
    int ret;

    WSADATA wsa_data;
    SOCKET sock;
    struct hostent *host;
    struct sockaddr_in addr;

    SECURITY_STATUS status;
    ULONG attrs;

    SCHANNEL_CRED cred;
    CredHandle cred_handle;
    CtxtHandle context;
    SecPkgCredentials_NamesA names;
    SecPkgContext_StreamSizes sizes;
    SecPkgContext_ConnectionInfo conn_info;
    CERT_CONTEXT *cert;

    SecBufferDesc buffers[2];
    SecBuffer *buf;
    unsigned buf_size = 4000;
    unsigned char *data;
    unsigned data_size;

    if (!pAcquireCredentialsHandleA || !pFreeCredentialsHandle ||
        !pInitializeSecurityContextA || !pDeleteSecurityContext ||
        !pQueryContextAttributesA || !pDecryptMessage || !pEncryptMessage)
    {
        skip("Required secur32 functions not available\n");
        return;
    }

    /* Create a socket and connect to www.winehq.org */
    ret = WSAStartup(0x0202, &wsa_data);
    if (ret)
    {
        skip("Can't init winsock 2.2\n");
        return;
    }

    host = gethostbyname("www.winehq.org");
    if (!host)
    {
        skip("Can't resolve www.winehq.org\n");
        return;
    }

    addr.sin_family = host->h_addrtype;
    addr.sin_addr = *(struct in_addr *)host->h_addr_list[0];
    addr.sin_port = htons(443);
    sock = socket(host->h_addrtype, SOCK_STREAM, 0);
    if (sock == SOCKET_ERROR)
    {
        skip("Can't create socket\n");
        return;
    }

    ret = connect(sock, (struct sockaddr *)&addr, sizeof(addr));
    if (ret == SOCKET_ERROR)
    {
        skip("Can't connect to www.winehq.org\n");
        return;
    }

    /* Create client credentials */
    init_cred(&cred);
    cred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT;
    cred.dwFlags = SCH_CRED_NO_DEFAULT_CREDS|SCH_CRED_MANUAL_CRED_VALIDATION;

    status = pAcquireCredentialsHandleA(NULL, (SEC_CHAR *)UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL,
        &cred, NULL, NULL, &cred_handle, NULL);
    ok(status == SEC_E_OK, "AcquireCredentialsHandleA failed: %08x\n", status);
    if (status != SEC_E_OK) return;

    /* Initialize the connection */
    init_buffers(&buffers[0], 4, buf_size);
    init_buffers(&buffers[1], 4, buf_size);

    buffers[0].pBuffers[0].BufferType = SECBUFFER_TOKEN;
    status = pInitializeSecurityContextA(&cred_handle, NULL, (SEC_CHAR *)"localhost",
        ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM,
        0, 0, NULL, 0, &context, &buffers[0], &attrs, NULL);
    ok(status == SEC_I_CONTINUE_NEEDED, "Expected SEC_I_CONTINUE_NEEDED, got %08x\n", status);

    buffers[1].cBuffers = 1;
    buffers[1].pBuffers[0].BufferType = SECBUFFER_TOKEN;
    buffers[0].pBuffers[0].cbBuffer = 1;
    memset(buffers[1].pBuffers[0].pvBuffer, 0xfa, buf_size);
    status = pInitializeSecurityContextA(&cred_handle, &context, (SEC_CHAR *)"localhost",
            ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM,
            0, 0, &buffers[1], 0, NULL, &buffers[0], &attrs, NULL);
todo_wine
    ok(status == SEC_E_INVALID_TOKEN, "Expected SEC_E_INVALID_TOKEN, got %08x\n", status);
todo_wine
    ok(buffers[0].pBuffers[0].cbBuffer == 0, "Output buffer size was not set to 0.\n");

    buffers[1].cBuffers = 1;
    buffers[1].pBuffers[0].BufferType = SECBUFFER_TOKEN;
    buffers[0].pBuffers[0].cbBuffer = 1;
    memset(buffers[1].pBuffers[0].pvBuffer, 0, buf_size);
    status = pInitializeSecurityContextA(&cred_handle, &context, (SEC_CHAR *)"localhost",
            ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM,
            0, 0, &buffers[1], 0, NULL, &buffers[0], &attrs, NULL);
    ok(status == SEC_E_INVALID_TOKEN, "Expected SEC_E_INVALID_TOKEN, got %08x\n", status);
todo_wine
    ok(buffers[0].pBuffers[0].cbBuffer == 0, "Output buffer size was not set to 0.\n");

    buffers[0].pBuffers[0].cbBuffer = 0;
    status = pInitializeSecurityContextA(&cred_handle, &context, (SEC_CHAR *)"localhost",
            ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM,
            0, 0, &buffers[1], 0, NULL, &buffers[0], &attrs, NULL);
todo_wine
    ok(status == SEC_E_INSUFFICIENT_MEMORY || status == SEC_E_INVALID_TOKEN,
       "Expected SEC_E_INSUFFICIENT_MEMORY or SEC_E_INVALID_TOKEN, got %08x\n", status);

    buffers[0].pBuffers[0].cbBuffer = buf_size;

    status = pInitializeSecurityContextA(&cred_handle, NULL, (SEC_CHAR *)"localhost",
            ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM,
            0, 0, NULL, 0, &context, &buffers[0], &attrs, NULL);
    ok(status == SEC_I_CONTINUE_NEEDED, "Expected SEC_I_CONTINUE_NEEDED, got %08x\n", status);

    buf = &buffers[0].pBuffers[0];
    send(sock, buf->pvBuffer, buf->cbBuffer, 0);
    buf->cbBuffer = buf_size;

    status = pInitializeSecurityContextA(&cred_handle, &context, (SEC_CHAR *)"localhost",
            ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM,
            0, 0, NULL, 0, NULL, &buffers[0], &attrs, NULL);
    ok(status == SEC_E_INCOMPLETE_MESSAGE, "Got unexpected status %#x.\n", status);
    ok(buffers[0].pBuffers[0].cbBuffer == buf_size, "Output buffer size changed.\n");
    ok(buffers[0].pBuffers[0].BufferType == SECBUFFER_TOKEN, "Output buffer type changed.\n");

    buffers[1].cBuffers = 4;
    buffers[1].pBuffers[0].cbBuffer = 0;

    status = pInitializeSecurityContextA(&cred_handle, &context, (SEC_CHAR *)"localhost",
            ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM,
            0, 0, &buffers[1], 0, NULL, &buffers[0], &attrs, NULL);
    ok(status == SEC_E_INCOMPLETE_MESSAGE, "Got unexpected status %#x.\n", status);
    ok(buffers[0].pBuffers[0].cbBuffer == buf_size, "Output buffer size changed.\n");
    ok(buffers[0].pBuffers[0].BufferType == SECBUFFER_TOKEN, "Output buffer type changed.\n");

    buf = &buffers[1].pBuffers[0];
    buf->cbBuffer = buf_size;
    ret = receive_data(sock, buf);
    if (ret == -1)
        return;

    buffers[1].pBuffers[0].cbBuffer = 4;
    status = pInitializeSecurityContextA(&cred_handle, &context, (SEC_CHAR *)"localhost",
            ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM,
            0, 0, &buffers[1], 0, NULL, &buffers[0], &attrs, NULL);
    ok(status == SEC_E_INCOMPLETE_MESSAGE, "Got unexpected status %#x.\n", status);
    ok(buffers[0].pBuffers[0].cbBuffer == buf_size, "Output buffer size changed.\n");
    ok(buffers[0].pBuffers[0].BufferType == SECBUFFER_TOKEN, "Output buffer type changed.\n");

    buffers[1].pBuffers[0].cbBuffer = 5;
    status = pInitializeSecurityContextA(&cred_handle, &context, (SEC_CHAR *)"localhost",
            ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM,
            0, 0, &buffers[1], 0, NULL, &buffers[0], &attrs, NULL);
    ok(status == SEC_E_INCOMPLETE_MESSAGE, "Got unexpected status %#x.\n", status);
    ok(buffers[0].pBuffers[0].cbBuffer == buf_size, "Output buffer size changed.\n");
    ok(buffers[0].pBuffers[0].BufferType == SECBUFFER_TOKEN, "Output buffer type changed.\n");

    buffers[1].pBuffers[0].cbBuffer = ret;
    status = pInitializeSecurityContextA(&cred_handle, &context, (SEC_CHAR *)"localhost",
            ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM,
            0, 0, &buffers[1], 0, NULL, &buffers[0], &attrs, NULL);
    buffers[1].pBuffers[0].cbBuffer = buf_size;
    while (status == SEC_I_CONTINUE_NEEDED)
    {
        buf = &buffers[0].pBuffers[0];
        send(sock, buf->pvBuffer, buf->cbBuffer, 0);
        buf->cbBuffer = buf_size;

        buf = &buffers[1].pBuffers[0];
        ret = receive_data(sock, buf);
        if (ret == -1)
            return;

        buf->BufferType = SECBUFFER_TOKEN;

        status = pInitializeSecurityContextA(&cred_handle, &context, (SEC_CHAR *)"localhost",
            ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM,
            0, 0, &buffers[1], 0, NULL, &buffers[0], &attrs, NULL);
        buffers[1].pBuffers[0].cbBuffer = buf_size;
    }

    ok(status == SEC_E_OK || broken(status == SEC_E_INVALID_TOKEN) /* WinNT */,
        "InitializeSecurityContext failed: %08x\n", status);
    if(status != SEC_E_OK) {
        win_skip("Handshake failed\n");
        return;
    }

    status = pQueryCredentialsAttributesA(&cred_handle, SECPKG_CRED_ATTR_NAMES, &names);
    ok(status == SEC_E_NO_CREDENTIALS || status == SEC_E_UNSUPPORTED_FUNCTION /* before Vista */, "expected SEC_E_NO_CREDENTIALS, got %08x\n", status);

    status = pQueryContextAttributesA(&context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&cert);
    ok(status == SEC_E_OK, "QueryContextAttributesW(SECPKG_ATTR_REMOTE_CERT_CONTEXT) failed: %08x\n", status);
    if(status == SEC_E_OK) {
        test_remote_cert(cert);
        CertFreeCertificateContext(cert);
    }

    status = pQueryContextAttributesA(&context, SECPKG_ATTR_CONNECTION_INFO, (void*)&conn_info);
    ok(status == SEC_E_OK, "QueryContextAttributesW(SECPKG_ATTR_CONNECTION_INFO) failed: %08x\n", status);
    if(status == SEC_E_OK) {
        ok(conn_info.dwCipherStrength >= 128, "conn_info.dwCipherStrength = %d\n", conn_info.dwCipherStrength);
        ok(conn_info.dwHashStrength >= 128, "conn_info.dwHashStrength = %d\n", conn_info.dwHashStrength);
    }

    status = pQueryContextAttributesA(&context, SECPKG_ATTR_STREAM_SIZES, &sizes);
    ok(status == SEC_E_OK, "QueryContextAttributesW(SECPKG_ATTR_STREAM_SIZES) failed: %08x\n", status);

    reset_buffers(&buffers[0]);

    /* Send a simple request so we get data for testing DecryptMessage */
    buf = &buffers[0].pBuffers[0];
    data = buf->pvBuffer;
    buf->BufferType = SECBUFFER_STREAM_HEADER;
    buf->cbBuffer = sizes.cbHeader;
    ++buf;
    buf->BufferType = SECBUFFER_DATA;
    buf->pvBuffer = data + sizes.cbHeader;
    buf->cbBuffer = sizeof(http_request) - 1;
    memcpy(buf->pvBuffer, http_request, sizeof(http_request) - 1);
    ++buf;
    buf->BufferType = SECBUFFER_STREAM_TRAILER;
    buf->pvBuffer = data + sizes.cbHeader + sizeof(http_request) -1;
    buf->cbBuffer = sizes.cbTrailer;

    status = pEncryptMessage(&context, 0, &buffers[0], 0);
    ok(status == SEC_E_OK, "EncryptMessage failed: %08x\n", status);
    if (status != SEC_E_OK)
        return;

    buf = &buffers[0].pBuffers[0];
    send(sock, buf->pvBuffer, buffers[0].pBuffers[0].cbBuffer + buffers[0].pBuffers[1].cbBuffer + buffers[0].pBuffers[2].cbBuffer, 0);

    reset_buffers(&buffers[0]);
    buf->cbBuffer = buf_size;
    data_size = receive_data(sock, buf);

    /* Too few buffers */
    --buffers[0].cBuffers;
    status = pDecryptMessage(&context, &buffers[0], 0, NULL);
    ok(status == SEC_E_INVALID_TOKEN, "Expected SEC_E_INVALID_TOKEN, got %08x\n", status);

    /* No data buffer */
    ++buffers[0].cBuffers;
    status = pDecryptMessage(&context, &buffers[0], 0, NULL);
    ok(status == SEC_E_INVALID_TOKEN, "Expected SEC_E_INVALID_TOKEN, got %08x\n", status);

    /* Two data buffers */
    buffers[0].pBuffers[0].BufferType = SECBUFFER_DATA;
    buffers[0].pBuffers[1].BufferType = SECBUFFER_DATA;
    status = pDecryptMessage(&context, &buffers[0], 0, NULL);
    ok(status == SEC_E_INVALID_TOKEN, "Expected SEC_E_INVALID_TOKEN, got %08x\n", status);

    /* Too few empty buffers */
    buffers[0].pBuffers[1].BufferType = SECBUFFER_EXTRA;
    status = pDecryptMessage(&context, &buffers[0], 0, NULL);
    ok(status == SEC_E_INVALID_TOKEN, "Expected SEC_E_INVALID_TOKEN, got %08x\n", status);

    /* Incomplete data */
    buffers[0].pBuffers[1].BufferType = SECBUFFER_EMPTY;
    buffers[0].pBuffers[0].cbBuffer = (data[3]<<8) | data[4];
    status = pDecryptMessage(&context, &buffers[0], 0, NULL);
    ok(status == SEC_E_INCOMPLETE_MESSAGE, "Expected SEC_E_INCOMPLETE_MESSAGE, got %08x\n", status);
    ok(buffers[0].pBuffers[0].BufferType == SECBUFFER_MISSING, "Expected first buffer to be SECBUFFER_MISSING\n");
    ok(buffers[0].pBuffers[0].cbBuffer == 5, "Expected first buffer to be a five bytes\n");

    buffers[0].pBuffers[0].cbBuffer = data_size;
    buffers[0].pBuffers[0].BufferType = SECBUFFER_DATA;
    buffers[0].pBuffers[1].BufferType = SECBUFFER_EMPTY;
    status = pDecryptMessage(&context, &buffers[0], 0, NULL);
    ok(status == SEC_E_OK, "DecryptMessage failed: %08x\n", status);
    if (status == SEC_E_OK)
    {
        ok(buffers[0].pBuffers[0].BufferType == SECBUFFER_STREAM_HEADER, "Expected first buffer to be SECBUFFER_STREAM_HEADER\n");
        ok(buffers[0].pBuffers[1].BufferType == SECBUFFER_DATA, "Expected second buffer to be SECBUFFER_DATA\n");
        ok(buffers[0].pBuffers[2].BufferType == SECBUFFER_STREAM_TRAILER, "Expected third buffer to be SECBUFFER_STREAM_TRAILER\n");

        data = buffers[0].pBuffers[1].pvBuffer;
        data[buffers[0].pBuffers[1].cbBuffer] = 0;
    }

    pDeleteSecurityContext(&context);
    pFreeCredentialsHandle(&cred_handle);

    free_buffers(&buffers[0]);
    free_buffers(&buffers[1]);

    closesocket(sock);
}
Beispiel #4
0
static krb5_error_code
get_init_creds_common(krb5_context context,
		      krb5_principal client,
		      krb5_deltat start_time,
		      krb5_get_init_creds_opt *options,
		      krb5_init_creds_context ctx)
{
    krb5_get_init_creds_opt *default_opt = NULL;
    krb5_error_code ret;
    krb5_enctype *etypes;
    krb5_preauthtype *pre_auth_types;

    memset(ctx, 0, sizeof(*ctx));

    if (options == NULL) {
	const char *realm = krb5_principal_get_realm(context, client);

        krb5_get_init_creds_opt_alloc (context, &default_opt);
	options = default_opt;
	krb5_get_init_creds_opt_set_default_flags(context, NULL, realm, options);
    }

    if (options->opt_private) {
	if (options->opt_private->password) {
	    ret = krb5_init_creds_set_password(context, ctx, 
					       options->opt_private->password);
	    if (ret)
		goto out;
	}

	ctx->keyproc = options->opt_private->key_proc;
	ctx->req_pac = options->opt_private->req_pac;
	ctx->pk_init_ctx = options->opt_private->pk_init_ctx;
	ctx->ic_flags = options->opt_private->flags;
    } else
	ctx->req_pac = KRB5_INIT_CREDS_TRISTATE_UNSET;

    if (ctx->keyproc == NULL)
	ctx->keyproc = default_s2k_func;

    /* Enterprise name implicitly turns on canonicalize */
    if ((ctx->ic_flags & KRB5_INIT_CREDS_CANONICALIZE) || 
	krb5_principal_get_type(context, client) == KRB5_NT_ENTERPRISE_PRINCIPAL)
	ctx->flags.canonicalize = 1;

    ctx->pre_auth_types = NULL;
    ctx->addrs = NULL;
    ctx->etypes = NULL;
    ctx->pre_auth_types = NULL;

    ret = init_cred(context, &ctx->cred, client, start_time, options);
    if (ret) {
	if (default_opt)
	    krb5_get_init_creds_opt_free(context, default_opt);
	return ret;
    }

    ret = krb5_init_creds_set_service(context, ctx, NULL);
    if (ret)
	goto out;

    if (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE)
	ctx->flags.forwardable = options->forwardable;

    if (options->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE)
	ctx->flags.proxiable = options->proxiable;

    if (start_time)
	ctx->flags.postdated = 1;
    if (ctx->cred.times.renew_till)
	ctx->flags.renewable = 1;
    if (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST) {
	ctx->addrs = options->address_list;
    } else if (options->opt_private) {
	switch (options->opt_private->addressless) {
	case KRB5_INIT_CREDS_TRISTATE_UNSET:
#if KRB5_ADDRESSLESS_DEFAULT == TRUE
	    ctx->addrs = &no_addrs;
#else
	    ctx->addrs = NULL;
#endif
	    break;
	case KRB5_INIT_CREDS_TRISTATE_FALSE:
	    ctx->addrs = NULL;
	    break;
	case KRB5_INIT_CREDS_TRISTATE_TRUE:
	    ctx->addrs = &no_addrs;
	    break;
	}
    }
    if (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST) {
	etypes = malloc((options->etype_list_length + 1)
			* sizeof(krb5_enctype));
	if (etypes == NULL) {
	    ret = ENOMEM;
	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
	    goto out;
	}
	memcpy (etypes, options->etype_list,
		options->etype_list_length * sizeof(krb5_enctype));
	etypes[options->etype_list_length] = ETYPE_NULL;
	ctx->etypes = etypes;
    }
    if (options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST) {
	pre_auth_types = malloc((options->preauth_list_length + 1)
				* sizeof(krb5_preauthtype));
	if (pre_auth_types == NULL) {
	    ret = ENOMEM;
	    krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
	    goto out;
	}
	memcpy (pre_auth_types, options->preauth_list,
		options->preauth_list_length * sizeof(krb5_preauthtype));
	pre_auth_types[options->preauth_list_length] = KRB5_PADATA_NONE;
	ctx->pre_auth_types = pre_auth_types;
    }
    if (options->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS)
	ctx->flags.request_anonymous = options->anonymous;
    if (default_opt)
        krb5_get_init_creds_opt_free(context, default_opt);
    return 0;
 out:
    if (default_opt)
	krb5_get_init_creds_opt_free(context, default_opt);
    return ret;
}