~ubuntu-branches/ubuntu/trusty/sflphone/trusty

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.1.0/pjsip/src/pjsip/sip_auth_server.c

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (4.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20140128182336-jrsv0k9u6cawc068
Tags: 1.3.0-1
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: sip_auth_server.c 4214 2012-07-25 14:29:28Z nanang $ */
 
2
/* 
 
3
 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
 
4
 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 2 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 
19
 */
 
20
 
 
21
#include <pjsip/sip_auth.h>
 
22
#include <pjsip/sip_auth_parser.h>      /* just to get pjsip_DIGEST_STR */
 
23
#include <pjsip/sip_auth_msg.h>
 
24
#include <pjsip/sip_errno.h>
 
25
#include <pjsip/sip_transport.h>
 
26
#include <pj/string.h>
 
27
#include <pj/assert.h>
 
28
 
 
29
 
 
30
/*
 
31
 * Initialize server authorization session data structure to serve the 
 
32
 * specified realm and to use lookup_func function to look for the credential 
 
33
 * info. 
 
34
 */
 
35
PJ_DEF(pj_status_t) pjsip_auth_srv_init(  pj_pool_t *pool,
 
36
                                          pjsip_auth_srv *auth_srv,
 
37
                                          const pj_str_t *realm,
 
38
                                          pjsip_auth_lookup_cred *lookup,
 
39
                                          unsigned options )
 
40
{
 
41
    PJ_ASSERT_RETURN(pool && auth_srv && realm && lookup, PJ_EINVAL);
 
42
 
 
43
    pj_bzero(auth_srv, sizeof(*auth_srv));
 
44
    pj_strdup( pool, &auth_srv->realm, realm);
 
45
    auth_srv->lookup = lookup;
 
46
    auth_srv->is_proxy = (options & PJSIP_AUTH_SRV_IS_PROXY);
 
47
 
 
48
    return PJ_SUCCESS;
 
49
}
 
50
 
 
51
/*
 
52
 * Initialize server authorization session data structure to serve the 
 
53
 * specified realm and to use lookup_func function to look for the credential 
 
54
 * info. 
 
55
 */
 
56
PJ_DEF(pj_status_t) pjsip_auth_srv_init2(
 
57
                                    pj_pool_t *pool,
 
58
                                    pjsip_auth_srv *auth_srv,
 
59
                                    const pjsip_auth_srv_init_param *param)
 
60
{
 
61
    PJ_ASSERT_RETURN(pool && auth_srv && param, PJ_EINVAL);
 
62
 
 
63
    pj_bzero(auth_srv, sizeof(*auth_srv));
 
64
    pj_strdup( pool, &auth_srv->realm, param->realm);
 
65
    auth_srv->lookup2 = param->lookup2;
 
66
    auth_srv->is_proxy = (param->options & PJSIP_AUTH_SRV_IS_PROXY);
 
67
 
 
68
    return PJ_SUCCESS;
 
69
}
 
70
 
 
71
 
 
72
/* Verify incoming Authorization/Proxy-Authorization header against the 
 
73
 * specified credential.
 
74
 */
 
75
static pj_status_t pjsip_auth_verify( const pjsip_authorization_hdr *hdr,
 
76
                                      const pj_str_t *method,
 
77
                                      const pjsip_cred_info *cred_info )
 
78
{
 
79
    if (pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR) == 0) {
 
80
        char digest_buf[PJSIP_MD5STRLEN];
 
81
        pj_str_t digest;
 
82
        const pjsip_digest_credential *dig = &hdr->credential.digest;
 
83
 
 
84
        /* Check that username and realm match. 
 
85
         * These checks should have been performed before entering this
 
86
         * function.
 
87
         */
 
88
        PJ_ASSERT_RETURN(pj_strcmp(&dig->username, &cred_info->username) == 0,
 
89
                         PJ_EINVALIDOP);
 
90
        PJ_ASSERT_RETURN(pj_strcmp(&dig->realm, &cred_info->realm) == 0,
 
91
                         PJ_EINVALIDOP);
 
92
 
 
93
        /* Prepare for our digest calculation. */
 
94
        digest.ptr = digest_buf;
 
95
        digest.slen = PJSIP_MD5STRLEN;
 
96
 
 
97
        /* Create digest for comparison. */
 
98
        pjsip_auth_create_digest(&digest, 
 
99
                                 &hdr->credential.digest.nonce,
 
100
                                 &hdr->credential.digest.nc, 
 
101
                                 &hdr->credential.digest.cnonce,
 
102
                                 &hdr->credential.digest.qop,
 
103
                                 &hdr->credential.digest.uri,
 
104
                                 &cred_info->realm,
 
105
                                 cred_info, 
 
106
                                 method );
 
107
 
 
108
        /* Compare digest. */
 
109
        return (pj_stricmp(&digest, &hdr->credential.digest.response) == 0) ?
 
110
               PJ_SUCCESS : PJSIP_EAUTHINVALIDDIGEST;
 
111
 
 
112
    } else {
 
113
        pj_assert(!"Unsupported authentication scheme");
 
114
        return PJSIP_EINVALIDAUTHSCHEME;
 
115
    }
 
116
}
 
117
 
 
118
 
 
119
/*
 
120
 * Request the authorization server framework to verify the authorization 
 
121
 * information in the specified request in rdata.
 
122
 */
 
123
PJ_DEF(pj_status_t) pjsip_auth_srv_verify( pjsip_auth_srv *auth_srv,
 
124
                                           pjsip_rx_data *rdata,
 
125
                                           int *status_code)
 
126
{
 
127
    pjsip_authorization_hdr *h_auth;
 
128
    pjsip_msg *msg = rdata->msg_info.msg;
 
129
    pjsip_hdr_e htype;
 
130
    pj_str_t acc_name;
 
131
    pjsip_cred_info cred_info;
 
132
    pj_status_t status;
 
133
 
 
134
    PJ_ASSERT_RETURN(auth_srv && rdata, PJ_EINVAL);
 
135
    PJ_ASSERT_RETURN(msg->type == PJSIP_REQUEST_MSG, PJSIP_ENOTREQUESTMSG);
 
136
 
 
137
    htype = auth_srv->is_proxy ? PJSIP_H_PROXY_AUTHORIZATION : 
 
138
                                 PJSIP_H_AUTHORIZATION;
 
139
 
 
140
    /* Initialize status with 200. */
 
141
    *status_code = 200;
 
142
 
 
143
    /* Find authorization header for our realm. */
 
144
    h_auth = (pjsip_authorization_hdr*) pjsip_msg_find_hdr(msg, htype, NULL);
 
145
    while (h_auth) {
 
146
        if (!pj_stricmp(&h_auth->credential.common.realm, &auth_srv->realm))
 
147
            break;
 
148
 
 
149
        h_auth = h_auth->next;
 
150
        if (h_auth == (void*) &msg->hdr) {
 
151
            h_auth = NULL;
 
152
            break;
 
153
        }
 
154
 
 
155
        h_auth=(pjsip_authorization_hdr*)pjsip_msg_find_hdr(msg,htype,h_auth);
 
156
    }
 
157
 
 
158
    if (!h_auth) {
 
159
        *status_code = auth_srv->is_proxy ? 407 : 401;
 
160
        return PJSIP_EAUTHNOAUTH;
 
161
    }
 
162
 
 
163
    /* Check authorization scheme. */
 
164
    if (pj_stricmp(&h_auth->scheme, &pjsip_DIGEST_STR) == 0)
 
165
        acc_name = h_auth->credential.digest.username;
 
166
    else {
 
167
        *status_code = auth_srv->is_proxy ? 407 : 401;
 
168
        return PJSIP_EINVALIDAUTHSCHEME;
 
169
    }
 
170
 
 
171
    /* Find the credential information for the account. */
 
172
    if (auth_srv->lookup2) {
 
173
        pjsip_auth_lookup_cred_param param;
 
174
 
 
175
        pj_bzero(&param, sizeof(param));
 
176
        param.realm = auth_srv->realm;
 
177
        param.acc_name = acc_name;
 
178
        param.rdata = rdata;
 
179
        status = (*auth_srv->lookup2)(rdata->tp_info.pool, &param, &cred_info);
 
180
        if (status != PJ_SUCCESS) {
 
181
            *status_code = PJSIP_SC_FORBIDDEN;
 
182
            return status;
 
183
        }
 
184
    } else {
 
185
        status = (*auth_srv->lookup)(rdata->tp_info.pool, &auth_srv->realm,
 
186
                                     &acc_name, &cred_info);
 
187
        if (status != PJ_SUCCESS) {
 
188
            *status_code = PJSIP_SC_FORBIDDEN;
 
189
            return status;
 
190
        }
 
191
    }
 
192
 
 
193
    /* Authenticate with the specified credential. */
 
194
    status = pjsip_auth_verify(h_auth, &msg->line.req.method.name, 
 
195
                               &cred_info);
 
196
    if (status != PJ_SUCCESS) {
 
197
        *status_code = PJSIP_SC_FORBIDDEN;
 
198
    }
 
199
    return status;
 
200
}
 
201
 
 
202
 
 
203
/*
 
204
 * Add authentication challenge headers to the outgoing response in tdata. 
 
205
 * Application may specify its customized nonce and opaque for the challenge, 
 
206
 * or can leave the value to NULL to make the function fills them in with 
 
207
 * random characters.
 
208
 */
 
209
PJ_DEF(pj_status_t) pjsip_auth_srv_challenge(  pjsip_auth_srv *auth_srv,
 
210
                                               const pj_str_t *qop,
 
211
                                               const pj_str_t *nonce,
 
212
                                               const pj_str_t *opaque,
 
213
                                               pj_bool_t stale,
 
214
                                               pjsip_tx_data *tdata)
 
215
{
 
216
    pjsip_www_authenticate_hdr *hdr;
 
217
    char nonce_buf[16];
 
218
    pj_str_t random;
 
219
 
 
220
    PJ_ASSERT_RETURN( auth_srv && tdata, PJ_EINVAL );
 
221
 
 
222
    random.ptr = nonce_buf;
 
223
    random.slen = sizeof(nonce_buf);
 
224
 
 
225
    /* Create the header. */
 
226
    if (auth_srv->is_proxy)
 
227
        hdr = pjsip_proxy_authenticate_hdr_create(tdata->pool);
 
228
    else
 
229
        hdr = pjsip_www_authenticate_hdr_create(tdata->pool);
 
230
 
 
231
    /* Initialize header. 
 
232
     * Note: only support digest authentication now.
 
233
     */
 
234
    hdr->scheme = pjsip_DIGEST_STR;
 
235
    hdr->challenge.digest.algorithm = pjsip_MD5_STR;
 
236
    if (nonce) {
 
237
        pj_strdup(tdata->pool, &hdr->challenge.digest.nonce, nonce);
 
238
    } else {
 
239
        pj_create_random_string(nonce_buf, sizeof(nonce_buf));
 
240
        pj_strdup(tdata->pool, &hdr->challenge.digest.nonce, &random);
 
241
    }
 
242
    if (opaque) {
 
243
        pj_strdup(tdata->pool, &hdr->challenge.digest.opaque, opaque);
 
244
    } else {
 
245
        pj_create_random_string(nonce_buf, sizeof(nonce_buf));
 
246
        pj_strdup(tdata->pool, &hdr->challenge.digest.opaque, &random);
 
247
    }
 
248
    if (qop) {
 
249
        pj_strdup(tdata->pool, &hdr->challenge.digest.qop, qop);
 
250
    } else {
 
251
        hdr->challenge.digest.qop.slen = 0;
 
252
    }
 
253
    pj_strdup(tdata->pool, &hdr->challenge.digest.realm, &auth_srv->realm);
 
254
    hdr->challenge.digest.stale = stale;
 
255
 
 
256
    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
 
257
 
 
258
    return PJ_SUCCESS;
 
259
}
 
260