Exemple #1
0
static krb5_error_code
mspac_import_authdata(krb5_context kcontext,
                      krb5_authdata_context context,
                      void *plugin_context,
                      void *request_context,
                      krb5_authdata **authdata,
                      krb5_boolean kdc_issued,
                      krb5_const_principal kdc_issuer)
{
    krb5_error_code code;
    struct mspac_context *pacctx = (struct mspac_context *)request_context;

    if (kdc_issued)
        return EINVAL;

    if (pacctx->pac != NULL) {
        krb5_pac_free(kcontext, pacctx->pac);
        pacctx->pac = NULL;
    }

    assert(authdata[0] != NULL);
    assert((authdata[0]->ad_type & AD_TYPE_FIELD_TYPE_MASK) ==
           KRB5_AUTHDATA_WIN2K_PAC);

    code = krb5_pac_parse(kcontext, authdata[0]->contents,
                          authdata[0]->length, &pacctx->pac);

    return code;
}
Exemple #2
0
static krb5_error_code
mspac_export_internal(krb5_context kcontext,
                      krb5_authdata_context context,
                      void *plugin_context,
                      void *request_context,
                      krb5_boolean restrict_authenticated,
                      void **ptr)
{
    struct mspac_context *pacctx = (struct mspac_context *)request_context;
    krb5_error_code code;
    krb5_pac pac;

    *ptr = NULL;

    if (pacctx->pac == NULL)
        return ENOENT;

    if (restrict_authenticated && (pacctx->pac->verified) == FALSE)
        return ENOENT;

    code = krb5_pac_parse(kcontext, pacctx->pac->data.data,
                          pacctx->pac->data.length, &pac);
    if (code == 0) {
        pac->verified = pacctx->pac->verified;
        *ptr = pac;
    }

    return code;
}
Exemple #3
0
static int mit_samba_update_pac_data(struct mit_samba_context *ctx,
				     hdb_entry_ex *client,
				     DATA_BLOB *pac_data,
				     DATA_BLOB *logon_data)
{
	TALLOC_CTX *tmp_ctx;
	DATA_BLOB *logon_blob;
	krb5_error_code code;
	NTSTATUS nt_status;
	krb5_pac pac = NULL;
	int ret;

	/* The user account may be set not to want the PAC */
    	if (client && !samba_princ_needs_pac(client)) {
		return EINVAL;
	}

	tmp_ctx = talloc_named(ctx, 0, "mit_samba_update_pac_data context");
	if (!tmp_ctx) {
		return ENOMEM;
	}

	logon_blob = talloc_zero(tmp_ctx, DATA_BLOB);
	if (!logon_blob) {
		ret = ENOMEM;
		goto done;
	}

	code = krb5_pac_parse(ctx->context,
			      pac_data->data, pac_data->length, &pac);
	if (code) {
		ret = EINVAL;
		goto done;
	}

	nt_status = samba_kdc_update_pac_blob(tmp_ctx, ctx->context,
					      &pac, logon_blob);
	if (!NT_STATUS_IS_OK(nt_status)) {
		DEBUG(0, ("Building PAC failed: %s\n",
			  nt_errstr(nt_status)));
		ret = EINVAL;
		goto done;
	}

	logon_data->data = (uint8_t *)malloc(logon_blob->length);
	if (!logon_data->data) {
		ret = ENOMEM;
		goto done;
	}
	memcpy(logon_data->data, logon_blob->data, logon_blob->length);
	logon_data->length = logon_blob->length;

	ret = 0;

done:
	if (pac) krb5_pac_free(ctx->context, pac);
	talloc_free(tmp_ctx);
	return ret;
}
Exemple #4
0
static krb5_error_code
mspac_internalize(krb5_context kcontext,
                  krb5_authdata_context context,
                  void *plugin_context,
                  void *request_context,
                  krb5_octet **buffer,
                  size_t *lenremain)
{
    struct mspac_context *pacctx = (struct mspac_context *)request_context;
    krb5_error_code code;
    krb5_int32 ibuf;
    krb5_octet *bp;
    size_t remain;
    krb5_pac pac = NULL;

    bp = *buffer;
    remain = *lenremain;

    /* length */
    code = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
    if (code != 0)
        return code;

    if (ibuf != 0) {
        code = krb5_pac_parse(kcontext, bp, ibuf, &pac);
        if (code != 0)
            return code;

        bp += ibuf;
        remain -= ibuf;
    }

    /* verified */
    code = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
    if (code != 0) {
        krb5_pac_free(kcontext, pac);
        return code;
    }

    if (pac != NULL) {
        pac->verified = (ibuf != 0);
    }

    if (pacctx->pac != NULL) {
        krb5_pac_free(kcontext, pacctx->pac);
    }

    pacctx->pac = pac;

    *buffer = bp;
    *lenremain = remain;

    return 0;
}
Exemple #5
0
NTSTATUS kerberos_pac_blob_to_server_info(TALLOC_CTX *mem_ctx,
						     struct smb_iconv_convenience *iconv_convenience,
						     DATA_BLOB pac_blob, 
						     krb5_context context,
						     struct auth_serversupplied_info **server_info) 
{
	krb5_error_code ret;
	krb5_pac pac;
	ret = krb5_pac_parse(context, 
			     pac_blob.data, pac_blob.length, 
			     &pac);
	if (ret) {
		return map_nt_error_from_unix(ret);
	}


	ret = kerberos_pac_to_server_info(mem_ctx, iconv_convenience, pac, context, server_info);
	krb5_pac_free(context, pac);
	if (ret) {
		return map_nt_error_from_unix(ret);
	}
	return NT_STATUS_OK;
}
Exemple #6
0
NTSTATUS kerberos_pac_blob_to_user_info_dc(TALLOC_CTX *mem_ctx,
					   DATA_BLOB pac_blob,
					   krb5_context context,
					   struct auth_user_info_dc **user_info_dc,
					   struct PAC_SIGNATURE_DATA *pac_srv_sig,
					   struct PAC_SIGNATURE_DATA *pac_kdc_sig)
{
	krb5_error_code ret;
	krb5_pac pac;
	ret = krb5_pac_parse(context,
			     pac_blob.data, pac_blob.length,
			     &pac);
	if (ret) {
		return map_nt_error_from_unix_common(ret);
	}


	ret = kerberos_pac_to_user_info_dc(mem_ctx, pac, context, user_info_dc, pac_srv_sig, pac_kdc_sig);
	krb5_pac_free(context, pac);
	if (ret) {
		return map_nt_error_from_unix_common(ret);
	}
	return NT_STATUS_OK;
}
Exemple #7
0
static krb5_error_code
mspac_set_attribute(krb5_context kcontext,
                    krb5_authdata_context context,
                    void *plugin_context,
                    void *request_context,
                    krb5_boolean complete,
                    const krb5_data *attribute,
                    const krb5_data *value)
{
    struct mspac_context *pacctx = (struct mspac_context *)request_context;
    krb5_error_code code;
    krb5_ui_4 type;

    if (pacctx->pac == NULL)
        return ENOENT;

    code = mspac_attr2type(attribute, &type);
    if (code != 0)
        return code;

    /* -1 is a magic type that refers to the entire PAC */
    if (type == (krb5_ui_4)-1) {
        krb5_pac newpac;

        code = krb5_pac_parse(kcontext, value->data, value->length, &newpac);
        if (code != 0)
            return code;

        krb5_pac_free(kcontext, pacctx->pac);
        pacctx->pac = newpac;
    } else {
        code = krb5_pac_add_buffer(kcontext, pacctx->pac, type, value);
    }

    return code;
}
Exemple #8
0
static int mit_samba_update_pac_data(struct mit_samba_context *ctx,
				     hdb_entry_ex *client,
				     DATA_BLOB *pac_data,
				     DATA_BLOB *logon_data)
{
	TALLOC_CTX *tmp_ctx;
	DATA_BLOB *logon_blob;
	krb5_error_code code;
	NTSTATUS nt_status;
	krb5_pac pac = NULL;
	int ret;
	struct samba_kdc_entry *skdc_entry = NULL;

	if (client) {
		skdc_entry = talloc_get_type_abort(client->ctx,
						   struct samba_kdc_entry);
	}

	/* The user account may be set not to want the PAC */
	if (client && !samba_princ_needs_pac(skdc_entry)) {
		return EINVAL;
	}

	tmp_ctx = talloc_named(ctx, 0, "mit_samba_update_pac_data context");
	if (!tmp_ctx) {
		return ENOMEM;
	}

	logon_blob = talloc_zero(tmp_ctx, DATA_BLOB);
	if (!logon_blob) {
		ret = ENOMEM;
		goto done;
	}

	code = krb5_pac_parse(ctx->context,
			      pac_data->data, pac_data->length, &pac);
	if (code) {
		ret = EINVAL;
		goto done;
	}

	/* TODO: An implementation-specific decision will need to be
	 * made as to when to check the KDC pac signature, and how to
	 * untrust untrusted RODCs */
	nt_status = samba_kdc_update_pac_blob(tmp_ctx, ctx->context,
					      pac, logon_blob, NULL, NULL);
	if (!NT_STATUS_IS_OK(nt_status)) {
		DEBUG(0, ("Building PAC failed: %s\n",
			  nt_errstr(nt_status)));
		ret = EINVAL;
		goto done;
	}

	logon_data->data = (uint8_t *)malloc(logon_blob->length);
	if (!logon_data->data) {
		ret = ENOMEM;
		goto done;
	}
	memcpy(logon_data->data, logon_blob->data, logon_blob->length);
	logon_data->length = logon_blob->length;

	ret = 0;

done:
	if (pac) krb5_pac_free(ctx->context, pac);
	talloc_free(tmp_ctx);
	return ret;
}
Exemple #9
0
static krb5_error_code
check_PAC(krb5_context context,
	  krb5_kdc_configuration *config,
	  const krb5_principal client_principal,
	  hdb_entry_ex *client,
	  hdb_entry_ex *server,
	  const EncryptionKey *server_key,
	  const EncryptionKey *krbtgt_key,
	  EncTicketPart *tkt,
	  krb5_data *rspac,
	  int *require_signedpath)
{
    AuthorizationData *ad = tkt->authorization_data;
    unsigned i, j;
    krb5_error_code ret;

    if (ad == NULL || ad->len == 0)
	return 0;

    for (i = 0; i < ad->len; i++) {
	AuthorizationData child;

	if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
	    continue;

	ret = decode_AuthorizationData(ad->val[i].ad_data.data,
				       ad->val[i].ad_data.length,
				       &child,
				       NULL);
	if (ret) {
	    krb5_set_error_string(context, "Failed to decode "
				  "IF_RELEVANT with %d", ret);
	    return ret;
	}
	for (j = 0; j < child.len; j++) {

	    if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
		krb5_pac pac;

		/* Found PAC */
		ret = krb5_pac_parse(context,
				     child.val[j].ad_data.data,
				     child.val[j].ad_data.length,
				     &pac);
		free_AuthorizationData(&child);
		if (ret)
		    return ret;

		ret = krb5_pac_verify(context, pac, tkt->authtime, 
				      client_principal,
				      krbtgt_key, NULL);
		if (ret) {
		    krb5_pac_free(context, pac);
		    return ret;
		}

		ret = _kdc_pac_verify(context, client_principal, 
				      client, server, &pac);
		if (ret) {
		    krb5_pac_free(context, pac);
		    return ret;
		}
		*require_signedpath = 0;

		ret = _krb5_pac_sign(context, pac, tkt->authtime,
				     client_principal,
				     server_key, krbtgt_key, rspac);

		krb5_pac_free(context, pac);

		return ret;
	    }
	}
	free_AuthorizationData(&child);
    }
    return 0;
}
Exemple #10
0
static void
test_ap(krb5_context context,
	krb5_principal target,
	krb5_principal server,
	krb5_keytab keytab,
	krb5_ccache ccache,
	const krb5_flags client_flags)
{
    krb5_error_code ret;
    krb5_auth_context client_ac = NULL, server_ac = NULL;
    krb5_data data;
    krb5_flags server_flags;
    krb5_ticket *ticket = NULL;
    int32_t server_seq, client_seq;

    ret = krb5_mk_req_exact(context,
			    &client_ac,
			    client_flags,
			    target,
			    NULL,
			    ccache,
			    &data);
    if (ret)
	krb5_err(context, 1, ret, "krb5_mk_req_exact");

    ret = krb5_rd_req(context,
		      &server_ac,
		      &data,
		      server,
		      keytab,
		      &server_flags,
		      &ticket);
    if (ret)
	krb5_err(context, 1, ret, "krb5_rd_req");


    if (server_flags & AP_OPTS_MUTUAL_REQUIRED) {
	krb5_ap_rep_enc_part *repl;

	krb5_data_free(&data);

	if ((client_flags & AP_OPTS_MUTUAL_REQUIRED) == 0)
	    krb5_errx(context, 1, "client flag missing mutual req");

	ret = krb5_mk_rep (context, server_ac, &data);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_mk_rep");

	ret = krb5_rd_rep (context,
			   client_ac,
			   &data,
			   &repl);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_rd_rep");

	krb5_free_ap_rep_enc_part (context, repl);
    } else {
	if (client_flags & AP_OPTS_MUTUAL_REQUIRED)
	    krb5_errx(context, 1, "server flag missing mutual req");
    }

    krb5_auth_con_getremoteseqnumber(context, server_ac, &server_seq);
    krb5_auth_con_getremoteseqnumber(context, client_ac, &client_seq);
    if (server_seq != client_seq)
	krb5_errx(context, 1, "seq num differ");

    krb5_auth_con_getlocalseqnumber(context, server_ac, &server_seq);
    krb5_auth_con_getlocalseqnumber(context, client_ac, &client_seq);
    if (server_seq != client_seq)
	krb5_errx(context, 1, "seq num differ");

    krb5_data_free(&data);
    krb5_auth_con_free(context, client_ac);
    krb5_auth_con_free(context, server_ac);

    if (verify_pac) {
	krb5_pac pac;

	ret = krb5_ticket_get_authorization_data_type(context,
						      ticket,
						      KRB5_AUTHDATA_WIN2K_PAC,
						      &data);
	if (ret)
	    krb5_err(context, 1, ret, "get pac");

	ret = krb5_pac_parse(context, data.data, data.length, &pac);
	if (ret)
	    krb5_err(context, 1, ret, "pac parse");

	krb5_pac_free(context, pac);
    }

    krb5_free_ticket(context, ticket);
}
Exemple #11
0
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_rd_req_ctx(krb5_context context,
		krb5_auth_context *auth_context,
		const krb5_data *inbuf,
		krb5_const_principal server,
		krb5_rd_req_in_ctx inctx,
		krb5_rd_req_out_ctx *outctx)
{
    krb5_error_code ret;
    krb5_ap_req ap_req;
    krb5_rd_req_out_ctx o = NULL;
    krb5_keytab id = NULL, keytab = NULL;
    krb5_principal service = NULL;

    *outctx = NULL;

    o = calloc(1, sizeof(*o));
    if (o == NULL) {
	krb5_set_error_message(context, ENOMEM,
			       N_("malloc: out of memory", ""));
	return ENOMEM;
    }

    if (*auth_context == NULL) {
	ret = krb5_auth_con_init(context, auth_context);
	if (ret)
	    goto out;
    }

    ret = krb5_decode_ap_req(context, inbuf, &ap_req);
    if(ret)
	goto out;

    /* Save that principal that was in the request */
    ret = _krb5_principalname2krb5_principal(context,
					     &o->server,
					     ap_req.ticket.sname,
					     ap_req.ticket.realm);
    if (ret)
	goto out;

    if (ap_req.ap_options.use_session_key &&
	(*auth_context)->keyblock == NULL) {
	ret = KRB5KRB_AP_ERR_NOKEY;
	krb5_set_error_message(context, ret,
			       N_("krb5_rd_req: user to user auth "
				  "without session key given", ""));
	goto out;
    }

    if (inctx && inctx->keytab)
	id = inctx->keytab;

    if((*auth_context)->keyblock){
	ret = krb5_copy_keyblock(context,
				 (*auth_context)->keyblock,
				 &o->keyblock);
	if (ret)
	    goto out;
    } else if(inctx && inctx->keyblock){
	ret = krb5_copy_keyblock(context,
				 inctx->keyblock,
				 &o->keyblock);
	if (ret)
	    goto out;
    } else {

	if(id == NULL) {
	    krb5_kt_default(context, &keytab);
	    id = keytab;
	}
	if (id == NULL)
	    goto out;

	if (server == NULL) {
	    ret = _krb5_principalname2krb5_principal(context,
						     &service,
						     ap_req.ticket.sname,
						     ap_req.ticket.realm);
	    if (ret)
		goto out;
	    server = service;
	}

	ret = get_key_from_keytab(context,
				  &ap_req,
				  server,
				  id,
				  &o->keyblock);
	if (ret) {
	    /* If caller specified a server, fail. */
	    if (service == NULL && (context->flags & KRB5_CTX_F_RD_REQ_IGNORE) == 0)
		goto out;
	    /* Otherwise, fall back to iterating over the keytab. This
	     * have serious performace issues for larger keytab.
	     */
	    o->keyblock = NULL;
	}
    }

    if (o->keyblock) {
	/*
	 * We got an exact keymatch, use that.
	 */

	ret = krb5_verify_ap_req2(context,
				  auth_context,
				  &ap_req,
				  server,
				  o->keyblock,
				  0,
				  &o->ap_req_options,
				  &o->ticket,
				  KRB5_KU_AP_REQ_AUTH);

	if (ret)
	    goto out;

    } else {
	/*
	 * Interate over keytab to find a key that can decrypt the request.
	 */

	krb5_keytab_entry entry;
	krb5_kt_cursor cursor;
	int done = 0, kvno = 0;

	memset(&cursor, 0, sizeof(cursor));

	if (ap_req.ticket.enc_part.kvno)
	    kvno = *ap_req.ticket.enc_part.kvno;

	ret = krb5_kt_start_seq_get(context, id, &cursor);
	if (ret)
	    goto out;

	done = 0;
	while (!done) {
	    krb5_principal p;

	    ret = krb5_kt_next_entry(context, id, &entry, &cursor);
	    if (ret) {
		_krb5_kt_principal_not_found(context, ret, id, o->server,
					     ap_req.ticket.enc_part.etype,
					     kvno);
		krb5_kt_end_seq_get(context, id, &cursor);
		goto out;
	    }

	    if (entry.keyblock.keytype != ap_req.ticket.enc_part.etype) {
		krb5_kt_free_entry (context, &entry);
		continue;
	    }

	    ret = krb5_verify_ap_req2(context,
				      auth_context,
				      &ap_req,
				      server,
				      &entry.keyblock,
				      0,
				      &o->ap_req_options,
				      &o->ticket,
				      KRB5_KU_AP_REQ_AUTH);
	    if (ret) {
		krb5_kt_free_entry(context, &entry);
		continue;
	    }

	    /*
	     * Found a match, save the keyblock for PAC processing,
	     * and update the service principal in the ticket to match
	     * whatever is in the keytab.
	     */

	    ret = krb5_copy_keyblock(context,
				     &entry.keyblock,
				     &o->keyblock);
	    if (ret) {
		krb5_kt_free_entry(context, &entry);
		krb5_kt_end_seq_get(context, id, &cursor);
		goto out;
	    }

	    ret = krb5_copy_principal(context, entry.principal, &p);
	    if (ret) {
		krb5_kt_free_entry(context, &entry);
		krb5_kt_end_seq_get(context, id, &cursor);
		goto out;
	    }
	    krb5_free_principal(context, o->ticket->server);
	    o->ticket->server = p;
	    
	    krb5_kt_free_entry(context, &entry);

	    done = 1;
	}
	krb5_kt_end_seq_get(context, id, &cursor);
    }

    /* If there is a PAC, verify its server signature */
    if (inctx == NULL || inctx->check_pac) {
	krb5_pac pac;
	krb5_data data;

	ret = krb5_ticket_get_authorization_data_type(context,
						      o->ticket,
						      KRB5_AUTHDATA_WIN2K_PAC,
						      &data);
	if (ret == 0) {
	    ret = krb5_pac_parse(context, data.data, data.length, &pac);
	    krb5_data_free(&data);
	    if (ret)
		goto out;

	    ret = krb5_pac_verify(context,
				  pac,
				  o->ticket->ticket.authtime,
				  o->ticket->client,
				  o->keyblock,
				  NULL);
	    krb5_pac_free(context, pac);
	    if (ret == 0)
		o->flags |= KRB5_RD_REQ_OUT_PAC_VALID;
	    ret = 0;
	} else
	    ret = 0;
    }
 out:

    if (ret || outctx == NULL) {
	krb5_rd_req_out_ctx_free(context, o);
    } else
	*outctx = o;

    free_AP_REQ(&ap_req);

    if (service)
	krb5_free_principal(context, service);

    if (keytab)
	krb5_kt_close(context, keytab);

    return ret;
}
Exemple #12
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_rd_req_ctx(krb5_context context,
		krb5_auth_context *auth_context,
		const krb5_data *inbuf,
		krb5_const_principal server,
		krb5_rd_req_in_ctx inctx,
		krb5_rd_req_out_ctx *outctx)
{
    krb5_error_code ret;
    krb5_ap_req ap_req;
    krb5_principal service = NULL;
    krb5_rd_req_out_ctx o = NULL;

    ret = _krb5_rd_req_out_ctx_alloc(context, &o);
    if (ret)
	goto out;

    if (*auth_context == NULL) {
	ret = krb5_auth_con_init(context, auth_context);
	if (ret)
	    goto out;
    }

    ret = krb5_decode_ap_req(context, inbuf, &ap_req);
    if(ret)
	goto out;

    if(server == NULL){
	ret = _krb5_principalname2krb5_principal(context,
						 &service,
						 ap_req.ticket.sname,
						 ap_req.ticket.realm);
	if (ret)
	    goto out;
	server = service;
    }
    if (ap_req.ap_options.use_session_key &&
	(*auth_context)->keyblock == NULL) {
	krb5_set_error_string(context, "krb5_rd_req: user to user auth "
			      "without session key given");
	ret = KRB5KRB_AP_ERR_NOKEY;
	goto out;
    }

    if((*auth_context)->keyblock){
	ret = krb5_copy_keyblock(context,
				 (*auth_context)->keyblock,
				 &o->keyblock);
	if (ret)
	    goto out;
    } else if(inctx->keyblock){
	ret = krb5_copy_keyblock(context,
				 inctx->keyblock,
				 &o->keyblock);
	if (ret)
	    goto out;
    } else {
	krb5_keytab keytab = NULL;

	if (inctx && inctx->keytab)
	    keytab = inctx->keytab;

	ret = get_key_from_keytab(context, 
				  auth_context, 
				  &ap_req,
				  server,
				  keytab,
				  &o->keyblock);
	if(ret)
	    goto out;
    }

    ret = krb5_verify_ap_req2(context,
			      auth_context,
			      &ap_req,
			      server,
			      o->keyblock,
			      0,
			      &o->ap_req_options,
			      &o->ticket,
			      KRB5_KU_AP_REQ_AUTH);

    if (ret)
	goto out;

    /* If there is a PAC, verify its server signature */
    if (inctx->check_pac) {
	krb5_pac pac;
	krb5_data data;

	ret = krb5_ticket_get_authorization_data_type(context,
						      o->ticket,
						      KRB5_AUTHDATA_WIN2K_PAC,
						      &data);
	if (ret == 0) {
	    ret = krb5_pac_parse(context, data.data, data.length, &pac);
	    krb5_data_free(&data);
	    if (ret)
		goto out;
	
	    ret = krb5_pac_verify(context,
				  pac, 
				  o->ticket->ticket.authtime,
				  o->ticket->client, 
				  o->keyblock, 
				  NULL);
	    krb5_pac_free(context, pac);
	    if (ret)
		goto out;
	}
	ret = 0;
    }
out:
    if (ret || outctx == NULL) {
	krb5_rd_req_out_ctx_free(context, o);
    } else 
	*outctx = o;

    free_AP_REQ(&ap_req);
    if(service)
	krb5_free_principal(context, service);
    return ret;
}
Exemple #13
0
krb5_error_code sss_extract_pac(krb5_context ctx,
                                krb5_ccache ccache,
                                krb5_principal server_principal,
                                krb5_principal client_principal,
                                krb5_keytab keytab,
                                krb5_authdata ***_pac_authdata)
{
#ifdef HAVE_PAC_RESPONDER
    krb5_error_code kerr;
    krb5_creds mcred;
    krb5_creds cred;
    krb5_authdata **pac_authdata = NULL;
    krb5_pac pac = NULL;
    int ret;
    krb5_ticket *ticket = NULL;
    krb5_keytab_entry entry;

    memset(&entry, 0, sizeof(entry));
    memset(&mcred, 0, sizeof(mcred));
    memset(&cred, 0, sizeof(mcred));

    mcred.server = server_principal;
    mcred.client = client_principal;

    kerr = krb5_cc_retrieve_cred(ctx, ccache, 0, &mcred, &cred);
    if (kerr != 0) {
        DEBUG(SSSDBG_OP_FAILURE, "krb5_cc_retrieve_cred failed.\n");
        goto done;
    }

    kerr = krb5_decode_ticket(&cred.ticket, &ticket);
    if (kerr != 0) {
        DEBUG(SSSDBG_OP_FAILURE, "krb5_decode_ticket failed.\n");
        goto done;
    }

    kerr = krb5_server_decrypt_ticket_keytab(ctx, keytab, ticket);
    if (kerr != 0) {
        DEBUG(SSSDBG_OP_FAILURE, "krb5_server_decrypt_ticket_keytab failed.\n");
        goto done;
    }

    kerr = sss_krb5_find_authdata(ctx,
                                  ticket->enc_part2->authorization_data, NULL,
                                  KRB5_AUTHDATA_WIN2K_PAC, &pac_authdata);
    if (kerr != 0) {
        DEBUG(SSSDBG_OP_FAILURE, "krb5_find_authdata failed.\n");
        goto done;
    }

    if (pac_authdata == NULL || pac_authdata[0] == NULL) {
        DEBUG(SSSDBG_OP_FAILURE, "No PAC authdata available.\n");
        kerr = ENOENT;
        goto done;
    }

    if (pac_authdata[1] != NULL) {
        DEBUG(SSSDBG_OP_FAILURE, "More than one PAC autdata found.\n");
        kerr = EINVAL;
        goto done;
    }

    kerr = krb5_pac_parse(ctx, pac_authdata[0]->contents,
                          pac_authdata[0]->length, &pac);
    if (kerr != 0) {
        DEBUG(SSSDBG_OP_FAILURE, "krb5_pac_parse failed.\n");
        goto done;
    }

    kerr = krb5_kt_get_entry(ctx, keytab, ticket->server,
                             ticket->enc_part.kvno, ticket->enc_part.enctype,
                             &entry);
    if (kerr != 0) {
        DEBUG(SSSDBG_OP_FAILURE, "krb5_kt_get_entry failed.\n");
        goto done;
    }

    kerr = krb5_pac_verify(ctx, pac, 0, NULL, &entry.key, NULL);
    if (kerr != 0) {
        DEBUG(SSSDBG_OP_FAILURE, "krb5_pac_verify failed.\n");
        goto done;
    }

    ret = unsetenv("_SSS_LOOPS");
    if (ret != EOK) {
        DEBUG(SSSDBG_CRIT_FAILURE, "Failed to unset _SSS_LOOPS, "
                  "sss_pac_make_request will most certainly fail.\n");
    }

    *_pac_authdata = pac_authdata;
    kerr = 0;

done:
    if (kerr != 0) {
        krb5_free_authdata(ctx, pac_authdata);
    }
    if (entry.magic != 0) {
        krb5_free_keytab_entry_contents(ctx, &entry);
    }
    krb5_pac_free(ctx, pac);
    if (ticket != NULL) {
        krb5_free_ticket(ctx, ticket);
    }

    krb5_free_cred_contents(ctx, &cred);
    return kerr;
#else
    return ENOTSUP;
#endif
}
Exemple #14
0
int
main(int argc, char **argv)
{
    krb5_error_code ret;
    krb5_context context;
    krb5_pac pac;
    krb5_data data;
    krb5_principal p, p2;

    ret = krb5_init_context(&context);
    if (ret)
	errx(1, "krb5_init_contex");

    krb5_enctype_enable(context, ETYPE_DES_CBC_MD5);

    ret = krb5_parse_name_flags(context, user,
				KRB5_PRINCIPAL_PARSE_NO_REALM, &p);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    ret = krb5_pac_parse(context, saved_pac, sizeof(saved_pac), &pac);
    if (ret)
	krb5_err(context, 1, ret, "krb5_pac_parse");

    ret = krb5_pac_verify(context, pac, authtime, p,
			   &member_keyblock, &kdc_keyblock);
    if (ret)
	krb5_err(context, 1, ret, "krb5_pac_verify");

    ret = _krb5_pac_sign(context, pac, authtime, p,
			 &member_keyblock, &kdc_keyblock, &data);
    if (ret)
	krb5_err(context, 1, ret, "_krb5_pac_sign");

    krb5_pac_free(context, pac);

    ret = krb5_pac_parse(context, data.data, data.length, &pac);
    krb5_data_free(&data);
    if (ret)
	krb5_err(context, 1, ret, "krb5_pac_parse 2");

    ret = krb5_pac_verify(context, pac, authtime, p,
			   &member_keyblock, &kdc_keyblock);
    if (ret)
	krb5_err(context, 1, ret, "krb5_pac_verify 2");

    /* make a copy and try to reproduce it */
    {
	uint32_t *list;
	size_t len, i;
	krb5_pac pac2;

	ret = krb5_pac_init(context, &pac2);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_pac_init");

	/* our two user buffer plus the three "system" buffers */
	ret = krb5_pac_get_types(context, pac, &len, &list);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_pac_get_types");

	for (i = 0; i < len; i++) {
	    /* skip server_cksum, privsvr_cksum, and logon_name */
	    if (list[i] == 6 || list[i] == 7 || list[i] == 10)
		continue;

	    ret = krb5_pac_get_buffer(context, pac, list[i], &data);
	    if (ret)
		krb5_err(context, 1, ret, "krb5_pac_get_buffer");

	    if (list[i] == 1) {
		if (type_1_length != data.length)
		    krb5_errx(context, 1, "type 1 have wrong length: %lu",
			      (unsigned long)data.length);
	    } else
		krb5_errx(context, 1, "unknown type %lu",
			  (unsigned long)list[i]);

	    ret = krb5_pac_add_buffer(context, pac2, list[i], &data);
	    if (ret)
		krb5_err(context, 1, ret, "krb5_pac_add_buffer");
	    krb5_data_free(&data);
	}
	free(list);

	ret = _krb5_pac_sign(context, pac2, authtime, p,
			     &member_keyblock, &kdc_keyblock, &data);
	if (ret)
	    krb5_err(context, 1, ret, "_krb5_pac_sign 4");

	krb5_pac_free(context, pac2);

	ret = krb5_pac_parse(context, data.data, data.length, &pac2);
	krb5_data_free(&data);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_pac_parse 4");

	ret = krb5_pac_verify(context, pac2, authtime, p,
			      &member_keyblock, &kdc_keyblock);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_pac_verify 4");

	krb5_pac_free(context, pac2);
    }

    krb5_pac_free(context, pac);

    /*
     * check pac from Christian
     */

    ret = krb5_parse_name_flags(context, user2,
				KRB5_PRINCIPAL_PARSE_NO_REALM, &p2);
    if (ret)
	krb5_err(context, 1, ret, "krb5_parse_name");

    ret = krb5_pac_parse(context, saved_pac2, sizeof(saved_pac2) -1, &pac);
    if (ret)
	krb5_err(context, 1, ret, "krb5_pac_parse");

    ret = krb5_pac_verify(context, pac, authtime2, p2,
			   &member_keyblock2, NULL);
    if (ret)
	krb5_err(context, 1, ret, "krb5_pac_verify c1");

    krb5_pac_free(context, pac);
    krb5_free_principal(context, p2);

    /*
     * Test empty free
     */

    ret = krb5_pac_init(context, &pac);
    if (ret)
	krb5_err(context, 1, ret, "krb5_pac_init");
    krb5_pac_free(context, pac);

    /*
     * Test add remove buffer
     */

    ret = krb5_pac_init(context, &pac);
    if (ret)
	krb5_err(context, 1, ret, "krb5_pac_init");

    {
	const krb5_data cdata = { 2, "\x00\x01" } ;

	ret = krb5_pac_add_buffer(context, pac, 1, &cdata);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_pac_add_buffer");
    }
    {
	ret = krb5_pac_get_buffer(context, pac, 1, &data);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_pac_get_buffer");
	if (data.length != 2 || memcmp(data.data, "\x00\x01", 2) != 0)
	    krb5_errx(context, 1, "krb5_pac_get_buffer data not the same");
	krb5_data_free(&data);
    }

    {
	const krb5_data cdata = { 2, "\x02\x00" } ;

	ret = krb5_pac_add_buffer(context, pac, 2, &cdata);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_pac_add_buffer");
    }
    {
	ret = krb5_pac_get_buffer(context, pac, 1, &data);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_pac_get_buffer");
	if (data.length != 2 || memcmp(data.data, "\x00\x01", 2) != 0)
	    krb5_errx(context, 1, "krb5_pac_get_buffer data not the same");
	krb5_data_free(&data);
	/* */
	ret = krb5_pac_get_buffer(context, pac, 2, &data);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_pac_get_buffer");
	if (data.length != 2 || memcmp(data.data, "\x02\x00", 2) != 0)
	    krb5_errx(context, 1, "krb5_pac_get_buffer data not the same");
	krb5_data_free(&data);
    }

    ret = _krb5_pac_sign(context, pac, authtime, p,
			 &member_keyblock, &kdc_keyblock, &data);
    if (ret)
	krb5_err(context, 1, ret, "_krb5_pac_sign");

    krb5_pac_free(context, pac);

    ret = krb5_pac_parse(context, data.data, data.length, &pac);
    krb5_data_free(&data);
    if (ret)
	krb5_err(context, 1, ret, "krb5_pac_parse 3");

    ret = krb5_pac_verify(context, pac, authtime, p,
			   &member_keyblock, &kdc_keyblock);
    if (ret)
	krb5_err(context, 1, ret, "krb5_pac_verify 3");

    {
	uint32_t *list;
	size_t len;

	/* our two user buffer plus the three "system" buffers */
	ret = krb5_pac_get_types(context, pac, &len, &list);
	if (ret)
	    krb5_err(context, 1, ret, "krb5_pac_get_types");
	if (len != 5)
	    krb5_errx(context, 1, "list wrong length");
	free(list);
    }

    krb5_pac_free(context, pac);

    krb5_free_principal(context, p);
    krb5_free_context(context);

    return 0;
}
Exemple #15
0
int
main(int argc, char **argv)
{
    krb5_error_code ret;
    krb5_context context;
    krb5_pac pac;
    krb5_data data;
    krb5_principal p;

    ret = krb5_init_context(&context);
    if (ret)
        err(NULL, 0, "krb5_init_contex");

    krb5_set_default_realm(context, "WIN2K3.THINKER.LOCAL");

    ret = krb5_parse_name(context, user, &p);
    if (ret)
        err(context, ret, "krb5_parse_name");

    ret = krb5_pac_parse(context, saved_pac, sizeof(saved_pac), &pac);
    if (ret)
        err(context, ret, "krb5_pac_parse");

    ret = krb5_pac_verify(context, pac, authtime, p,
                           &member_keyblock, &kdc_keyblock);
    if (ret)
        err(context, ret, "krb5_pac_verify");

    ret = krb5int_pac_sign(context, pac, authtime, p,
                         &member_keyblock, &kdc_keyblock, &data);
    if (ret)
        err(context, ret, "krb5int_pac_sign");

    krb5_pac_free(context, pac);

    ret = krb5_pac_parse(context, data.data, data.length, &pac);
    krb5_free_data_contents(context, &data);
    if (ret)
        err(context, ret, "krb5_pac_parse 2");

    ret = krb5_pac_verify(context, pac, authtime, p,
                           &member_keyblock, &kdc_keyblock);
    if (ret)
        err(context, ret, "krb5_pac_verify 2");

    /* make a copy and try to reproduce it */
    {
        uint32_t *list;
        size_t len, i;
        krb5_pac pac2;

        ret = krb5_pac_init(context, &pac2);
        if (ret)
            err(context, ret, "krb5_pac_init");

        /* our two user buffer plus the three "system" buffers */
        ret = krb5_pac_get_types(context, pac, &len, &list);
        if (ret)
            err(context, ret, "krb5_pac_get_types");

        for (i = 0; i < len; i++) {
            /* skip server_cksum, privsvr_cksum, and logon_name */
            if (list[i] == 6 || list[i] == 7 || list[i] == 10)
                continue;

            ret = krb5_pac_get_buffer(context, pac, list[i], &data);
            if (ret)
                err(context, ret, "krb5_pac_get_buffer");

            if (list[i] == 1) {
                if (type_1_length != data.length)
                    err(context, 0, "type 1 have wrong length: %lu",
                        (unsigned long)data.length);
            } else
                err(context, 0, "unknown type %lu", (unsigned long)list[i]);

            ret = krb5_pac_add_buffer(context, pac2, list[i], &data);
            if (ret)
                err(context, ret, "krb5_pac_add_buffer");
            krb5_free_data_contents(context, &data);
        }
        free(list);
        
        ret = krb5int_pac_sign(context, pac2, authtime, p,
                               &member_keyblock, &kdc_keyblock, &data);
        if (ret)
            err(context, ret, "krb5int_pac_sign 4");
        
        krb5_pac_free(context, pac2);

        ret = krb5_pac_parse(context, data.data, data.length, &pac2);
        if (ret)
            err(context, ret, "krb5_pac_parse 4");
        
        ret = krb5_pac_verify(context, pac2, authtime, p,
                              &member_keyblock, &kdc_keyblock);
        if (ret)
            err(context, ret, "krb5_pac_verify 4");
        
        krb5_free_data_contents(context, &data);

        krb5_pac_free(context, pac2);
    }

    krb5_pac_free(context, pac);

    /*
     * Test empty free
     */

    ret = krb5_pac_init(context, &pac);
    if (ret)
        err(context, ret, "krb5_pac_init");
    krb5_pac_free(context, pac);

    /*
     * Test add remove buffer
     */

    ret = krb5_pac_init(context, &pac);
    if (ret)
        err(context, ret, "krb5_pac_init");

    {
        const krb5_data cdata = { 0, 2, "\x00\x01" } ;

        ret = krb5_pac_add_buffer(context, pac, 1, &cdata);
        if (ret)
            err(context, ret, "krb5_pac_add_buffer");
    }
    {
        ret = krb5_pac_get_buffer(context, pac, 1, &data);
        if (ret)
            err(context, ret, "krb5_pac_get_buffer");
        if (data.length != 2 || memcmp(data.data, "\x00\x01", 2) != 0)
            err(context, 0, "krb5_pac_get_buffer data not the same");
        krb5_free_data_contents(context, &data);
    }

    {
        const krb5_data cdata = { 0, 2, "\x02\x00" } ;

        ret = krb5_pac_add_buffer(context, pac, 2, &cdata);
        if (ret)
            err(context, ret, "krb5_pac_add_buffer");
    }
    {
        ret = krb5_pac_get_buffer(context, pac, 1, &data);
        if (ret)
            err(context, ret, "krb5_pac_get_buffer");
        if (data.length != 2 || memcmp(data.data, "\x00\x01", 2) != 0)
            err(context, 0, "krb5_pac_get_buffer data not the same");
        krb5_free_data_contents(context, &data);
        /* */
        ret = krb5_pac_get_buffer(context, pac, 2, &data);
        if (ret)
            err(context, ret, "krb5_pac_get_buffer");
        if (data.length != 2 || memcmp(data.data, "\x02\x00", 2) != 0)
            err(context, 0, "krb5_pac_get_buffer data not the same");
        krb5_free_data_contents(context, &data);
    }

    ret = krb5int_pac_sign(context, pac, authtime, p,
                           &member_keyblock, &kdc_keyblock, &data);
    if (ret)
        err(context, ret, "krb5int_pac_sign");

    krb5_pac_free(context, pac);

    ret = krb5_pac_parse(context, data.data, data.length, &pac);
    krb5_free_data_contents(context, &data);
    if (ret)
        err(context, ret, "krb5_pac_parse 3");

    ret = krb5_pac_verify(context, pac, authtime, p,
                           &member_keyblock, &kdc_keyblock);
    if (ret)
        err(context, ret, "krb5_pac_verify 3");

    {
        uint32_t *list;
        size_t len;

        /* our two user buffer plus the three "system" buffers */
        ret = krb5_pac_get_types(context, pac, &len, &list);
        if (ret)
            err(context, ret, "krb5_pac_get_types");
        if (len != 5)
            err(context, 0, "list wrong length");
        free(list);
    }

    krb5_pac_free(context, pac);

    krb5_free_principal(context, p);
    krb5_free_context(context);

    return 0;
}