Coverage Report

Created: 2025-11-28 06:23

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
7.83k
#define AUTHENTICATE_DIGEST_S    "Digest"
38
7.83k
#define AUTHENTICATE_DIGEST_LEN  (sizeof(AUTHENTICATE_DIGEST_S)-1)
39
40
#define LOWER1B(_n) \
41
64.2k
  ((_n < 'A' ||_n > 'Z') ? _n : _n |0x20)
42
#define LOWER4B(_n) \
43
165k
  ((_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
21.3k
  case _hex4: \
49
21.3k
    if (body.len > 5 && LOWER1B(*(body.s+4))==_c5 ) \
50
21.3k
    { \
51
11.2k
      STR_ADVANCE_BY(&body, 5); \
52
11.2k
      state = _new_state; \
53
11.2k
      quoted_val = _quoted; \
54
11.2k
    } else { \
55
10.0k
      STR_ADVANCE_BY(&body, 4); \
56
10.0k
    } \
57
21.3k
    break;
58
59
#define CASE_6B(_hex4,_c5,_c6, _new_state, _quoted) \
60
27.1k
  case _hex4: \
61
27.1k
    if (body.len > 6 && LOWER1B(*(body.s+4))==_c5 && LOWER1B(*(body.s+5))==_c6) \
62
27.1k
    { \
63
5.96k
      STR_ADVANCE_BY(&body, 6); \
64
5.96k
      state = _new_state; \
65
5.96k
      quoted_val = _quoted; \
66
21.1k
    } else { \
67
21.1k
      STR_ADVANCE_BY(&body, 4); \
68
21.1k
    } \
69
27.1k
    break;
70
71
278k
#define OTHER_STATE      0
72
44.8k
#define QOP_STATE        1
73
5.22k
#define REALM_STATE      2
74
4.61k
#define NONCE_STATE      3
75
262
#define STALE_STATE      4
76
416
#define DOMAIN_STATE     5
77
426
#define OPAQUE_STATE     6
78
14.5k
#define ALGORITHM_STATE  7
79
1.10k
#define IK_STATE         8
80
864
#define CK_STATE         9
81
82
20.5k
#define TRB_SCASEMATCH(cp, S) (turbo_casematch(cp, (S), (sizeof(S) - 1)))
83
2.82k
#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
3.61M
#define STR_ADVANCE_BY(sptr, incr) {int _t = (incr); (sptr)->s += _t; (sptr)->len -= _t;}
88
3.09M
#define STR_ADVANCE(sptr) STR_ADVANCE_BY(sptr, 1)
89
31.9k
#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
31.9k
{
93
31.9k
  if (val->len < slen || !turbo_casematch(val->s, sval, slen))
94
12.9k
    return 0;
95
19.0k
  STR_ADVANCE_BY(val, slen);
96
19.0k
  return 1;
97
31.9k
}
98
99
int parse_qop_value(str val, struct authenticate_body *auth)
100
21.4k
{
101
102
  /* parse first token */
103
21.4k
  if (!STR_ADVANCE_IF_STARTS(&val, "auth"))
104
6.91k
    return -1;
105
14.4k
  if (val.len == 0) {
106
993
    auth->flags |= QOP_AUTH;
107
993
    return 0;
108
993
  }
109
13.4k
  switch (*val.s) {
110
1.07k
    case ' ':
111
2.17k
    case '\t':
112
2.17k
      STR_ADVANCE(&val);
113
2.17k
      auth->flags |= QOP_AUTH;
114
2.17k
      break;
115
1.94k
    case '-':
116
1.94k
      STR_ADVANCE(&val);
117
1.94k
      if (STR_ADVANCE_IF_STARTS(&val, "int")) {
118
797
        auth->flags |= QOP_AUTH_INT;
119
797
      } else
120
1.14k
        return -1;
121
797
      break;
122
8.01k
    case ',':
123
8.01k
      auth->flags |= QOP_AUTH;
124
8.01k
      goto postcomma;
125
1.35k
    default:
126
1.35k
      return -1;
127
13.4k
  }
128
129
2.97k
  if (val.len == 0)
130
266
    return 0;
131
132
2.71k
  trim_leading(&val);
133
134
2.71k
  if (val.len == 0)
135
388
    return 0;
136
2.32k
  if (*val.s != ',')
137
1.75k
    return -1;
138
8.58k
postcomma:
139
8.58k
  STR_ADVANCE(&val);
140
8.58k
  trim_leading(&val);
141
142
  /* parse second token */
143
8.58k
  if (!STR_ADVANCE_IF_STARTS(&val, "auth"))
144
4.84k
    return -1;
145
3.74k
  if (val.len == 0) {
146
1.20k
    auth->flags |= QOP_AUTH;
147
1.20k
    return 0;
148
1.20k
  }
149
2.54k
  if (TRB_STRCASEMATCH(&val, "-int")) {
150
601
    auth->flags |= QOP_AUTH_INT;
151
601
    return 0;
152
601
  } else
153
1.93k
    return -1;
154
2.54k
}
155
156
int parse_authenticate_body( str body, struct authenticate_body *auth)
157
7.85k
{
158
7.85k
  int  n, ret = 0;
159
7.85k
  int state;
160
7.85k
  str name;
161
7.85k
  str val;
162
7.85k
  int quoted_val;
163
164
7.85k
  if (body.len == 0)
165
22
  {
166
22
    LM_ERR("empty body\n");
167
22
    goto error;
168
22
  }
169
170
7.83k
  memset( auth, 0, sizeof(struct authenticate_body));
171
172
  /* parse the "digest" */
173
7.83k
  trim_leading(&body);
174
7.83k
  if (body.len <= AUTHENTICATE_DIGEST_LEN)
175
60
    goto parse_error;
176
7.77k
  if (!TRB_SCASEMATCH(body.s, "digest"))
177
194
    goto parse_error;
178
7.57k
  STR_ADVANCE_BY(&body, AUTHENTICATE_DIGEST_LEN);
179
7.57k
  if (!is_ws(*body.s))
180
8
    goto parse_error;
181
7.56k
  STR_ADVANCE(&body);
182
7.56k
  trim_leading(&body);
183
7.56k
  if (body.len == 0)
184
51
    goto parse_error;
185
186
170k
  while (body.len > 0)
187
167k
  {
188
167k
    state = OTHER_STATE;
189
167k
    quoted_val = 0;
190
    /* get name */
191
167k
    name.s = body.s;
192
167k
    if (body.len > 4)
193
165k
    {
194
165k
      n = LOWER4B( GET4B(body.s) );
195
165k
      switch(n)
196
165k
      {
197
13.3k
        CASE_5B( 0x7265616c, 'm', REALM_STATE, 1); /*realm*/
198
5.59k
        CASE_5B( 0x6e6f6e63, 'e', NONCE_STATE, 1); /*nonce*/
199
2.41k
        CASE_5B( 0x7374616c, 'e', STALE_STATE, 0); /*stale*/
200
3.05k
        CASE_6B( 0x646f6d62, 'i', 'n', DOMAIN_STATE, 1); /*domain*/
201
24.0k
        CASE_6B( 0x6f706171, 'u', 'e', OPAQUE_STATE, 1); /*opaque*/
202
11.0k
        case 0x616c676f: /*algo*/
203
11.0k
          if (body.len > 9 && TRB_SCASEMATCH(body.s+4, "rithm"))
204
7.36k
          {
205
7.36k
            STR_ADVANCE_BY(&body, 9);
206
7.36k
            state = ALGORITHM_STATE;
207
7.36k
          } else {
208
3.72k
            STR_ADVANCE_BY(&body, 4);
209
3.72k
          }
210
11.0k
          break;
211
106k
        default:
212
106k
          if ((n|0xff)==0x716f70ff) /*qop*/
213
23.4k
          {
214
23.4k
            state = QOP_STATE;
215
23.4k
            STR_ADVANCE_BY(&body, 3);
216
82.6k
          } else if ((n|0xffff) == 0x696bffff) { /*ik*/
217
669
            state = IK_STATE;
218
669
            STR_ADVANCE_BY(&body, 2);
219
82.0k
          } else if ((n|0xffff) == 0x636bffff) { /*ck*/
220
576
            state = CK_STATE;
221
576
            STR_ADVANCE_BY(&body, 2);
222
576
          }
223
165k
      }
224
165k
    } else if (body.len > 2) {
225
1.22k
      if (body.len > 3) {
226
581
        if (TRB_SCASEMATCH(body.s, "qop"))
227
22
        {
228
22
          STR_ADVANCE_BY(&body, 3);
229
22
          state = QOP_STATE;
230
22
        }
231
642
      } else if (TRB_SCASEMATCH(body.s, "ik"))
232
8
      {
233
8
        STR_ADVANCE_BY(&body, 2);
234
8
        state = IK_STATE;
235
634
      } else if (TRB_SCASEMATCH(body.s, "ck"))
236
15
      {
237
15
        STR_ADVANCE_BY(&body, 2);
238
15
        state = CK_STATE;
239
15
      }
240
1.22k
    }
241
242
    /* parse to the "=" */
243
1.31M
    for(n=0 ; body.len > 0 && !is_ws(*body.s) && *body.s != '=' ; n++)
244
1.14M
      STR_ADVANCE(&body);
245
167k
    if (body.len == 0)
246
2.35k
      goto parse_error;
247
164k
    if (n!=0)
248
110k
      state = OTHER_STATE;
249
164k
    name.len = body.s - name.s;
250
    /* get the '=' */
251
164k
    trim_leading(&body);
252
164k
    if (body.len == 0 || *body.s != '=')
253
1.01k
      goto parse_error;
254
163k
    STR_ADVANCE(&body);
255
    /* get the value (quoted or not) */
256
163k
    trim_leading(&body);
257
163k
    if (body.len <= 1 || (quoted_val && *body.s != '\"'))
258
308
      goto parse_error;
259
163k
    if (!quoted_val && *body.s == '\"')
260
68.6k
      quoted_val = 1;
261
163k
    if (quoted_val)
262
85.1k
    {
263
85.1k
      STR_ADVANCE(&body);
264
85.1k
      char *cp = memchr(body.s, '\"', body.len);
265
85.1k
      if (cp == NULL)
266
149
        goto error;
267
85.0k
      val.s = body.s;
268
85.0k
      STR_ADVANCE_BY(&body, cp - body.s);
269
85.0k
    } else {
270
78.4k
      val.s = body.s;
271
1.69M
      while (body.len > 0 && !is_ws(*body.s) && *body.s != ',')
272
1.62M
        STR_ADVANCE(&body);
273
78.4k
    }
274
163k
    val.len = body.s - val.s;
275
163k
    if (val.len==0)
276
6.57k
      val.s = 0;
277
    /* consume the closing '"' if quoted */
278
163k
    STR_ADVANCE_BY(&body, quoted_val);
279
163k
    trim_leading(&body);
280
163k
    if (body.len > 0 && *body.s == ',')
281
55.4k
    {
282
55.4k
      STR_ADVANCE(&body);
283
55.4k
      trim_leading(&body);
284
55.4k
    }
285
286
163k
    LM_DBG("<%.*s>=\"%.*s\" state=%d\n",
287
163k
      name.len,name.s,val.len,val.s,state);
288
289
    /* process the AVP */
290
163k
    switch (state)
291
163k
    {
292
21.4k
      case QOP_STATE:
293
21.4k
        auth->qop = val;
294
21.4k
        if (parse_qop_value(val, auth) < 0)
295
17.9k
          LM_DBG("Unknown token in qop value '%.*s'\n",
296
21.4k
            val.len, val.s);
297
21.4k
        break;
298
5.22k
      case REALM_STATE:
299
5.22k
        auth->realm = val;
300
5.22k
        break;
301
4.61k
      case NONCE_STATE:
302
4.61k
        auth->nonce = val;
303
4.61k
        break;
304
416
      case DOMAIN_STATE:
305
416
        auth->domain = val;
306
416
        break;
307
426
      case OPAQUE_STATE:
308
426
        auth->opaque = val;
309
426
        break;
310
431
      case IK_STATE:
311
431
        auth->ik = val;
312
431
        break;
313
273
      case CK_STATE:
314
273
        auth->ck = val;
315
273
        break;
316
7.15k
      case ALGORITHM_STATE:
317
7.15k
        auth->algorithm = parse_digest_algorithm(&val);
318
7.15k
        if (auth->algorithm == ALG_OTHER) {
319
625
          LM_INFO("bad algorithm \"%.*s\"\n", val.len, val.s);
320
625
          goto error;
321
625
        }
322
6.53k
        break;
323
6.53k
      case STALE_STATE:
324
262
        if (TRB_STRCASEMATCH(&val, "true"))
325
238
        {
326
238
          auth->flags |= AUTHENTICATE_STALE;
327
238
        } else if (!(TRB_STRCASEMATCH(&val, "false")))
328
24
        {
329
24
          LM_ERR("unsupported stale value \"%.*s\"\n",val.len,val.s);
330
24
          goto error;
331
24
        }
332
238
        break;
333
123k
      default:
334
123k
        break;
335
163k
    }
336
163k
  }
337
338
  /* some checkings */
339
3.04k
  if (auth->nonce.s==0 || auth->realm.s==0)
340
1.56k
  {
341
1.56k
    LM_ERR("realm or nonce missing\n");
342
1.56k
    goto error;
343
1.56k
  }
344
345
1.47k
  return ret;
346
3.99k
parse_error:
347
3.99k
  LM_ERR("parse error in <%.*s> around %ld\n", body.len, body.s, (long)(body.len));
348
6.37k
error:
349
6.37k
  return -1;
350
3.99k
}
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.35k
{
356
8.35k
  void **parsed;
357
8.35k
  struct authenticate_body *auth_body, *ret_auth;
358
8.35k
  int rc, prev_parsed;
359
360
8.35k
  parsed = &(authenticate->parsed);
361
8.35k
  prev_parsed = (*parsed != NULL);
362
8.35k
  ret_auth = NULL;
363
364
9.61k
  while(*parsed == NULL)
365
7.85k
  {
366
7.85k
    auth_body = pkg_malloc(sizeof(struct authenticate_body));
367
7.85k
    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
7.85k
    rc = parse_authenticate_body(authenticate->body, auth_body);
375
7.85k
    if (rc < 0) {
376
6.37k
      pkg_free(auth_body);
377
6.37k
      *picked_auth = ret_auth;
378
6.37k
      return -1;
379
6.37k
    }
380
381
1.47k
    if (rc == 0 && !ret_auth &&
382
293
        (md == NULL || md->matchf(auth_body, md)))
383
293
      ret_auth = auth_body;
384
385
1.47k
    *parsed = auth_body;
386
387
1.47k
    authenticate = authenticate->sibling;
388
1.47k
    if (authenticate)
389
1.25k
      parsed = &(authenticate->parsed);
390
214
    else
391
214
      break;
392
1.47k
  }
393
1.97k
  if (prev_parsed) {
394
3.51k
    while (!ret_auth && authenticate) {
395
1.75k
      if (authenticate->parsed &&
396
1.75k
          (md == NULL || md->matchf(authenticate->parsed, md)))
397
1.75k
        ret_auth = authenticate->parsed;
398
1.75k
      authenticate = authenticate->sibling;
399
1.75k
    }
400
1.75k
  }
401
1.97k
  *picked_auth = ret_auth;
402
403
1.97k
  return ret_auth ? 0 : -1;
404
8.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
1.09k
{
416
1.09k
    if ( !msg->www_authenticate &&
417
14
  (parse_headers(msg, HDR_WWW_AUTHENTICATE_F,0)==-1 || !msg->www_authenticate)) {
418
14
  return -1;
419
14
    }
420
421
1.08k
    return parse_authenticate_header(msg->www_authenticate, md,
422
1.08k
  picked_auth);
423
1.09k
}
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.37k
{
436
7.37k
    if ( !msg->proxy_authenticate &&
437
112
  (parse_headers(msg, HDR_PROXY_AUTHENTICATE_F,0)==-1 || !msg->proxy_authenticate)) {
438
112
  return -1;
439
112
    }
440
441
7.26k
    return parse_authenticate_header(msg->proxy_authenticate, md,
442
7.26k
  picked_auth);
443
7.37k
}
444
445
446
void free_authenticate(struct authenticate_body *authenticate_b)
447
1.47k
{
448
1.47k
    if (authenticate_b) {
449
1.47k
  pkg_free(authenticate_b);
450
1.47k
    }
451
452
1.47k
    return;
453
1.47k
}