Coverage Report

Created: 2026-09-03 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensips/parser/parse_authenticate.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2011 VoIP Embedded Inc. <http://www.voipembedded.com/>
3
 *
4
 *
5
 * This file is part of opensips, a free SIP server.
6
 *
7
 * opensips is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version
11
 *
12
 * opensips is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
20
 *
21
 * History:
22
 * --------
23
 *  2005-01-31  first version (ramona)
24
 *  2011-03-07  Initial revision (Ovidiu Sas)
25
 */
26
27
#include <stdlib.h>
28
#include <string.h>
29
#include "../dprint.h"
30
#include "../ut.h"
31
#include "../lib/turbocompare.h"
32
#include "../mem/mem.h"
33
#include "msg_parser.h"
34
#include "parse_authenticate.h"
35
36
37
8.02k
#define AUTHENTICATE_DIGEST_S    "Digest"
38
8.02k
#define AUTHENTICATE_DIGEST_LEN  (sizeof(AUTHENTICATE_DIGEST_S)-1)
39
40
#define LOWER1B(_n) \
41
59.5k
  ((_n < 'A' ||_n > 'Z') ? _n : _n |0x20)
42
#define LOWER4B(_n) \
43
271k
  ((_n)|TURBO_LCMASK((unsigned int)_n))
44
#define GET4B(_p) \
45
  ((*(_p)<<24) + (*(_p+1)<<16) + (*(_p+2)<<8) + *(_p+3))
46
47
#define CASE_5B(_hex4,_c5, _new_state, _quoted) \
48
29.8k
  case _hex4: \
49
29.8k
    if (body.len > 5 && LOWER1B(*(body.s+4))==_c5 ) \
50
29.8k
    { \
51
23.4k
      STR_ADVANCE_BY(&body, 5); \
52
23.4k
      state = _new_state; \
53
23.4k
      quoted_val = _quoted; \
54
23.4k
    } else { \
55
6.37k
      STR_ADVANCE_BY(&body, 4); \
56
6.37k
    } \
57
29.8k
    break;
58
59
#define CASE_6B(_hex4,_c5,_c6, _new_state, _quoted) \
60
16.9k
  case _hex4: \
61
16.9k
    if (body.len > 6 && LOWER1B(*(body.s+4))==_c5 && LOWER1B(*(body.s+5))==_c6) \
62
16.9k
    { \
63
11.0k
      STR_ADVANCE_BY(&body, 6); \
64
11.0k
      state = _new_state; \
65
11.0k
      quoted_val = _quoted; \
66
11.0k
    } else { \
67
5.94k
      STR_ADVANCE_BY(&body, 4); \
68
5.94k
    } \
69
16.9k
    break;
70
71
388k
#define OTHER_STATE      0
72
165k
#define QOP_STATE        1
73
9.23k
#define REALM_STATE      2
74
12.5k
#define NONCE_STATE      3
75
838
#define STALE_STATE      4
76
10.5k
#define DOMAIN_STATE     5
77
219
#define OPAQUE_STATE     6
78
14.5k
#define ALGORITHM_STATE  7
79
15.4k
#define IK_STATE         8
80
836
#define CK_STATE         9
81
82
18.2k
#define TRB_SCASEMATCH(cp, S) (turbo_casematch(cp, (S), (sizeof(S) - 1)))
83
47.2k
#define TRB_STRCASEMATCH(sarg, S) (turbo_strcasematch(sarg, (S), (sizeof(S) - 1)))
84
#define TRB_STRCASESTARTS(sarg, S) ((sarg)->len >= (sizeof(S) - 1) && \
85
  turbo_casematch((sarg)->s, (S), (sizeof(S) - 1)))
86
87
6.26M
#define STR_ADVANCE_BY(sptr, incr) {int _t = (incr); (sptr)->s += _t; (sptr)->len -= _t;}
88
5.27M
#define STR_ADVANCE(sptr) STR_ADVANCE_BY(sptr, 1)
89
142k
#define STR_ADVANCE_IF_STARTS(sarg, S) (str_advance_if_starts((sarg), (S), (sizeof(S) - 1)))
90
91
static int str_advance_if_starts(str *val, const char *sval, size_t slen)
92
142k
{
93
142k
  if (val->len < slen || !turbo_casematch(val->s, sval, slen))
94
26.7k
    return 0;
95
116k
  STR_ADVANCE_BY(val, slen);
96
116k
  return 1;
97
142k
}
98
99
int parse_qop_value(str val, struct authenticate_body *auth)
100
81.4k
{
101
102
  /* parse first token */
103
81.4k
  if (!STR_ADVANCE_IF_STARTS(&val, "auth"))
104
13.9k
    return -1;
105
67.4k
  if (val.len == 0) {
106
1.38k
    auth->flags |= QOP_AUTH;
107
1.38k
    return 0;
108
1.38k
  }
109
66.1k
  switch (*val.s) {
110
4.31k
    case ' ':
111
6.97k
    case '\t':
112
6.97k
      STR_ADVANCE(&val);
113
6.97k
      auth->flags |= QOP_AUTH;
114
6.97k
      break;
115
2.84k
    case '-':
116
2.84k
      STR_ADVANCE(&val);
117
2.84k
      if (STR_ADVANCE_IF_STARTS(&val, "int")) {
118
2.07k
        auth->flags |= QOP_AUTH_INT;
119
2.07k
      } else
120
768
        return -1;
121
2.07k
      break;
122
55.6k
    case ',':
123
55.6k
      auth->flags |= QOP_AUTH;
124
55.6k
      goto postcomma;
125
699
    default:
126
699
      return -1;
127
66.1k
  }
128
129
9.04k
  if (val.len == 0)
130
1.79k
    return 0;
131
132
7.25k
  trim_leading(&val);
133
134
7.25k
  if (val.len == 0)
135
615
    return 0;
136
6.64k
  if (*val.s != ',')
137
3.67k
    return -1;
138
58.5k
postcomma:
139
58.5k
  STR_ADVANCE(&val);
140
58.5k
  trim_leading(&val);
141
142
  /* parse second token */
143
58.5k
  if (!STR_ADVANCE_IF_STARTS(&val, "auth"))
144
11.9k
    return -1;
145
46.5k
  if (val.len == 0) {
146
496
    auth->flags |= QOP_AUTH;
147
496
    return 0;
148
496
  }
149
46.0k
  if (TRB_STRCASEMATCH(&val, "-int")) {
150
14.4k
    auth->flags |= QOP_AUTH_INT;
151
14.4k
    return 0;
152
14.4k
  } else
153
31.6k
    return -1;
154
46.0k
}
155
156
int parse_authenticate_body( str body, struct authenticate_body *auth)
157
8.04k
{
158
8.04k
  int  n, ret = 0;
159
8.04k
  int state;
160
8.04k
  str name;
161
8.04k
  str val;
162
8.04k
  int quoted_val;
163
164
8.04k
  if (body.len == 0)
165
22
  {
166
22
    LM_ERR("empty body\n");
167
22
    goto error;
168
22
  }
169
170
8.02k
  memset( auth, 0, sizeof(struct authenticate_body));
171
172
  /* parse the "digest" */
173
8.02k
  trim_leading(&body);
174
8.02k
  if (body.len <= AUTHENTICATE_DIGEST_LEN)
175
58
    goto parse_error;
176
7.96k
  if (!TRB_SCASEMATCH(body.s, "digest"))
177
346
    goto parse_error;
178
7.62k
  STR_ADVANCE_BY(&body, AUTHENTICATE_DIGEST_LEN);
179
7.62k
  if (!is_ws(*body.s))
180
16
    goto parse_error;
181
7.60k
  STR_ADVANCE(&body);
182
7.60k
  trim_leading(&body);
183
7.60k
  if (body.len == 0)
184
31
    goto parse_error;
185
186
277k
  while (body.len > 0)
187
273k
  {
188
273k
    state = OTHER_STATE;
189
273k
    quoted_val = 0;
190
    /* get name */
191
273k
    name.s = body.s;
192
273k
    if (body.len > 4)
193
271k
    {
194
271k
      n = LOWER4B( GET4B(body.s) );
195
271k
      switch(n)
196
271k
      {
197
13.2k
        CASE_5B( 0x7265616c, 'm', REALM_STATE, 1); /*realm*/
198
14.5k
        CASE_5B( 0x6e6f6e63, 'e', NONCE_STATE, 1); /*nonce*/
199
2.06k
        CASE_5B( 0x7374616c, 'e', STALE_STATE, 0); /*stale*/
200
14.8k
        CASE_6B( 0x646f6d62, 'i', 'n', DOMAIN_STATE, 1); /*domain*/
201
2.12k
        CASE_6B( 0x6f706171, 'u', 'e', OPAQUE_STATE, 1); /*opaque*/
202
8.70k
        case 0x616c676f: /*algo*/
203
8.70k
          if (body.len > 9 && TRB_SCASEMATCH(body.s+4, "rithm"))
204
7.44k
          {
205
7.44k
            STR_ADVANCE_BY(&body, 9);
206
7.44k
            state = ALGORITHM_STATE;
207
7.44k
          } else {
208
1.25k
            STR_ADVANCE_BY(&body, 4);
209
1.25k
          }
210
8.70k
          break;
211
216k
        default:
212
216k
          if ((n|0xff)==0x716f70ff) /*qop*/
213
84.4k
          {
214
84.4k
            state = QOP_STATE;
215
84.4k
            STR_ADVANCE_BY(&body, 3);
216
131k
          } else if ((n|0xffff) == 0x696bffff) { /*ik*/
217
7.77k
            state = IK_STATE;
218
7.77k
            STR_ADVANCE_BY(&body, 2);
219
124k
          } else if ((n|0xffff) == 0x636bffff) { /*ck*/
220
586
            state = CK_STATE;
221
586
            STR_ADVANCE_BY(&body, 2);
222
586
          }
223
271k
      }
224
271k
    } else if (body.len > 2) {
225
1.30k
      if (body.len > 3) {
226
853
        if (TRB_SCASEMATCH(body.s, "qop"))
227
29
        {
228
29
          STR_ADVANCE_BY(&body, 3);
229
29
          state = QOP_STATE;
230
29
        }
231
853
      } else if (TRB_SCASEMATCH(body.s, "ik"))
232
8
      {
233
8
        STR_ADVANCE_BY(&body, 2);
234
8
        state = IK_STATE;
235
441
      } else if (TRB_SCASEMATCH(body.s, "ck"))
236
9
      {
237
9
        STR_ADVANCE_BY(&body, 2);
238
9
        state = CK_STATE;
239
9
      }
240
1.30k
    }
241
242
    /* parse to the "=" */
243
2.39M
    for(n=0 ; body.len > 0 && !is_ws(*body.s) && *body.s != '=' ; n++)
244
2.11M
      STR_ADVANCE(&body);
245
273k
    if (body.len == 0)
246
2.18k
      goto parse_error;
247
271k
    if (n!=0)
248
114k
      state = OTHER_STATE;
249
271k
    name.len = body.s - name.s;
250
    /* get the '=' */
251
271k
    trim_leading(&body);
252
271k
    if (body.len == 0 || *body.s != '=')
253
978
      goto parse_error;
254
270k
    STR_ADVANCE(&body);
255
    /* get the value (quoted or not) */
256
270k
    trim_leading(&body);
257
270k
    if (body.len <= 1 || (quoted_val && *body.s != '\"'))
258
300
      goto parse_error;
259
270k
    if (!quoted_val && *body.s == '\"')
260
147k
      quoted_val = 1;
261
270k
    if (quoted_val)
262
180k
    {
263
180k
      STR_ADVANCE(&body);
264
180k
      char *cp = memchr(body.s, '\"', body.len);
265
180k
      if (cp == NULL)
266
206
        goto error;
267
180k
      val.s = body.s;
268
180k
      STR_ADVANCE_BY(&body, cp - body.s);
269
180k
    } else {
270
89.8k
      val.s = body.s;
271
2.62M
      while (body.len > 0 && !is_ws(*body.s) && *body.s != ',')
272
2.53M
        STR_ADVANCE(&body);
273
89.8k
    }
274
270k
    val.len = body.s - val.s;
275
270k
    if (val.len==0)
276
29.9k
      val.s = 0;
277
    /* consume the closing '"' if quoted */
278
270k
    STR_ADVANCE_BY(&body, quoted_val);
279
270k
    trim_leading(&body);
280
270k
    if (body.len > 0 && *body.s == ',')
281
88.8k
    {
282
88.8k
      STR_ADVANCE(&body);
283
88.8k
      trim_leading(&body);
284
88.8k
    }
285
286
270k
    LM_DBG("<%.*s>=\"%.*s\" state=%d\n",
287
270k
      name.len,name.s,val.len,val.s,state);
288
289
    /* process the AVP */
290
270k
    switch (state)
291
270k
    {
292
81.4k
      case QOP_STATE:
293
81.4k
        auth->qop = val;
294
81.4k
        if (parse_qop_value(val, auth) < 0)
295
62.7k
          LM_DBG("Unknown token in qop value '%.*s'\n",
296
81.4k
            val.len, val.s);
297
81.4k
        break;
298
9.23k
      case REALM_STATE:
299
9.23k
        auth->realm = val;
300
9.23k
        break;
301
12.5k
      case NONCE_STATE:
302
12.5k
        auth->nonce = val;
303
12.5k
        break;
304
10.5k
      case DOMAIN_STATE:
305
10.5k
        auth->domain = val;
306
10.5k
        break;
307
219
      case OPAQUE_STATE:
308
219
        auth->opaque = val;
309
219
        break;
310
7.70k
      case IK_STATE:
311
7.70k
        auth->ik = val;
312
7.70k
        break;
313
241
      case CK_STATE:
314
241
        auth->ck = val;
315
241
        break;
316
7.13k
      case ALGORITHM_STATE:
317
7.13k
        auth->algorithm = parse_digest_algorithm(&val);
318
7.13k
        if (auth->algorithm == ALG_OTHER) {
319
567
          LM_INFO("bad algorithm \"%.*s\"\n", val.len, val.s);
320
567
          goto error;
321
567
        }
322
6.57k
        break;
323
6.57k
      case STALE_STATE:
324
838
        if (TRB_STRCASEMATCH(&val, "true"))
325
559
        {
326
559
          auth->flags |= AUTHENTICATE_STALE;
327
559
        } else if (!(TRB_STRCASEMATCH(&val, "false")))
328
60
        {
329
60
          LM_ERR("unsupported stale value \"%.*s\"\n",val.len,val.s);
330
60
          goto error;
331
60
        }
332
778
        break;
333
140k
      default:
334
140k
        break;
335
270k
    }
336
270k
  }
337
338
  /* some checkings */
339
3.27k
  if (auth->nonce.s==0 || auth->realm.s==0)
340
1.64k
  {
341
1.64k
    LM_ERR("realm or nonce missing\n");
342
1.64k
    goto error;
343
1.64k
  }
344
345
1.62k
  return ret;
346
3.91k
parse_error:
347
3.91k
  LM_ERR("parse error in <%.*s> around %ld\n", body.len, body.s, (long)(body.len));
348
6.41k
error:
349
6.41k
  return -1;
350
3.91k
}
351
352
353
int parse_authenticate_header(struct hdr_field *authenticate,
354
    const struct match_auth_hf_desc *md, struct authenticate_body **picked_auth)
355
8.53k
{
356
8.53k
  void **parsed;
357
8.53k
  struct authenticate_body *auth_body, *ret_auth;
358
8.53k
  int rc, prev_parsed;
359
360
8.53k
  parsed = &(authenticate->parsed);
361
8.53k
  prev_parsed = (*parsed != NULL);
362
8.53k
  ret_auth = NULL;
363
364
9.93k
  while(*parsed == NULL)
365
8.04k
  {
366
8.04k
    auth_body = pkg_malloc(sizeof(struct authenticate_body));
367
8.04k
    if (auth_body == NULL)
368
0
    {
369
0
      LM_ERR("oom\n");
370
0
      *picked_auth = ret_auth;
371
0
      return -1;
372
0
    }
373
374
8.04k
    rc = parse_authenticate_body(authenticate->body, auth_body);
375
8.04k
    if (rc < 0) {
376
6.41k
      pkg_free(auth_body);
377
6.41k
      *picked_auth = ret_auth;
378
6.41k
      return -1;
379
6.41k
    }
380
381
1.62k
    if (rc == 0 && !ret_auth &&
382
315
        (md == NULL || md->matchf(auth_body, md)))
383
315
      ret_auth = auth_body;
384
385
1.62k
    *parsed = auth_body;
386
387
1.62k
    authenticate = authenticate->sibling;
388
1.62k
    if (authenticate)
389
1.40k
      parsed = &(authenticate->parsed);
390
224
    else
391
224
      break;
392
1.62k
  }
393
2.11k
  if (prev_parsed) {
394
3.78k
    while (!ret_auth && authenticate) {
395
1.89k
      if (authenticate->parsed &&
396
1.89k
          (md == NULL || md->matchf(authenticate->parsed, md)))
397
1.89k
        ret_auth = authenticate->parsed;
398
1.89k
      authenticate = authenticate->sibling;
399
1.89k
    }
400
1.89k
  }
401
2.11k
  *picked_auth = ret_auth;
402
403
2.11k
  return ret_auth ? 0 : -1;
404
8.53k
}
405
406
/*
407
 * This method is used to parse WWW-Authenticate header.
408
 *
409
 * params: msg : sip msg
410
 * returns 0 on success,
411
 *        -1 on failure.
412
 */
413
int parse_www_authenticate_header(struct sip_msg *msg,
414
    const struct match_auth_hf_desc *md, struct authenticate_body **picked_auth)
415
2.66k
{
416
2.66k
    if ( !msg->www_authenticate &&
417
98
  (parse_headers(msg, HDR_WWW_AUTHENTICATE_F,0)==-1 || !msg->www_authenticate)) {
418
98
  return -1;
419
98
    }
420
421
2.56k
    return parse_authenticate_header(msg->www_authenticate, md,
422
2.56k
  picked_auth);
423
2.66k
}
424
425
426
/*
427
 * This method is used to parse Proxy-Authenticate header.
428
 *
429
 * params: msg : sip msg
430
 * returns 0 on success,
431
 *        -1 on failure.
432
 */
433
int parse_proxy_authenticate_header(struct sip_msg *msg,
434
    const struct match_auth_hf_desc *md, struct authenticate_body **picked_auth)
435
6.11k
{
436
6.11k
    if ( !msg->proxy_authenticate &&
437
147
  (parse_headers(msg, HDR_PROXY_AUTHENTICATE_F,0)==-1 || !msg->proxy_authenticate)) {
438
147
  return -1;
439
147
    }
440
441
5.96k
    return parse_authenticate_header(msg->proxy_authenticate, md,
442
5.96k
  picked_auth);
443
6.11k
}
444
445
446
void free_authenticate(struct authenticate_body *authenticate_b)
447
1.62k
{
448
1.62k
    if (authenticate_b) {
449
1.62k
  pkg_free(authenticate_b);
450
1.62k
    }
451
452
1.62k
    return;
453
1.62k
}