Coverage Report

Created: 2026-09-14 06:45

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
9.00k
#define AUTHENTICATE_DIGEST_S    "Digest"
38
9.00k
#define AUTHENTICATE_DIGEST_LEN  (sizeof(AUTHENTICATE_DIGEST_S)-1)
39
40
#define LOWER1B(_n) \
41
167k
  ((_n < 'A' ||_n > 'Z') ? _n : _n |0x20)
42
#define LOWER4B(_n) \
43
1.23M
  ((_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
87.4k
  case _hex4: \
49
87.4k
    if (body.len > 5 && LOWER1B(*(body.s+4))==_c5 ) \
50
87.4k
    { \
51
75.4k
      STR_ADVANCE_BY(&body, 5); \
52
75.4k
      state = _new_state; \
53
75.4k
      quoted_val = _quoted; \
54
75.4k
    } else { \
55
12.0k
      STR_ADVANCE_BY(&body, 4); \
56
12.0k
    } \
57
87.4k
    break;
58
59
#define CASE_6B(_hex4,_c5,_c6, _new_state, _quoted) \
60
44.6k
  case _hex4: \
61
44.6k
    if (body.len > 6 && LOWER1B(*(body.s+4))==_c5 && LOWER1B(*(body.s+5))==_c6) \
62
44.6k
    { \
63
31.3k
      STR_ADVANCE_BY(&body, 6); \
64
31.3k
      state = _new_state; \
65
31.3k
      quoted_val = _quoted; \
66
31.3k
    } else { \
67
13.3k
      STR_ADVANCE_BY(&body, 4); \
68
13.3k
    } \
69
44.6k
    break;
70
71
1.80M
#define OTHER_STATE      0
72
1.04M
#define QOP_STATE        1
73
2.82k
#define REALM_STATE      2
74
70.1k
#define NONCE_STATE      3
75
690
#define STALE_STATE      4
76
29.3k
#define DOMAIN_STATE     5
77
307
#define OPAQUE_STATE     6
78
42.6k
#define ALGORITHM_STATE  7
79
4.82k
#define IK_STATE         8
80
1.26k
#define CK_STATE         9
81
82
40.0k
#define TRB_SCASEMATCH(cp, S) (turbo_casematch(cp, (S), (sizeof(S) - 1)))
83
160k
#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
27.9M
#define STR_ADVANCE_BY(sptr, incr) {int _t = (incr); (sptr)->s += _t; (sptr)->len -= _t;}
88
23.1M
#define STR_ADVANCE(sptr) STR_ADVANCE_BY(sptr, 1)
89
985k
#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
985k
{
93
985k
  if (val->len < slen || !turbo_casematch(val->s, sval, slen))
94
228k
    return 0;
95
757k
  STR_ADVANCE_BY(val, slen);
96
757k
  return 1;
97
985k
}
98
99
int parse_qop_value(str val, struct authenticate_body *auth)
100
521k
{
101
102
  /* parse first token */
103
521k
  if (!STR_ADVANCE_IF_STARTS(&val, "auth"))
104
54.9k
    return -1;
105
467k
  if (val.len == 0) {
106
1.30k
    auth->flags |= QOP_AUTH;
107
1.30k
    return 0;
108
1.30k
  }
109
465k
  switch (*val.s) {
110
1.20k
    case ' ':
111
1.57k
    case '\t':
112
1.57k
      STR_ADVANCE(&val);
113
1.57k
      auth->flags |= QOP_AUTH;
114
1.57k
      break;
115
134k
    case '-':
116
134k
      STR_ADVANCE(&val);
117
134k
      if (STR_ADVANCE_IF_STARTS(&val, "int")) {
118
130k
        auth->flags |= QOP_AUTH_INT;
119
130k
      } else
120
4.60k
        return -1;
121
130k
      break;
122
328k
    case ',':
123
328k
      auth->flags |= QOP_AUTH;
124
328k
      goto postcomma;
125
697
    default:
126
697
      return -1;
127
465k
  }
128
129
131k
  if (val.len == 0)
130
97.9k
    return 0;
131
132
33.7k
  trim_leading(&val);
133
134
33.7k
  if (val.len == 0)
135
225
    return 0;
136
33.4k
  if (*val.s != ',')
137
32.9k
    return -1;
138
329k
postcomma:
139
329k
  STR_ADVANCE(&val);
140
329k
  trim_leading(&val);
141
142
  /* parse second token */
143
329k
  if (!STR_ADVANCE_IF_STARTS(&val, "auth"))
144
168k
    return -1;
145
160k
  if (val.len == 0) {
146
356
    auth->flags |= QOP_AUTH;
147
356
    return 0;
148
356
  }
149
160k
  if (TRB_STRCASEMATCH(&val, "-int")) {
150
18.4k
    auth->flags |= QOP_AUTH_INT;
151
18.4k
    return 0;
152
18.4k
  } else
153
141k
    return -1;
154
160k
}
155
156
int parse_authenticate_body( str body, struct authenticate_body *auth)
157
9.01k
{
158
9.01k
  int  n, ret = 0;
159
9.01k
  int state;
160
9.01k
  str name;
161
9.01k
  str val;
162
9.01k
  int quoted_val;
163
164
9.01k
  if (body.len == 0)
165
8
  {
166
8
    LM_ERR("empty body\n");
167
8
    goto error;
168
8
  }
169
170
9.00k
  memset( auth, 0, sizeof(struct authenticate_body));
171
172
  /* parse the "digest" */
173
9.00k
  trim_leading(&body);
174
9.00k
  if (body.len <= AUTHENTICATE_DIGEST_LEN)
175
58
    goto parse_error;
176
8.94k
  if (!TRB_SCASEMATCH(body.s, "digest"))
177
206
    goto parse_error;
178
8.74k
  STR_ADVANCE_BY(&body, AUTHENTICATE_DIGEST_LEN);
179
8.74k
  if (!is_ws(*body.s))
180
8
    goto parse_error;
181
8.73k
  STR_ADVANCE(&body);
182
8.73k
  trim_leading(&body);
183
8.73k
  if (body.len == 0)
184
32
    goto parse_error;
185
186
1.23M
  while (body.len > 0)
187
1.23M
  {
188
1.23M
    state = OTHER_STATE;
189
1.23M
    quoted_val = 0;
190
    /* get name */
191
1.23M
    name.s = body.s;
192
1.23M
    if (body.len > 4)
193
1.23M
    {
194
1.23M
      n = LOWER4B( GET4B(body.s) );
195
1.23M
      switch(n)
196
1.23M
      {
197
9.11k
        CASE_5B( 0x7265616c, 'm', REALM_STATE, 1); /*realm*/
198
71.6k
        CASE_5B( 0x6e6f6e63, 'e', NONCE_STATE, 1); /*nonce*/
199
6.71k
        CASE_5B( 0x7374616c, 'e', STALE_STATE, 0); /*stale*/
200
38.3k
        CASE_6B( 0x646f6d62, 'i', 'n', DOMAIN_STATE, 1); /*domain*/
201
6.32k
        CASE_6B( 0x6f706171, 'u', 'e', OPAQUE_STATE, 1); /*opaque*/
202
29.5k
        case 0x616c676f: /*algo*/
203
29.5k
          if (body.len > 9 && TRB_SCASEMATCH(body.s+4, "rithm"))
204
21.3k
          {
205
21.3k
            STR_ADVANCE_BY(&body, 9);
206
21.3k
            state = ALGORITHM_STATE;
207
21.3k
          } else {
208
8.16k
            STR_ADVANCE_BY(&body, 4);
209
8.16k
          }
210
29.5k
          break;
211
1.06M
        default:
212
1.06M
          if ((n|0xff)==0x716f70ff) /*qop*/
213
524k
          {
214
524k
            state = QOP_STATE;
215
524k
            STR_ADVANCE_BY(&body, 3);
216
544k
          } else if ((n|0xffff) == 0x696bffff) { /*ik*/
217
2.42k
            state = IK_STATE;
218
2.42k
            STR_ADVANCE_BY(&body, 2);
219
542k
          } else if ((n|0xffff) == 0x636bffff) { /*ck*/
220
956
            state = CK_STATE;
221
956
            STR_ADVANCE_BY(&body, 2);
222
956
          }
223
1.23M
      }
224
1.23M
    } else if (body.len > 2) {
225
1.28k
      if (body.len > 3) {
226
697
        if (TRB_SCASEMATCH(body.s, "qop"))
227
22
        {
228
22
          STR_ADVANCE_BY(&body, 3);
229
22
          state = QOP_STATE;
230
22
        }
231
697
      } else if (TRB_SCASEMATCH(body.s, "ik"))
232
8
      {
233
8
        STR_ADVANCE_BY(&body, 2);
234
8
        state = IK_STATE;
235
578
      } else if (TRB_SCASEMATCH(body.s, "ck"))
236
8
      {
237
8
        STR_ADVANCE_BY(&body, 2);
238
8
        state = CK_STATE;
239
8
      }
240
1.28k
    }
241
242
    /* parse to the "=" */
243
11.5M
    for(n=0 ; body.len > 0 && !is_ws(*body.s) && *body.s != '=' ; n++)
244
10.3M
      STR_ADVANCE(&body);
245
1.23M
    if (body.len == 0)
246
2.45k
      goto parse_error;
247
1.23M
    if (n!=0)
248
567k
      state = OTHER_STATE;
249
1.23M
    name.len = body.s - name.s;
250
    /* get the '=' */
251
1.23M
    trim_leading(&body);
252
1.23M
    if (body.len == 0 || *body.s != '=')
253
1.25k
      goto parse_error;
254
1.22M
    STR_ADVANCE(&body);
255
    /* get the value (quoted or not) */
256
1.22M
    trim_leading(&body);
257
1.22M
    if (body.len <= 1 || (quoted_val && *body.s != '\"'))
258
412
      goto parse_error;
259
1.22M
    if (!quoted_val && *body.s == '\"')
260
697k
      quoted_val = 1;
261
1.22M
    if (quoted_val)
262
801k
    {
263
801k
      STR_ADVANCE(&body);
264
801k
      char *cp = memchr(body.s, '\"', body.len);
265
801k
      if (cp == NULL)
266
276
        goto error;
267
801k
      val.s = body.s;
268
801k
      STR_ADVANCE_BY(&body, cp - body.s);
269
801k
    } else {
270
427k
      val.s = body.s;
271
10.4M
      while (body.len > 0 && !is_ws(*body.s) && *body.s != ',')
272
9.98M
        STR_ADVANCE(&body);
273
427k
    }
274
1.22M
    val.len = body.s - val.s;
275
1.22M
    if (val.len==0)
276
68.9k
      val.s = 0;
277
    /* consume the closing '"' if quoted */
278
1.22M
    STR_ADVANCE_BY(&body, quoted_val);
279
1.22M
    trim_leading(&body);
280
1.22M
    if (body.len > 0 && *body.s == ',')
281
402k
    {
282
402k
      STR_ADVANCE(&body);
283
402k
      trim_leading(&body);
284
402k
    }
285
286
1.22M
    LM_DBG("<%.*s>=\"%.*s\" state=%d\n",
287
1.22M
      name.len,name.s,val.len,val.s,state);
288
289
    /* process the AVP */
290
1.22M
    switch (state)
291
1.22M
    {
292
521k
      case QOP_STATE:
293
521k
        auth->qop = val;
294
521k
        if (parse_qop_value(val, auth) < 0)
295
403k
          LM_DBG("Unknown token in qop value '%.*s'\n",
296
521k
            val.len, val.s);
297
521k
        break;
298
2.82k
      case REALM_STATE:
299
2.82k
        auth->realm = val;
300
2.82k
        break;
301
70.1k
      case NONCE_STATE:
302
70.1k
        auth->nonce = val;
303
70.1k
        break;
304
29.3k
      case DOMAIN_STATE:
305
29.3k
        auth->domain = val;
306
29.3k
        break;
307
307
      case OPAQUE_STATE:
308
307
        auth->opaque = val;
309
307
        break;
310
2.39k
      case IK_STATE:
311
2.39k
        auth->ik = val;
312
2.39k
        break;
313
300
      case CK_STATE:
314
300
        auth->ck = val;
315
300
        break;
316
21.3k
      case ALGORITHM_STATE:
317
21.3k
        auth->algorithm = parse_digest_algorithm(&val);
318
21.3k
        if (auth->algorithm == ALG_OTHER) {
319
806
          LM_INFO("bad algorithm \"%.*s\"\n", val.len, val.s);
320
806
          goto error;
321
806
        }
322
20.5k
        break;
323
20.5k
      case STALE_STATE:
324
690
        if (TRB_STRCASEMATCH(&val, "true"))
325
545
        {
326
545
          auth->flags |= AUTHENTICATE_STALE;
327
545
        } else if (!(TRB_STRCASEMATCH(&val, "false")))
328
46
        {
329
46
          LM_ERR("unsupported stale value \"%.*s\"\n",val.len,val.s);
330
46
          goto error;
331
46
        }
332
644
        break;
333
579k
      default:
334
579k
        break;
335
1.22M
    }
336
1.22M
  }
337
338
  /* some checkings */
339
3.45k
  if (auth->nonce.s==0 || auth->realm.s==0)
340
1.72k
  {
341
1.72k
    LM_ERR("realm or nonce missing\n");
342
1.72k
    goto error;
343
1.72k
  }
344
345
1.72k
  return ret;
346
4.42k
parse_error:
347
4.42k
  LM_ERR("parse error in <%.*s> around %ld\n", body.len, body.s, (long)(body.len));
348
7.28k
error:
349
7.28k
  return -1;
350
4.42k
}
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
9.35k
{
356
9.35k
  void **parsed;
357
9.35k
  struct authenticate_body *auth_body, *ret_auth;
358
9.35k
  int rc, prev_parsed;
359
360
9.35k
  parsed = &(authenticate->parsed);
361
9.35k
  prev_parsed = (*parsed != NULL);
362
9.35k
  ret_auth = NULL;
363
364
10.8k
  while(*parsed == NULL)
365
9.01k
  {
366
9.01k
    auth_body = pkg_malloc(sizeof(struct authenticate_body));
367
9.01k
    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
9.01k
    rc = parse_authenticate_body(authenticate->body, auth_body);
375
9.01k
    if (rc < 0) {
376
7.28k
      pkg_free(auth_body);
377
7.28k
      *picked_auth = ret_auth;
378
7.28k
      return -1;
379
7.28k
    }
380
381
1.72k
    if (rc == 0 && !ret_auth &&
382
308
        (md == NULL || md->matchf(auth_body, md)))
383
308
      ret_auth = auth_body;
384
385
1.72k
    *parsed = auth_body;
386
387
1.72k
    authenticate = authenticate->sibling;
388
1.72k
    if (authenticate)
389
1.50k
      parsed = &(authenticate->parsed);
390
225
    else
391
225
      break;
392
1.72k
  }
393
2.07k
  if (prev_parsed) {
394
3.69k
    while (!ret_auth && authenticate) {
395
1.84k
      if (authenticate->parsed &&
396
1.84k
          (md == NULL || md->matchf(authenticate->parsed, md)))
397
1.84k
        ret_auth = authenticate->parsed;
398
1.84k
      authenticate = authenticate->sibling;
399
1.84k
    }
400
1.84k
  }
401
2.07k
  *picked_auth = ret_auth;
402
403
2.07k
  return ret_auth ? 0 : -1;
404
9.35k
}
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.60k
{
416
2.60k
    if ( !msg->www_authenticate &&
417
217
  (parse_headers(msg, HDR_WWW_AUTHENTICATE_F,0)==-1 || !msg->www_authenticate)) {
418
217
  return -1;
419
217
    }
420
421
2.38k
    return parse_authenticate_header(msg->www_authenticate, md,
422
2.38k
  picked_auth);
423
2.60k
}
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
7.12k
{
436
7.12k
    if ( !msg->proxy_authenticate &&
437
154
  (parse_headers(msg, HDR_PROXY_AUTHENTICATE_F,0)==-1 || !msg->proxy_authenticate)) {
438
154
  return -1;
439
154
    }
440
441
6.97k
    return parse_authenticate_header(msg->proxy_authenticate, md,
442
6.97k
  picked_auth);
443
7.12k
}
444
445
446
void free_authenticate(struct authenticate_body *authenticate_b)
447
1.72k
{
448
1.72k
    if (authenticate_b) {
449
1.72k
  pkg_free(authenticate_b);
450
1.72k
    }
451
452
1.72k
    return;
453
1.72k
}