Blame lib/alert.c

Packit 549fdc
/*
Packit 549fdc
 * Copyright (C) 2000-2012 Free Software Foundation, Inc.
Packit 549fdc
 *
Packit 549fdc
 * Author: Nikos Mavrogiannopoulos
Packit 549fdc
 *
Packit 549fdc
 * This file is part of GnuTLS.
Packit 549fdc
 *
Packit 549fdc
 * The GnuTLS is free software; you can redistribute it and/or
Packit 549fdc
 * modify it under the terms of the GNU Lesser General Public License
Packit 549fdc
 * as published by the Free Software Foundation; either version 2.1 of
Packit 549fdc
 * the License, or (at your option) any later version.
Packit 549fdc
 *
Packit 549fdc
 * This library is distributed in the hope that it will be useful, but
Packit 549fdc
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 549fdc
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 549fdc
 * Lesser General Public License for more details.
Packit 549fdc
 *
Packit 549fdc
 * You should have received a copy of the GNU Lesser General Public License
Packit 549fdc
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
Packit 549fdc
 *
Packit 549fdc
 */
Packit 549fdc
Packit 549fdc
#include "gnutls_int.h"
Packit 549fdc
#include "errors.h"
Packit 549fdc
#include <record.h>
Packit 549fdc
#include <debug.h>
Packit 549fdc
#include "str.h"
Packit 549fdc
Packit 549fdc
typedef struct {
Packit 549fdc
	gnutls_alert_description_t alert;
Packit 549fdc
	const char *name;
Packit 549fdc
	const char *desc;
Packit 549fdc
} gnutls_alert_entry;
Packit 549fdc
Packit 549fdc
#define ALERT_ENTRY(x,y) \
Packit 549fdc
  {x, #x, y}
Packit 549fdc
Packit 549fdc
static const gnutls_alert_entry sup_alerts[] = {
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_CLOSE_NOTIFY, N_("Close notify")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_UNEXPECTED_MESSAGE, N_("Unexpected message")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_BAD_RECORD_MAC, N_("Bad record MAC")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_DECRYPTION_FAILED, N_("Decryption failed")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_RECORD_OVERFLOW, N_("Record overflow")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_DECOMPRESSION_FAILURE,
Packit 549fdc
		    N_("Decompression failed")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_HANDSHAKE_FAILURE, N_("Handshake failed")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_BAD_CERTIFICATE, N_("Certificate is bad")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_UNSUPPORTED_CERTIFICATE,
Packit 549fdc
		    N_("Certificate is not supported")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_CERTIFICATE_REVOKED,
Packit 549fdc
		    N_("Certificate was revoked")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_CERTIFICATE_EXPIRED,
Packit 549fdc
		    N_("Certificate is expired")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_CERTIFICATE_UNKNOWN,
Packit 549fdc
		    N_("Unknown certificate")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_ILLEGAL_PARAMETER, N_("Illegal parameter")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_UNKNOWN_CA, N_("CA is unknown")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_ACCESS_DENIED, N_("Access was denied")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_DECODE_ERROR, N_("Decode error")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_DECRYPT_ERROR, N_("Decrypt error")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_EXPORT_RESTRICTION, N_("Export restriction")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_PROTOCOL_VERSION,
Packit 549fdc
		    N_("Error in protocol version")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_INSUFFICIENT_SECURITY,
Packit 549fdc
		    N_("Insufficient security")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_USER_CANCELED, N_("User canceled")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_SSL3_NO_CERTIFICATE,
Packit 549fdc
		    N_("No certificate (SSL 3.0)")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_INTERNAL_ERROR, N_("Internal error")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_INAPPROPRIATE_FALLBACK,
Packit 549fdc
		    N_("Inappropriate fallback")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_NO_RENEGOTIATION,
Packit 549fdc
		    N_("No renegotiation is allowed")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_CERTIFICATE_UNOBTAINABLE,
Packit 549fdc
		    N_("Could not retrieve the specified certificate")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_UNSUPPORTED_EXTENSION,
Packit 549fdc
		    N_("An unsupported extension was sent")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_UNRECOGNIZED_NAME,
Packit 549fdc
		    N_("The server name sent was not recognized")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_UNKNOWN_PSK_IDENTITY,
Packit 549fdc
		    N_("The SRP/PSK username is missing or not known")),
Packit 549fdc
	ALERT_ENTRY(GNUTLS_A_NO_APPLICATION_PROTOCOL,
Packit 549fdc
		    N_
Packit 549fdc
		    ("No supported application protocol could be negotiated")),
Packit 549fdc
	{0, NULL, NULL}
Packit 549fdc
};
Packit 549fdc
Packit 549fdc
/**
Packit 549fdc
 * gnutls_alert_get_name:
Packit 549fdc
 * @alert: is an alert number.
Packit 549fdc
 *
Packit 549fdc
 * This function will return a string that describes the given alert
Packit 549fdc
 * number, or %NULL.  See gnutls_alert_get().
Packit 549fdc
 *
Packit 549fdc
 * Returns: string corresponding to #gnutls_alert_description_t value.
Packit 549fdc
 **/
Packit 549fdc
const char *gnutls_alert_get_name(gnutls_alert_description_t alert)
Packit 549fdc
{
Packit 549fdc
	const gnutls_alert_entry *p;
Packit 549fdc
Packit 549fdc
	for (p = sup_alerts; p->desc != NULL; p++)
Packit 549fdc
		if (p->alert == alert)
Packit 549fdc
			return _(p->desc);
Packit 549fdc
Packit 549fdc
	return NULL;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
/**
Packit 549fdc
 * gnutls_alert_get_strname:
Packit 549fdc
 * @alert: is an alert number.
Packit 549fdc
 *
Packit 549fdc
 * This function will return a string of the name of the alert.
Packit 549fdc
 *
Packit 549fdc
 * Returns: string corresponding to #gnutls_alert_description_t value.
Packit 549fdc
 *
Packit 549fdc
 * Since: 3.0
Packit 549fdc
 **/
Packit 549fdc
const char *gnutls_alert_get_strname(gnutls_alert_description_t alert)
Packit 549fdc
{
Packit 549fdc
	const gnutls_alert_entry *p;
Packit 549fdc
Packit 549fdc
	for (p = sup_alerts; p->name != NULL; p++)
Packit 549fdc
		if (p->alert == alert)
Packit 549fdc
			return p->name;
Packit 549fdc
Packit 549fdc
	return NULL;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
/**
Packit 549fdc
 * gnutls_alert_send:
Packit 549fdc
 * @session: is a #gnutls_session_t type.
Packit 549fdc
 * @level: is the level of the alert
Packit 549fdc
 * @desc: is the alert description
Packit 549fdc
 *
Packit 549fdc
 * This function will send an alert to the peer in order to inform
Packit 549fdc
 * him of something important (eg. his Certificate could not be verified).
Packit 549fdc
 * If the alert level is Fatal then the peer is expected to close the
Packit 549fdc
 * connection, otherwise he may ignore the alert and continue.
Packit 549fdc
 *
Packit 549fdc
 * The error code of the underlying record send function will be
Packit 549fdc
 * returned, so you may also receive %GNUTLS_E_INTERRUPTED or
Packit 549fdc
 * %GNUTLS_E_AGAIN as well.
Packit 549fdc
 *
Packit 549fdc
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
Packit 549fdc
 *   an error code is returned.
Packit 549fdc
 **/
Packit 549fdc
int
Packit 549fdc
gnutls_alert_send(gnutls_session_t session, gnutls_alert_level_t level,
Packit 549fdc
		  gnutls_alert_description_t desc)
Packit 549fdc
{
Packit 549fdc
	uint8_t data[2];
Packit 549fdc
	int ret;
Packit 549fdc
	const char *name;
Packit 549fdc
Packit 549fdc
	data[0] = (uint8_t) level;
Packit 549fdc
	data[1] = (uint8_t) desc;
Packit 549fdc
Packit 549fdc
	name = gnutls_alert_get_name((gnutls_alert_description_t) data[1]);
Packit 549fdc
	if (name == NULL)
Packit 549fdc
		name = "(unknown)";
Packit 549fdc
	_gnutls_record_log("REC: Sending Alert[%d|%d] - %s\n", data[0],
Packit 549fdc
			   data[1], name);
Packit 549fdc
Packit 549fdc
	if ((ret =
Packit 549fdc
	     _gnutls_send_int(session, GNUTLS_ALERT, -1,
Packit 549fdc
			      EPOCH_WRITE_CURRENT, data, 2,
Packit 549fdc
			      MBUFFER_FLUSH)) >= 0)
Packit 549fdc
		return 0;
Packit 549fdc
	else
Packit 549fdc
		return ret;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
/**
Packit 549fdc
 * gnutls_error_to_alert:
Packit 549fdc
 * @err: is a negative integer
Packit 549fdc
 * @level: the alert level will be stored there
Packit 549fdc
 *
Packit 549fdc
 * Get an alert depending on the error code returned by a gnutls
Packit 549fdc
 * function.  All alerts sent by this function should be considered
Packit 549fdc
 * fatal.  The only exception is when @err is %GNUTLS_E_REHANDSHAKE,
Packit 549fdc
 * where a warning alert should be sent to the peer indicating that no
Packit 549fdc
 * renegotiation will be performed.
Packit 549fdc
 *
Packit 549fdc
 * If there is no mapping to a valid alert the alert to indicate
Packit 549fdc
 * internal error is returned.
Packit 549fdc
 *
Packit 549fdc
 * Returns: the alert code to use for a particular error code.
Packit 549fdc
 **/
Packit 549fdc
int gnutls_error_to_alert(int err, int *level)
Packit 549fdc
{
Packit 549fdc
	int ret, _level = -1;
Packit 549fdc
Packit 549fdc
	switch (err) {		/* send appropriate alert */
Packit 549fdc
	case GNUTLS_E_PK_SIG_VERIFY_FAILED:
Packit 549fdc
		ret = GNUTLS_A_DECRYPT_ERROR;
Packit 549fdc
		_level = GNUTLS_AL_FATAL;
Packit 549fdc
		break;
Packit 549fdc
	case GNUTLS_E_DECRYPTION_FAILED:
Packit 549fdc
		/* GNUTLS_A_DECRYPTION_FAILED is not sent, because
Packit 549fdc
		 * it is not defined in SSL3. Note that we must
Packit 549fdc
		 * not distinguish Decryption failures from mac
Packit 549fdc
		 * check failures, due to the possibility of some
Packit 549fdc
		 * attacks.
Packit 549fdc
		 */
Packit 549fdc
		ret = GNUTLS_A_BAD_RECORD_MAC;
Packit 549fdc
		_level = GNUTLS_AL_FATAL;
Packit 549fdc
		break;
Packit 549fdc
	case GNUTLS_E_UNEXPECTED_PACKET_LENGTH:
Packit 549fdc
	case GNUTLS_E_UNEXPECTED_EXTENSIONS_LENGTH:
Packit 549fdc
	case GNUTLS_E_NO_CERTIFICATE_FOUND:
Packit 549fdc
		ret = GNUTLS_A_DECODE_ERROR;
Packit 549fdc
		_level = GNUTLS_AL_FATAL;
Packit 549fdc
		break;
Packit 549fdc
	case GNUTLS_E_DECOMPRESSION_FAILED:
Packit 549fdc
		ret = GNUTLS_A_DECOMPRESSION_FAILURE;
Packit 549fdc
		_level = GNUTLS_AL_FATAL;
Packit 549fdc
		break;
Packit 549fdc
	case GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER:
Packit 549fdc
	case GNUTLS_E_ILLEGAL_SRP_USERNAME:
Packit 549fdc
	case GNUTLS_E_PK_INVALID_PUBKEY:
Packit 549fdc
		ret = GNUTLS_A_ILLEGAL_PARAMETER;
Packit 549fdc
		_level = GNUTLS_AL_FATAL;
Packit 549fdc
		break;
Packit 549fdc
	case GNUTLS_E_UNKNOWN_SRP_USERNAME:
Packit 549fdc
		ret = GNUTLS_A_UNKNOWN_PSK_IDENTITY;
Packit 549fdc
		_level = GNUTLS_AL_FATAL;
Packit 549fdc
		break;
Packit 549fdc
	case GNUTLS_E_ASN1_ELEMENT_NOT_FOUND:
Packit 549fdc
	case GNUTLS_E_ASN1_IDENTIFIER_NOT_FOUND:
Packit 549fdc
	case GNUTLS_E_ASN1_DER_ERROR:
Packit 549fdc
	case GNUTLS_E_ASN1_VALUE_NOT_FOUND:
Packit 549fdc
	case GNUTLS_E_ASN1_GENERIC_ERROR:
Packit 549fdc
	case GNUTLS_E_ASN1_VALUE_NOT_VALID:
Packit 549fdc
	case GNUTLS_E_ASN1_TAG_ERROR:
Packit 549fdc
	case GNUTLS_E_ASN1_TAG_IMPLICIT:
Packit 549fdc
	case GNUTLS_E_ASN1_TYPE_ANY_ERROR:
Packit 549fdc
	case GNUTLS_E_ASN1_SYNTAX_ERROR:
Packit 549fdc
	case GNUTLS_E_ASN1_DER_OVERFLOW:
Packit 549fdc
	case GNUTLS_E_CERTIFICATE_ERROR:
Packit 549fdc
	case GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR:
Packit 549fdc
		ret = GNUTLS_A_BAD_CERTIFICATE;
Packit 549fdc
		_level = GNUTLS_AL_FATAL;
Packit 549fdc
		break;
Packit 549fdc
	case GNUTLS_E_UNKNOWN_CIPHER_SUITE:
Packit 549fdc
	case GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM:
Packit 549fdc
	case GNUTLS_E_INSUFFICIENT_CREDENTIALS:
Packit 549fdc
	case GNUTLS_E_NO_CIPHER_SUITES:
Packit 549fdc
	case GNUTLS_E_NO_COMPRESSION_ALGORITHMS:
Packit 549fdc
	case GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM:
Packit 549fdc
	case GNUTLS_E_SAFE_RENEGOTIATION_FAILED:
Packit 549fdc
	case GNUTLS_E_INCOMPAT_DSA_KEY_WITH_TLS_PROTOCOL:
Packit 549fdc
	case GNUTLS_E_UNKNOWN_PK_ALGORITHM:
Packit 549fdc
	case GNUTLS_E_UNWANTED_ALGORITHM:
Packit 549fdc
		ret = GNUTLS_A_HANDSHAKE_FAILURE;
Packit 549fdc
		_level = GNUTLS_AL_FATAL;
Packit 549fdc
		break;
Packit 549fdc
	case GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION:
Packit 549fdc
		ret = GNUTLS_A_UNSUPPORTED_EXTENSION;
Packit 549fdc
		_level = GNUTLS_AL_FATAL;
Packit 549fdc
		break;
Packit 549fdc
	case GNUTLS_E_USER_ERROR:
Packit 549fdc
		ret = GNUTLS_A_USER_CANCELED;
Packit 549fdc
		_level = GNUTLS_AL_FATAL;
Packit 549fdc
		break;
Packit 549fdc
	case GNUTLS_E_UNEXPECTED_PACKET:
Packit 549fdc
	case GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET:
Packit 549fdc
	case GNUTLS_E_PREMATURE_TERMINATION:
Packit 549fdc
		ret = GNUTLS_A_UNEXPECTED_MESSAGE;
Packit 549fdc
		_level = GNUTLS_AL_FATAL;
Packit 549fdc
		break;
Packit 549fdc
	case GNUTLS_E_REHANDSHAKE:
Packit 549fdc
	case GNUTLS_E_UNSAFE_RENEGOTIATION_DENIED:
Packit 549fdc
		ret = GNUTLS_A_NO_RENEGOTIATION;
Packit 549fdc
		_level = GNUTLS_AL_WARNING;
Packit 549fdc
		break;
Packit 549fdc
	case GNUTLS_E_UNSUPPORTED_VERSION_PACKET:
Packit 549fdc
		ret = GNUTLS_A_PROTOCOL_VERSION;
Packit 549fdc
		_level = GNUTLS_AL_FATAL;
Packit 549fdc
		break;
Packit 549fdc
	case GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE:
Packit 549fdc
		ret = GNUTLS_A_UNSUPPORTED_CERTIFICATE;
Packit 549fdc
		_level = GNUTLS_AL_FATAL;
Packit 549fdc
		break;
Packit 549fdc
	case GNUTLS_E_RECORD_OVERFLOW:
Packit 549fdc
		ret = GNUTLS_A_RECORD_OVERFLOW;
Packit 549fdc
		_level = GNUTLS_AL_FATAL;
Packit 549fdc
		break;
Packit 549fdc
	case GNUTLS_E_INTERNAL_ERROR:
Packit 549fdc
	case GNUTLS_E_NO_TEMPORARY_DH_PARAMS:
Packit 549fdc
	case GNUTLS_E_NO_TEMPORARY_RSA_PARAMS:
Packit 549fdc
		ret = GNUTLS_A_INTERNAL_ERROR;
Packit 549fdc
		_level = GNUTLS_AL_FATAL;
Packit 549fdc
		break;
Packit 549fdc
	case GNUTLS_E_INAPPROPRIATE_FALLBACK:
Packit 549fdc
		ret = GNUTLS_A_INAPPROPRIATE_FALLBACK;
Packit 549fdc
		_level = GNUTLS_AL_FATAL;
Packit 549fdc
		break;
Packit 549fdc
	case GNUTLS_E_OPENPGP_GETKEY_FAILED:
Packit 549fdc
		ret = GNUTLS_A_CERTIFICATE_UNOBTAINABLE;
Packit 549fdc
		_level = GNUTLS_AL_FATAL;
Packit 549fdc
		break;
Packit 549fdc
	case GNUTLS_E_DH_PRIME_UNACCEPTABLE:
Packit 549fdc
	case GNUTLS_E_SESSION_USER_ID_CHANGED:
Packit 549fdc
	case GNUTLS_E_INSUFFICIENT_SECURITY:
Packit 549fdc
		ret = GNUTLS_A_INSUFFICIENT_SECURITY;
Packit 549fdc
		_level = GNUTLS_AL_FATAL;
Packit 549fdc
		break;
Packit 549fdc
	case GNUTLS_E_NO_APPLICATION_PROTOCOL:
Packit 549fdc
		ret = GNUTLS_A_NO_APPLICATION_PROTOCOL;
Packit 549fdc
		_level = GNUTLS_AL_FATAL;
Packit 549fdc
		break;
Packit 549fdc
	case GNUTLS_E_UNRECOGNIZED_NAME:
Packit 549fdc
		ret = GNUTLS_A_UNRECOGNIZED_NAME;
Packit 549fdc
		_level = GNUTLS_AL_FATAL;
Packit 549fdc
		break;
Packit 549fdc
	default:
Packit 549fdc
		ret = GNUTLS_A_INTERNAL_ERROR;
Packit 549fdc
		_level = GNUTLS_AL_FATAL;
Packit 549fdc
		break;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	if (level != NULL)
Packit 549fdc
		*level = _level;
Packit 549fdc
Packit 549fdc
	return ret;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
/**
Packit 549fdc
 * gnutls_alert_send_appropriate:
Packit 549fdc
 * @session: is a #gnutls_session_t type.
Packit 549fdc
 * @err: is an integer
Packit 549fdc
 *
Packit 549fdc
 * Sends an alert to the peer depending on the error code returned by
Packit 549fdc
 * a gnutls function. This function will call gnutls_error_to_alert()
Packit 549fdc
 * to determine the appropriate alert to send.
Packit 549fdc
 *
Packit 549fdc
 * This function may also return %GNUTLS_E_AGAIN, or
Packit 549fdc
 * %GNUTLS_E_INTERRUPTED.
Packit 549fdc
 *
Packit 549fdc
 * If the return value is %GNUTLS_E_INVALID_REQUEST, then no alert has
Packit 549fdc
 * been sent to the peer.
Packit 549fdc
 *
Packit 549fdc
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
Packit 549fdc
 *   an error code is returned.
Packit 549fdc
 */
Packit 549fdc
int gnutls_alert_send_appropriate(gnutls_session_t session, int err)
Packit 549fdc
{
Packit 549fdc
	gnutls_alert_description_t alert;
Packit 549fdc
	int level;
Packit 549fdc
Packit 549fdc
	alert = gnutls_error_to_alert(err, &level);
Packit 549fdc
	if (alert < 0) {
Packit 549fdc
		return alert;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	return gnutls_alert_send(session, (gnutls_alert_level_t)level, alert);
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
/**
Packit 549fdc
 * gnutls_alert_get:
Packit 549fdc
 * @session: is a #gnutls_session_t type.
Packit 549fdc
 *
Packit 549fdc
 * This function will return the last alert number received.  This
Packit 549fdc
 * function should be called when %GNUTLS_E_WARNING_ALERT_RECEIVED or
Packit 549fdc
 * %GNUTLS_E_FATAL_ALERT_RECEIVED errors are returned by a gnutls
Packit 549fdc
 * function.  The peer may send alerts if he encounters an error.
Packit 549fdc
 * If no alert has been received the returned value is undefined.
Packit 549fdc
 *
Packit 549fdc
 * Returns: the last alert received, a
Packit 549fdc
 *   #gnutls_alert_description_t value.
Packit 549fdc
 **/
Packit 549fdc
gnutls_alert_description_t gnutls_alert_get(gnutls_session_t session)
Packit 549fdc
{
Packit 549fdc
	return (gnutls_alert_description_t)session->internals.last_alert;
Packit 549fdc
}