mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 18:55:19 +00:00 
			
		
		
		
	
		
			
	
	
		
			648 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			648 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /*
 | ||
|  |  * Asterisk -- An open source telephony toolkit. | ||
|  |  * | ||
|  |  * Copyright (C) 2009, Digium, Inc. | ||
|  |  * | ||
|  |  * Russell Bryant <russell@digium.com> | ||
|  |  * | ||
|  |  * See http://www.asterisk.org for more information about
 | ||
|  |  * the Asterisk project. Please do not directly contact | ||
|  |  * any of the maintainers of this project for assistance; | ||
|  |  * the project provides a web site, mailing lists and IRC | ||
|  |  * channels for your use. | ||
|  |  * | ||
|  |  * This program is free software, distributed under the terms of | ||
|  |  * the GNU General Public License Version 2. See the LICENSE file | ||
|  |  * at the top of the source tree. | ||
|  |  */ | ||
|  | 
 | ||
|  | /*!
 | ||
|  |  * \file | ||
|  |  * | ||
|  |  * \brief Security Event Reporting Helpers | ||
|  |  * | ||
|  |  * \author Russell Bryant <russell@digium.com> | ||
|  |  */ | ||
|  | 
 | ||
|  | #include "asterisk.h"
 | ||
|  | 
 | ||
|  | ASTERISK_FILE_VERSION(__FILE__, "$Revision$") | ||
|  | 
 | ||
|  | #include "asterisk/utils.h"
 | ||
|  | #include "asterisk/strings.h"
 | ||
|  | #include "asterisk/network.h"
 | ||
|  | #include "asterisk/security_events.h"
 | ||
|  | 
 | ||
|  | static const size_t TIMESTAMP_STR_LEN = 32; | ||
|  | 
 | ||
|  | static const struct { | ||
|  | 	const char *name; | ||
|  | 	uint32_t version; | ||
|  | 	enum ast_security_event_severity severity; | ||
|  | #define MAX_SECURITY_IES 12
 | ||
|  | 	struct ast_security_event_ie_type required_ies[MAX_SECURITY_IES]; | ||
|  | 	struct ast_security_event_ie_type optional_ies[MAX_SECURITY_IES]; | ||
|  | #undef MAX_SECURITY_IES
 | ||
|  | } sec_events[AST_SECURITY_EVENT_NUM_TYPES] = { | ||
|  | 
 | ||
|  | #define SEC_EVT_FIELD(e, field) (offsetof(struct ast_security_event_##e, field))
 | ||
|  | 
 | ||
|  | [AST_SECURITY_EVENT_FAILED_ACL] = { | ||
|  | 	.name     = "FailedACL", | ||
|  | 	.version  = AST_SECURITY_EVENT_FAILED_ACL_VERSION, | ||
|  | 	.severity = AST_SECURITY_EVENT_SEVERITY_ERROR, | ||
|  | 	.required_ies = { | ||
|  | 		{ AST_EVENT_IE_EVENT_TV, 0 }, | ||
|  | 		{ AST_EVENT_IE_SEVERITY, 0 }, | ||
|  | 		{ AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) }, | ||
|  | 		{ AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) }, | ||
|  | 		{ AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) }, | ||
|  | 		{ AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) }, | ||
|  | 		{ AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | 	.optional_ies = { | ||
|  | 		{ AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) }, | ||
|  | 		{ AST_EVENT_IE_ACL_NAME, SEC_EVT_FIELD(failed_acl, acl_name) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | }, | ||
|  | 
 | ||
|  | [AST_SECURITY_EVENT_INVAL_ACCT_ID] = { | ||
|  | 	.name     = "InvalidAccountID", | ||
|  | 	.version  = AST_SECURITY_EVENT_INVAL_ACCT_ID_VERSION, | ||
|  | 	.severity = AST_SECURITY_EVENT_SEVERITY_ERROR, | ||
|  | 	.required_ies = { | ||
|  | 		{ AST_EVENT_IE_EVENT_TV, 0 }, | ||
|  | 		{ AST_EVENT_IE_SEVERITY, 0 }, | ||
|  | 		{ AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) }, | ||
|  | 		{ AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) }, | ||
|  | 		{ AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) }, | ||
|  | 		{ AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) }, | ||
|  | 		{ AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | 	.optional_ies = { | ||
|  | 		{ AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | }, | ||
|  | 
 | ||
|  | [AST_SECURITY_EVENT_SESSION_LIMIT] = { | ||
|  | 	.name     = "SessionLimit", | ||
|  | 	.version  = AST_SECURITY_EVENT_SESSION_LIMIT_VERSION, | ||
|  | 	.severity = AST_SECURITY_EVENT_SEVERITY_ERROR, | ||
|  | 	.required_ies = { | ||
|  | 		{ AST_EVENT_IE_EVENT_TV, 0 }, | ||
|  | 		{ AST_EVENT_IE_SEVERITY, 0 }, | ||
|  | 		{ AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) }, | ||
|  | 		{ AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) }, | ||
|  | 		{ AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) }, | ||
|  | 		{ AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) }, | ||
|  | 		{ AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | 	.optional_ies = { | ||
|  | 		{ AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | }, | ||
|  | 
 | ||
|  | [AST_SECURITY_EVENT_MEM_LIMIT] = { | ||
|  | 	.name     = "MemoryLimit", | ||
|  | 	.version  = AST_SECURITY_EVENT_MEM_LIMIT_VERSION, | ||
|  | 	.severity = AST_SECURITY_EVENT_SEVERITY_ERROR, | ||
|  | 	.required_ies = { | ||
|  | 		{ AST_EVENT_IE_EVENT_TV, 0 }, | ||
|  | 		{ AST_EVENT_IE_SEVERITY, 0 }, | ||
|  | 		{ AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) }, | ||
|  | 		{ AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) }, | ||
|  | 		{ AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) }, | ||
|  | 		{ AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) }, | ||
|  | 		{ AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | 	.optional_ies = { | ||
|  | 		{ AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | }, | ||
|  | 
 | ||
|  | [AST_SECURITY_EVENT_LOAD_AVG] = { | ||
|  | 	.name     = "LoadAverageLimit", | ||
|  | 	.version  = AST_SECURITY_EVENT_LOAD_AVG_VERSION, | ||
|  | 	.severity = AST_SECURITY_EVENT_SEVERITY_ERROR, | ||
|  | 	.required_ies = { | ||
|  | 		{ AST_EVENT_IE_EVENT_TV, 0 }, | ||
|  | 		{ AST_EVENT_IE_SEVERITY, 0 }, | ||
|  | 		{ AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) }, | ||
|  | 		{ AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) }, | ||
|  | 		{ AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) }, | ||
|  | 		{ AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) }, | ||
|  | 		{ AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | 	.optional_ies = { | ||
|  | 		{ AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | }, | ||
|  | 
 | ||
|  | [AST_SECURITY_EVENT_REQ_NO_SUPPORT] = { | ||
|  | 	.name     = "RequestNotSupported", | ||
|  | 	.version  = AST_SECURITY_EVENT_REQ_NO_SUPPORT_VERSION, | ||
|  | 	.severity = AST_SECURITY_EVENT_SEVERITY_ERROR, | ||
|  | 	.required_ies = { | ||
|  | 		{ AST_EVENT_IE_EVENT_TV, 0 }, | ||
|  | 		{ AST_EVENT_IE_SEVERITY, 0 }, | ||
|  | 		{ AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) }, | ||
|  | 		{ AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) }, | ||
|  | 		{ AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) }, | ||
|  | 		{ AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) }, | ||
|  | 		{ AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) }, | ||
|  | 		{ AST_EVENT_IE_REQUEST_TYPE, SEC_EVT_FIELD(req_no_support, request_type) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | 	.optional_ies = { | ||
|  | 		{ AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | }, | ||
|  | 
 | ||
|  | [AST_SECURITY_EVENT_REQ_NOT_ALLOWED] = { | ||
|  | 	.name     = "RequestNotAllowed", | ||
|  | 	.version  = AST_SECURITY_EVENT_REQ_NOT_ALLOWED_VERSION, | ||
|  | 	.severity = AST_SECURITY_EVENT_SEVERITY_ERROR, | ||
|  | 	.required_ies = { | ||
|  | 		{ AST_EVENT_IE_EVENT_TV, 0 }, | ||
|  | 		{ AST_EVENT_IE_SEVERITY, 0 }, | ||
|  | 		{ AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) }, | ||
|  | 		{ AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) }, | ||
|  | 		{ AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) }, | ||
|  | 		{ AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) }, | ||
|  | 		{ AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) }, | ||
|  | 		{ AST_EVENT_IE_REQUEST_TYPE, SEC_EVT_FIELD(req_not_allowed, request_type) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | 	.optional_ies = { | ||
|  | 		{ AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) }, | ||
|  | 		{ AST_EVENT_IE_REQUEST_PARAMS, SEC_EVT_FIELD(req_not_allowed, request_params) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | }, | ||
|  | 
 | ||
|  | [AST_SECURITY_EVENT_AUTH_METHOD_NOT_ALLOWED] = { | ||
|  | 	.name     = "AuthMethodNotAllowed", | ||
|  | 	.version  = AST_SECURITY_EVENT_AUTH_METHOD_NOT_ALLOWED_VERSION, | ||
|  | 	.severity = AST_SECURITY_EVENT_SEVERITY_ERROR, | ||
|  | 	.required_ies = { | ||
|  | 		{ AST_EVENT_IE_EVENT_TV, 0 }, | ||
|  | 		{ AST_EVENT_IE_SEVERITY, 0 }, | ||
|  | 		{ AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) }, | ||
|  | 		{ AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) }, | ||
|  | 		{ AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) }, | ||
|  | 		{ AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) }, | ||
|  | 		{ AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) }, | ||
|  | 		{ AST_EVENT_IE_AUTH_METHOD, SEC_EVT_FIELD(auth_method_not_allowed, auth_method) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | 	.optional_ies = { | ||
|  | 		{ AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | }, | ||
|  | 
 | ||
|  | [AST_SECURITY_EVENT_REQ_BAD_FORMAT] = { | ||
|  | 	.name     = "RequestBadFormat", | ||
|  | 	.version  = AST_SECURITY_EVENT_REQ_BAD_FORMAT_VERSION, | ||
|  | 	.severity = AST_SECURITY_EVENT_SEVERITY_ERROR, | ||
|  | 	.required_ies = { | ||
|  | 		{ AST_EVENT_IE_EVENT_TV, 0 }, | ||
|  | 		{ AST_EVENT_IE_SEVERITY, 0 }, | ||
|  | 		{ AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) }, | ||
|  | 		{ AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) }, | ||
|  | 		{ AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) }, | ||
|  | 		{ AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) }, | ||
|  | 		{ AST_EVENT_IE_REQUEST_TYPE, SEC_EVT_FIELD(req_bad_format, request_type) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | 	.optional_ies = { | ||
|  | 		{ AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) }, | ||
|  | 		{ AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) }, | ||
|  | 		{ AST_EVENT_IE_REQUEST_PARAMS, SEC_EVT_FIELD(req_bad_format, request_params) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | }, | ||
|  | 
 | ||
|  | [AST_SECURITY_EVENT_SUCCESSFUL_AUTH] = { | ||
|  | 	.name     = "SuccessfulAuth", | ||
|  | 	.version  = AST_SECURITY_EVENT_SUCCESSFUL_AUTH_VERSION, | ||
|  | 	.severity = AST_SECURITY_EVENT_SEVERITY_INFO, | ||
|  | 	.required_ies = { | ||
|  | 		{ AST_EVENT_IE_EVENT_TV, 0 }, | ||
|  | 		{ AST_EVENT_IE_SEVERITY, 0 }, | ||
|  | 		{ AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) }, | ||
|  | 		{ AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) }, | ||
|  | 		{ AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) }, | ||
|  | 		{ AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) }, | ||
|  | 		{ AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | 	.optional_ies = { | ||
|  | 		{ AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | }, | ||
|  | 
 | ||
|  | [AST_SECURITY_EVENT_UNEXPECTED_ADDR] = { | ||
|  | 	.name     = "UnexpectedAddress", | ||
|  | 	.version  = AST_SECURITY_EVENT_UNEXPECTED_ADDR_VERSION, | ||
|  | 	.severity = AST_SECURITY_EVENT_SEVERITY_ERROR, | ||
|  | 	.required_ies = { | ||
|  | 		{ AST_EVENT_IE_EVENT_TV, 0 }, | ||
|  | 		{ AST_EVENT_IE_SEVERITY, 0 }, | ||
|  | 		{ AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) }, | ||
|  | 		{ AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) }, | ||
|  | 		{ AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) }, | ||
|  | 		{ AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) }, | ||
|  | 		{ AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) }, | ||
|  | 		{ AST_EVENT_IE_EXPECTED_ADDR, SEC_EVT_FIELD(unexpected_addr, expected_addr) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | 	.optional_ies = { | ||
|  | 		{ AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | }, | ||
|  | 
 | ||
|  | [AST_SECURITY_EVENT_CHAL_RESP_FAILED] = { | ||
|  | 	.name     = "ChallengeResponseFailed", | ||
|  | 	.version  = AST_SECURITY_EVENT_CHAL_RESP_FAILED_VERSION, | ||
|  | 	.severity = AST_SECURITY_EVENT_SEVERITY_ERROR, | ||
|  | 	.required_ies = { | ||
|  | 		{ AST_EVENT_IE_EVENT_TV, 0 }, | ||
|  | 		{ AST_EVENT_IE_SEVERITY, 0 }, | ||
|  | 		{ AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) }, | ||
|  | 		{ AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) }, | ||
|  | 		{ AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) }, | ||
|  | 		{ AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) }, | ||
|  | 		{ AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) }, | ||
|  | 		{ AST_EVENT_IE_CHALLENGE, SEC_EVT_FIELD(chal_resp_failed, challenge) }, | ||
|  | 		{ AST_EVENT_IE_RESPONSE, SEC_EVT_FIELD(chal_resp_failed, response) }, | ||
|  | 		{ AST_EVENT_IE_EXPECTED_RESPONSE, SEC_EVT_FIELD(chal_resp_failed, expected_response) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | 	.optional_ies = { | ||
|  | 		{ AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | }, | ||
|  | 
 | ||
|  | [AST_SECURITY_EVENT_INVAL_PASSWORD] = { | ||
|  | 	.name     = "InvalidPassword", | ||
|  | 	.version  = AST_SECURITY_EVENT_INVAL_PASSWORD_VERSION, | ||
|  | 	.severity = AST_SECURITY_EVENT_SEVERITY_ERROR, | ||
|  | 	.required_ies = { | ||
|  | 		{ AST_EVENT_IE_EVENT_TV, 0 }, | ||
|  | 		{ AST_EVENT_IE_SEVERITY, 0 }, | ||
|  | 		{ AST_EVENT_IE_SERVICE, SEC_EVT_FIELD(common, service) }, | ||
|  | 		{ AST_EVENT_IE_EVENT_VERSION, SEC_EVT_FIELD(common, version) }, | ||
|  | 		{ AST_EVENT_IE_ACCOUNT_ID, SEC_EVT_FIELD(common, account_id) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_ID, SEC_EVT_FIELD(common, session_id) }, | ||
|  | 		{ AST_EVENT_IE_LOCAL_ADDR, SEC_EVT_FIELD(common, local_addr) }, | ||
|  | 		{ AST_EVENT_IE_REMOTE_ADDR, SEC_EVT_FIELD(common, remote_addr) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | 	.optional_ies = { | ||
|  | 		{ AST_EVENT_IE_MODULE, SEC_EVT_FIELD(common, module) }, | ||
|  | 		{ AST_EVENT_IE_SESSION_TV, SEC_EVT_FIELD(common, session_tv) }, | ||
|  | 		{ AST_EVENT_IE_END, 0 } | ||
|  | 	}, | ||
|  | }, | ||
|  | 
 | ||
|  | #undef SEC_EVT_FIELD
 | ||
|  | 
 | ||
|  | }; | ||
|  | 
 | ||
|  | static const struct { | ||
|  | 	enum ast_security_event_severity severity; | ||
|  | 	const char *str; | ||
|  | } severities[] = { | ||
|  | 	{ AST_SECURITY_EVENT_SEVERITY_INFO,  "Informational" }, | ||
|  | 	{ AST_SECURITY_EVENT_SEVERITY_ERROR, "Error" }, | ||
|  | }; | ||
|  | 
 | ||
|  | const char *ast_security_event_severity_get_name( | ||
|  | 		const enum ast_security_event_severity severity) | ||
|  | { | ||
|  | 	unsigned int i; | ||
|  | 
 | ||
|  | 	for (i = 0; i < ARRAY_LEN(severities); i++) { | ||
|  | 		if (severities[i].severity == severity) { | ||
|  | 			return severities[i].str; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return NULL; | ||
|  | } | ||
|  | 
 | ||
|  | static int check_event_type(const enum ast_security_event_type event_type) | ||
|  | { | ||
|  | 	if (event_type < 0 || event_type >= AST_SECURITY_EVENT_NUM_TYPES) { | ||
|  | 		ast_log(LOG_ERROR, "Invalid security event type %u\n", event_type); | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return 0; | ||
|  | } | ||
|  | 
 | ||
|  | const char *ast_security_event_get_name(const enum ast_security_event_type event_type) | ||
|  | { | ||
|  | 	if (check_event_type(event_type)) { | ||
|  | 		return NULL; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return sec_events[event_type].name; | ||
|  | } | ||
|  | 
 | ||
|  | const struct ast_security_event_ie_type *ast_security_event_get_required_ies( | ||
|  | 		const enum ast_security_event_type event_type) | ||
|  | { | ||
|  | 	if (check_event_type(event_type)) { | ||
|  | 		return NULL; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return sec_events[event_type].required_ies; | ||
|  | } | ||
|  | 
 | ||
|  | const struct ast_security_event_ie_type *ast_security_event_get_optional_ies( | ||
|  | 		const enum ast_security_event_type event_type) | ||
|  | { | ||
|  | 	if (check_event_type(event_type)) { | ||
|  | 		return NULL; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return sec_events[event_type].optional_ies; | ||
|  | } | ||
|  | 
 | ||
|  | static void encode_timestamp(struct ast_str **str, const struct timeval *tv) | ||
|  | { | ||
|  | 	ast_str_set(str, 0, "%u-%u", | ||
|  | 			(unsigned int) tv->tv_sec, | ||
|  | 			(unsigned int) tv->tv_usec); | ||
|  | } | ||
|  | 
 | ||
|  | static struct ast_event *alloc_event(const struct ast_security_event_common *sec) | ||
|  | { | ||
|  | 	struct ast_str *str = ast_str_alloca(TIMESTAMP_STR_LEN); | ||
|  | 	struct timeval tv = ast_tvnow(); | ||
|  | 	const char *severity_str; | ||
|  | 
 | ||
|  | 	if (check_event_type(sec->event_type)) { | ||
|  | 		return NULL; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	encode_timestamp(&str, &tv); | ||
|  | 
 | ||
|  | 	severity_str = S_OR( | ||
|  | 		ast_security_event_severity_get_name(sec_events[sec->event_type].severity), | ||
|  | 		"Unknown" | ||
|  | 	); | ||
|  | 
 | ||
|  | 	return ast_event_new(AST_EVENT_SECURITY, | ||
|  | 		AST_EVENT_IE_SECURITY_EVENT, AST_EVENT_IE_PLTYPE_UINT, sec->event_type, | ||
|  | 		AST_EVENT_IE_EVENT_VERSION, AST_EVENT_IE_PLTYPE_UINT, sec->version, | ||
|  | 		AST_EVENT_IE_EVENT_TV, AST_EVENT_IE_PLTYPE_STR, str->str, | ||
|  | 		AST_EVENT_IE_SERVICE, AST_EVENT_IE_PLTYPE_STR, sec->service, | ||
|  | 		AST_EVENT_IE_SEVERITY, AST_EVENT_IE_PLTYPE_STR, severity_str, | ||
|  | 		AST_EVENT_IE_END); | ||
|  | } | ||
|  | 
 | ||
|  | static int add_timeval_ie(struct ast_event **event, enum ast_event_ie_type ie_type, | ||
|  | 		const struct timeval *tv) | ||
|  | { | ||
|  | 	struct ast_str *str = ast_str_alloca(TIMESTAMP_STR_LEN); | ||
|  | 
 | ||
|  | 	encode_timestamp(&str, tv); | ||
|  | 
 | ||
|  | 	return ast_event_append_ie_str(event, ie_type, ast_str_buffer(str)); | ||
|  | } | ||
|  | 
 | ||
|  | static int add_ipv4_ie(struct ast_event **event, enum ast_event_ie_type ie_type, | ||
|  | 		const struct ast_security_event_ipv4_addr *addr) | ||
|  | { | ||
|  | 	struct ast_str *str = ast_str_alloca(64); | ||
|  | 
 | ||
|  | 	ast_str_set(&str, 0, "IPV4/"); | ||
|  | 
 | ||
|  | 	switch (addr->transport) { | ||
|  | 	case AST_SECURITY_EVENT_TRANSPORT_UDP: | ||
|  | 		ast_str_append(&str, 0, "UDP/"); | ||
|  | 		break; | ||
|  | 	case AST_SECURITY_EVENT_TRANSPORT_TCP: | ||
|  | 		ast_str_append(&str, 0, "TCP/"); | ||
|  | 		break; | ||
|  | 	case AST_SECURITY_EVENT_TRANSPORT_TLS: | ||
|  | 		ast_str_append(&str, 0, "TLS/"); | ||
|  | 		break; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	ast_str_append(&str, 0, "%s/%hu", | ||
|  | 			ast_inet_ntoa(addr->sin->sin_addr), | ||
|  | 			ntohs(addr->sin->sin_port)); | ||
|  | 
 | ||
|  | 	return ast_event_append_ie_str(event, ie_type, ast_str_buffer(str)); | ||
|  | } | ||
|  | 
 | ||
|  | enum ie_required { | ||
|  | 	NOT_REQUIRED, | ||
|  | 	REQUIRED | ||
|  | }; | ||
|  | 
 | ||
|  | static int add_ie(struct ast_event **event, const struct ast_security_event_common *sec, | ||
|  | 		const struct ast_security_event_ie_type *ie_type, enum ie_required req) | ||
|  | { | ||
|  | 	int res = 0; | ||
|  | 
 | ||
|  | 	switch (ie_type->ie_type) { | ||
|  | 	case AST_EVENT_IE_SERVICE: | ||
|  | 	case AST_EVENT_IE_ACCOUNT_ID: | ||
|  | 	case AST_EVENT_IE_SESSION_ID: | ||
|  | 	case AST_EVENT_IE_MODULE: | ||
|  | 	case AST_EVENT_IE_ACL_NAME: | ||
|  | 	case AST_EVENT_IE_REQUEST_TYPE: | ||
|  | 	case AST_EVENT_IE_REQUEST_PARAMS: | ||
|  | 	case AST_EVENT_IE_AUTH_METHOD: | ||
|  | 	case AST_EVENT_IE_CHALLENGE: | ||
|  | 	case AST_EVENT_IE_RESPONSE: | ||
|  | 	case AST_EVENT_IE_EXPECTED_RESPONSE: | ||
|  | 	{ | ||
|  | 		const char *str; | ||
|  | 
 | ||
|  | 		str = *((const char **)(((const char *) sec) + ie_type->offset)); | ||
|  | 
 | ||
|  | 		if (req && !str) { | ||
|  | 			ast_log(LOG_WARNING, "Required IE '%d' for security event " | ||
|  | 					"type '%d' not present\n", ie_type->ie_type, | ||
|  | 					sec->event_type); | ||
|  | 			res = -1; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (str) { | ||
|  | 			res = ast_event_append_ie_str(event, ie_type->ie_type, str); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		break; | ||
|  | 	} | ||
|  | 	case AST_EVENT_IE_EVENT_VERSION: | ||
|  | 	{ | ||
|  | 		uint32_t val; | ||
|  | 		val = *((const uint32_t *)(((const char *) sec) + ie_type->offset)); | ||
|  | 		res = ast_event_append_ie_uint(event, ie_type->ie_type, val); | ||
|  | 		break; | ||
|  | 	} | ||
|  | 	case AST_EVENT_IE_LOCAL_ADDR: | ||
|  | 	case AST_EVENT_IE_REMOTE_ADDR: | ||
|  | 	case AST_EVENT_IE_EXPECTED_ADDR: | ||
|  | 	{ | ||
|  | 		const struct ast_security_event_ipv4_addr *addr; | ||
|  | 
 | ||
|  | 		addr = (const struct ast_security_event_ipv4_addr *)(((const char *) sec) + ie_type->offset); | ||
|  | 
 | ||
|  | 		if (req && !addr->sin) { | ||
|  | 			ast_log(LOG_WARNING, "Required IE '%d' for security event " | ||
|  | 					"type '%d' not present\n", ie_type->ie_type, | ||
|  | 					sec->event_type); | ||
|  | 			res = -1; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (addr->sin) { | ||
|  | 			res = add_ipv4_ie(event, ie_type->ie_type, addr); | ||
|  | 		} | ||
|  | 		break; | ||
|  | 	} | ||
|  | 	case AST_EVENT_IE_SESSION_TV: | ||
|  | 	{ | ||
|  | 		const struct timeval *tval; | ||
|  | 
 | ||
|  | 		tval = *((const struct timeval **)(((const char *) sec) + ie_type->offset)); | ||
|  | 
 | ||
|  | 		if (req && !tval) { | ||
|  | 			ast_log(LOG_WARNING, "Required IE '%d' for security event " | ||
|  | 					"type '%d' not present\n", ie_type->ie_type, | ||
|  | 					sec->event_type); | ||
|  | 			res = -1; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (tval) { | ||
|  | 			add_timeval_ie(event, ie_type->ie_type, tval); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		break; | ||
|  | 	} | ||
|  | 	case AST_EVENT_IE_EVENT_TV: | ||
|  | 	case AST_EVENT_IE_SEVERITY: | ||
|  | 		/* Added automatically, nothing to do here. */ | ||
|  | 		break; | ||
|  | 	default: | ||
|  | 		ast_log(LOG_WARNING, "Unhandled IE type '%d', this security event " | ||
|  | 				"will be missing data.\n", ie_type->ie_type); | ||
|  | 		break; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return res; | ||
|  | } | ||
|  | 
 | ||
|  | static int handle_security_event(const struct ast_security_event_common *sec) | ||
|  | { | ||
|  | 	struct ast_event *event; | ||
|  | 	const struct ast_security_event_ie_type *ies; | ||
|  | 	unsigned int i; | ||
|  | 
 | ||
|  | 	if (!(event = alloc_event(sec))) { | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	for (ies = ast_security_event_get_required_ies(sec->event_type), i = 0; | ||
|  | 			ies[i].ie_type != AST_EVENT_IE_END; | ||
|  | 			i++) { | ||
|  | 		if (add_ie(&event, sec, ies + i, REQUIRED)) { | ||
|  | 			goto return_error; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	for (ies = ast_security_event_get_optional_ies(sec->event_type), i = 0; | ||
|  | 			ies[i].ie_type != AST_EVENT_IE_END; | ||
|  | 			i++) { | ||
|  | 		if (add_ie(&event, sec, ies + i, NOT_REQUIRED)) { | ||
|  | 			goto return_error; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 
 | ||
|  | 	if (ast_event_queue(event)) { | ||
|  | 		goto return_error; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return 0; | ||
|  | 
 | ||
|  | return_error: | ||
|  | 	if (event) { | ||
|  | 		ast_event_destroy(event); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return -1; | ||
|  | } | ||
|  | 
 | ||
|  | int ast_security_event_report(const struct ast_security_event_common *sec) | ||
|  | { | ||
|  | 	int res; | ||
|  | 
 | ||
|  | 	if (sec->event_type < 0 || sec->event_type >= AST_SECURITY_EVENT_NUM_TYPES) { | ||
|  | 		ast_log(LOG_ERROR, "Invalid security event type\n"); | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (!sec_events[sec->event_type].name) { | ||
|  | 		ast_log(LOG_WARNING, "Security event type %u not handled\n", | ||
|  | 				sec->event_type); | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (sec->version != sec_events[sec->event_type].version) { | ||
|  | 		ast_log(LOG_WARNING, "Security event %u version mismatch\n", | ||
|  | 				sec->event_type); | ||
|  | 		return -1; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	res = handle_security_event(sec); | ||
|  | 
 | ||
|  | 	return res; | ||
|  | } | ||
|  | 
 | ||
|  | 
 |