2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2013, Digium, Inc.
6 * Mark Michelson <mmichelson@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
23 #include "asterisk/res_pjsip.h"
24 #include "asterisk/logger.h"
25 #include "asterisk/sorcery.h"
26 #include "include/res_pjsip_private.h"
28 static void auth_destroy(void *obj)
30 struct ast_sip_auth *auth = obj;
31 ast_string_field_free_memory(auth);
34 static void *auth_alloc(const char *name)
36 struct ast_sip_auth *auth = ast_sorcery_generic_alloc(sizeof(*auth), auth_destroy);
42 if (ast_string_field_init(auth, 64)) {
50 static int auth_type_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
52 struct ast_sip_auth *auth = obj;
53 if (!strcasecmp(var->value, "userpass")) {
54 auth->type = AST_SIP_AUTH_TYPE_USER_PASS;
55 } else if (!strcasecmp(var->value, "md5")) {
56 auth->type = AST_SIP_AUTH_TYPE_MD5;
58 ast_log(LOG_WARNING, "Unknown authentication storage type '%s' specified for %s\n",
59 var->value, var->name);
65 static const char *auth_types_map[] = {
66 [AST_SIP_AUTH_TYPE_USER_PASS] = "userpass",
67 [AST_SIP_AUTH_TYPE_MD5] = "md5"
70 const char *ast_sip_auth_type_to_str(enum ast_sip_auth_type type)
72 return ARRAY_IN_BOUNDS(type, auth_types_map) ?
73 auth_types_map[type] : "";
76 static int auth_type_to_str(const void *obj, const intptr_t *args, char **buf)
78 const struct ast_sip_auth *auth = obj;
79 *buf = ast_strdup(ast_sip_auth_type_to_str(auth->type));
83 static int auth_apply(const struct ast_sorcery *sorcery, void *obj)
85 struct ast_sip_auth *auth = obj;
88 if (ast_strlen_zero(auth->auth_user)) {
89 ast_log(LOG_ERROR, "No authentication username for auth '%s'\n",
90 ast_sorcery_object_get_id(auth));
95 case AST_SIP_AUTH_TYPE_USER_PASS:
96 if (ast_strlen_zero(auth->auth_pass)) {
97 ast_log(LOG_ERROR, "'userpass' authentication specified but no"
98 "password specified for auth '%s'\n", ast_sorcery_object_get_id(auth));
102 case AST_SIP_AUTH_TYPE_MD5:
103 if (ast_strlen_zero(auth->md5_creds)) {
104 ast_log(LOG_ERROR, "'md5' authentication specified but no md5_cred"
105 "specified for auth '%s'\n", ast_sorcery_object_get_id(auth));
107 } else if (strlen(auth->md5_creds) != PJSIP_MD5STRLEN) {
108 ast_log(LOG_ERROR, "'md5' authentication requires digest of size '%d', but"
109 "digest is '%d' in size for auth '%s'\n", PJSIP_MD5STRLEN, (int)strlen(auth->md5_creds),
110 ast_sorcery_object_get_id(auth));
114 case AST_SIP_AUTH_TYPE_ARTIFICIAL:
121 int ast_sip_for_each_auth(const struct ast_sip_auth_array *array,
122 ao2_callback_fn on_auth, void *arg)
126 if (!array || !array->num) {
130 for (i = 0; i < array->num; ++i) {
131 RAII_VAR(struct ast_sip_auth *, auth, ast_sorcery_retrieve_by_id(
132 ast_sip_get_sorcery(), SIP_SORCERY_AUTH_TYPE,
133 array->names[i]), ao2_cleanup);
139 if (on_auth(auth, arg, 0)) {
147 static int sip_auth_to_ami(const struct ast_sip_auth *auth,
148 struct ast_str **buf)
150 return ast_sip_sorcery_object_to_ami(auth, buf);
153 static int format_ami_auth_handler(void *obj, void *arg, int flags)
155 const struct ast_sip_auth *auth = obj;
156 struct ast_sip_ami *ami = arg;
157 const struct ast_sip_endpoint *endpoint = ami->arg;
158 RAII_VAR(struct ast_str *, buf,
159 ast_sip_create_ami_event("AuthDetail", ami), ast_free);
165 if (sip_auth_to_ami(auth, &buf)) {
170 ast_str_append(&buf, 0, "EndpointName: %s\r\n",
171 ast_sorcery_object_get_id(endpoint));
174 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
178 int ast_sip_format_auths_ami(const struct ast_sip_auth_array *auths,
179 struct ast_sip_ami *ami)
181 return ast_sip_for_each_auth(auths, format_ami_auth_handler, ami);
184 static int format_ami_endpoint_auth(const struct ast_sip_endpoint *endpoint,
185 struct ast_sip_ami *ami)
187 ami->arg = (void *)endpoint;
188 if (ast_sip_format_auths_ami(&endpoint->inbound_auths, ami)) {
192 return ast_sip_format_auths_ami(&endpoint->outbound_auths, ami);
195 static struct ast_sip_endpoint_formatter endpoint_auth_formatter = {
196 .format_ami = format_ami_endpoint_auth
199 /*! \brief Initialize sorcery with auth support */
200 int ast_sip_initialize_sorcery_auth(struct ast_sorcery *sorcery)
202 ast_sorcery_apply_default(sorcery, SIP_SORCERY_AUTH_TYPE, "config", "pjsip.conf,criteria=type=auth");
204 if (ast_sorcery_object_register(sorcery, SIP_SORCERY_AUTH_TYPE, auth_alloc, NULL, auth_apply)) {
208 ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "type", "",
210 ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "username",
211 "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_auth, auth_user));
212 ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "password",
213 "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_auth, auth_pass));
214 ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "md5_cred",
215 "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_auth, md5_creds));
216 ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "realm",
217 "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_auth, realm));
218 ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "nonce_lifetime",
219 "32", OPT_UINT_T, 0, FLDSET(struct ast_sip_auth, nonce_lifetime));
220 ast_sorcery_object_field_register_custom(sorcery, SIP_SORCERY_AUTH_TYPE, "auth_type",
221 "userpass", auth_type_handler, auth_type_to_str, 0, 0);
223 ast_sip_register_endpoint_formatter(&endpoint_auth_formatter);