Coverage Report

Created: 2026-10-10 06:26

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.75k
#define AUTHENTICATE_DIGEST_S    "Digest"
38
9.75k
#define AUTHENTICATE_DIGEST_LEN  (sizeof(AUTHENTICATE_DIGEST_S)-1)
39
40
#define LOWER1B(_n) \
41
72.5k
  ((_n < 'A' ||_n > 'Z') ? _n : _n |0x20)
42
#define LOWER4B(_n) \
43
280k
  ((_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
37.0k
  case _hex4: \
49
37.0k
    if (body.len > 5 && LOWER1B(*(body.s+4))==_c5 ) \
50
37.0k
    { \
51
29.2k
      STR_ADVANCE_BY(&body, 5); \
52
29.2k
      state = _new_state; \
53
29.2k
      quoted_val = _quoted; \
54
29.2k
    } else { \
55
7.79k
      STR_ADVANCE_BY(&body, 4); \
56
7.79k
    } \
57
37.0k
    break;
58
59
#define CASE_6B(_hex4,_c5,_c6, _new_state, _quoted) \
60
20.3k
  case _hex4: \
61
20.3k
    if (body.len > 6 && LOWER1B(*(body.s+4))==_c5 && LOWER1B(*(body.s+5))==_c6) \
62
20.3k
    { \
63
623
      STR_ADVANCE_BY(&body, 6); \
64
623
      state = _new_state; \
65
623
      quoted_val = _quoted; \
66
19.7k
    } else { \
67
19.7k
      STR_ADVANCE_BY(&body, 4); \
68
19.7k
    } \
69
20.3k
    break;
70
71
461k
#define OTHER_STATE      0
72
84.3k
#define QOP_STATE        1
73
4.43k
#define REALM_STATE      2
74
19.3k
#define NONCE_STATE      3
75
459
#define STALE_STATE      4
76
252
#define DOMAIN_STATE     5
77
293
#define OPAQUE_STATE     6
78
25.6k
#define ALGORITHM_STATE  7
79
8.55k
#define IK_STATE         8
80
11.1k
#define CK_STATE         9
81
82
26.7k
#define TRB_SCASEMATCH(cp, S) (turbo_casematch(cp, (S), (sizeof(S) - 1)))
83
13.7k
#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.7M
#define STR_ADVANCE_BY(sptr, incr) {int _t = (incr); (sptr)->s += _t; (sptr)->len -= _t;}
88
26.8M
#define STR_ADVANCE(sptr) STR_ADVANCE_BY(sptr, 1)
89
65.2k
#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
65.2k
{
93
65.2k
  if (val->len < slen || !turbo_casematch(val->s, sval, slen))
94
20.4k
    return 0;
95
44.7k
  STR_ADVANCE_BY(val, slen);
96
44.7k
  return 1;
97
65.2k
}
98
99
int parse_qop_value(str val, struct authenticate_body *auth)
100
41.6k
{
101
102
  /* parse first token */
103
41.6k
  if (!STR_ADVANCE_IF_STARTS(&val, "auth"))
104
13.2k
    return -1;
105
28.4k
  if (val.len == 0) {
106
286
    auth->flags |= QOP_AUTH;
107
286
    return 0;
108
286
  }
109
28.1k
  switch (*val.s) {
110
3.00k
    case ' ':
111
3.66k
    case '\t':
112
3.66k
      STR_ADVANCE(&val);
113
3.66k
      auth->flags |= QOP_AUTH;
114
3.66k
      break;
115
3.56k
    case '-':
116
3.56k
      STR_ADVANCE(&val);
117
3.56k
      if (STR_ADVANCE_IF_STARTS(&val, "int")) {
118
2.85k
        auth->flags |= QOP_AUTH_INT;
119
2.85k
      } else
120
712
        return -1;
121
2.85k
      break;
122
19.2k
    case ',':
123
19.2k
      auth->flags |= QOP_AUTH;
124
19.2k
      goto postcomma;
125
1.65k
    default:
126
1.65k
      return -1;
127
28.1k
  }
128
129
6.51k
  if (val.len == 0)
130
1.86k
    return 0;
131
132
4.65k
  trim_leading(&val);
133
134
4.65k
  if (val.len == 0)
135
482
    return 0;
136
4.17k
  if (*val.s != ',')
137
3.39k
    return -1;
138
20.0k
postcomma:
139
20.0k
  STR_ADVANCE(&val);
140
20.0k
  trim_leading(&val);
141
142
  /* parse second token */
143
20.0k
  if (!STR_ADVANCE_IF_STARTS(&val, "auth"))
144
6.53k
    return -1;
145
13.4k
  if (val.len == 0) {
146
344
    auth->flags |= QOP_AUTH;
147
344
    return 0;
148
344
  }
149
13.1k
  if (TRB_STRCASEMATCH(&val, "-int")) {
150
4.43k
    auth->flags |= QOP_AUTH_INT;
151
4.43k
    return 0;
152
4.43k
  } else
153
8.71k
    return -1;
154
13.1k
}
155
156
int parse_authenticate_body( str body, struct authenticate_body *auth)
157
9.76k
{
158
9.76k
  int  n, ret = 0;
159
9.76k
  int state;
160
9.76k
  str name;
161
9.76k
  str val;
162
9.76k
  int quoted_val;
163
164
9.76k
  if (body.len == 0)
165
16
  {
166
16
    LM_ERR("empty body\n");
167
16
    goto error;
168
16
  }
169
170
9.75k
  memset( auth, 0, sizeof(struct authenticate_body));
171
172
  /* parse the "digest" */
173
9.75k
  trim_leading(&body);
174
9.75k
  if (body.len <= AUTHENTICATE_DIGEST_LEN)
175
73
    goto parse_error;
176
9.67k
  if (!TRB_SCASEMATCH(body.s, "digest"))
177
291
    goto parse_error;
178
9.38k
  STR_ADVANCE_BY(&body, AUTHENTICATE_DIGEST_LEN);
179
9.38k
  if (!is_ws(*body.s))
180
16
    goto parse_error;
181
9.37k
  STR_ADVANCE(&body);
182
9.37k
  trim_leading(&body);
183
9.37k
  if (body.len == 0)
184
32
    goto parse_error;
185
186
286k
  while (body.len > 0)
187
282k
  {
188
282k
    state = OTHER_STATE;
189
282k
    quoted_val = 0;
190
    /* get name */
191
282k
    name.s = body.s;
192
282k
    if (body.len > 4)
193
280k
    {
194
280k
      n = LOWER4B( GET4B(body.s) );
195
280k
      switch(n)
196
280k
      {
197
5.82k
        CASE_5B( 0x7265616c, 'm', REALM_STATE, 1); /*realm*/
198
25.6k
        CASE_5B( 0x6e6f6e63, 'e', NONCE_STATE, 1); /*nonce*/
199
5.59k
        CASE_5B( 0x7374616c, 'e', STALE_STATE, 0); /*stale*/
200
10.5k
        CASE_6B( 0x646f6d62, 'i', 'n', DOMAIN_STATE, 1); /*domain*/
201
9.86k
        CASE_6B( 0x6f706171, 'u', 'e', OPAQUE_STATE, 1); /*opaque*/
202
15.5k
        case 0x616c676f: /*algo*/
203
15.5k
          if (body.len > 9 && TRB_SCASEMATCH(body.s+4, "rithm"))
204
12.9k
          {
205
12.9k
            STR_ADVANCE_BY(&body, 9);
206
12.9k
            state = ALGORITHM_STATE;
207
12.9k
          } else {
208
2.62k
            STR_ADVANCE_BY(&body, 4);
209
2.62k
          }
210
15.5k
          break;
211
207k
        default:
212
207k
          if ((n|0xff)==0x716f70ff) /*qop*/
213
42.6k
          {
214
42.6k
            state = QOP_STATE;
215
42.6k
            STR_ADVANCE_BY(&body, 3);
216
165k
          } else if ((n|0xffff) == 0x696bffff) { /*ik*/
217
4.30k
            state = IK_STATE;
218
4.30k
            STR_ADVANCE_BY(&body, 2);
219
160k
          } else if ((n|0xffff) == 0x636bffff) { /*ck*/
220
10.9k
            state = CK_STATE;
221
10.9k
            STR_ADVANCE_BY(&body, 2);
222
10.9k
          }
223
280k
      }
224
280k
    } else if (body.len > 2) {
225
1.34k
      if (body.len > 3) {
226
880
        if (TRB_SCASEMATCH(body.s, "qop"))
227
15
        {
228
15
          STR_ADVANCE_BY(&body, 3);
229
15
          state = QOP_STATE;
230
15
        }
231
880
      } else if (TRB_SCASEMATCH(body.s, "ik"))
232
8
      {
233
8
        STR_ADVANCE_BY(&body, 2);
234
8
        state = IK_STATE;
235
457
      } 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.34k
    }
241
242
    /* parse to the "=" */
243
10.0M
    for(n=0 ; body.len > 0 && !is_ws(*body.s) && *body.s != '=' ; n++)
244
9.78M
      STR_ADVANCE(&body);
245
282k
    if (body.len == 0)
246
2.80k
      goto parse_error;
247
279k
    if (n!=0)
248
179k
      state = OTHER_STATE;
249
279k
    name.len = body.s - name.s;
250
    /* get the '=' */
251
279k
    trim_leading(&body);
252
279k
    if (body.len == 0 || *body.s != '=')
253
1.40k
      goto parse_error;
254
278k
    STR_ADVANCE(&body);
255
    /* get the value (quoted or not) */
256
278k
    trim_leading(&body);
257
278k
    if (body.len <= 1 || (quoted_val && *body.s != '\"'))
258
331
      goto parse_error;
259
278k
    if (!quoted_val && *body.s == '\"')
260
108k
      quoted_val = 1;
261
278k
    if (quoted_val)
262
137k
    {
263
137k
      STR_ADVANCE(&body);
264
137k
      char *cp = memchr(body.s, '\"', body.len);
265
137k
      if (cp == NULL)
266
253
        goto error;
267
136k
      val.s = body.s;
268
136k
      STR_ADVANCE_BY(&body, cp - body.s);
269
141k
    } else {
270
141k
      val.s = body.s;
271
16.6M
      while (body.len > 0 && !is_ws(*body.s) && *body.s != ',')
272
16.4M
        STR_ADVANCE(&body);
273
141k
    }
274
278k
    val.len = body.s - val.s;
275
278k
    if (val.len==0)
276
45.8k
      val.s = 0;
277
    /* consume the closing '"' if quoted */
278
278k
    STR_ADVANCE_BY(&body, quoted_val);
279
278k
    trim_leading(&body);
280
278k
    if (body.len > 0 && *body.s == ',')
281
116k
    {
282
116k
      STR_ADVANCE(&body);
283
116k
      trim_leading(&body);
284
116k
    }
285
286
278k
    LM_DBG("<%.*s>=\"%.*s\" state=%d\n",
287
278k
      name.len,name.s,val.len,val.s,state);
288
289
    /* process the AVP */
290
278k
    switch (state)
291
278k
    {
292
41.6k
      case QOP_STATE:
293
41.6k
        auth->qop = val;
294
41.6k
        if (parse_qop_value(val, auth) < 0)
295
34.2k
          LM_DBG("Unknown token in qop value '%.*s'\n",
296
41.6k
            val.len, val.s);
297
41.6k
        break;
298
4.43k
      case REALM_STATE:
299
4.43k
        auth->realm = val;
300
4.43k
        break;
301
19.3k
      case NONCE_STATE:
302
19.3k
        auth->nonce = val;
303
19.3k
        break;
304
252
      case DOMAIN_STATE:
305
252
        auth->domain = val;
306
252
        break;
307
293
      case OPAQUE_STATE:
308
293
        auth->opaque = val;
309
293
        break;
310
4.24k
      case IK_STATE:
311
4.24k
        auth->ik = val;
312
4.24k
        break;
313
230
      case CK_STATE:
314
230
        auth->ck = val;
315
230
        break;
316
12.6k
      case ALGORITHM_STATE:
317
12.6k
        auth->algorithm = parse_digest_algorithm(&val);
318
12.6k
        if (auth->algorithm == ALG_OTHER) {
319
645
          LM_INFO("bad algorithm \"%.*s\"\n", val.len, val.s);
320
645
          goto error;
321
645
        }
322
12.0k
        break;
323
12.0k
      case STALE_STATE:
324
459
        if (TRB_STRCASEMATCH(&val, "true"))
325
314
        {
326
314
          auth->flags |= AUTHENTICATE_STALE;
327
314
        } 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
413
        break;
333
194k
      default:
334
194k
        break;
335
278k
    }
336
278k
  }
337
338
  /* some checkings */
339
3.86k
  if (auth->nonce.s==0 || auth->realm.s==0)
340
1.76k
  {
341
1.76k
    LM_ERR("realm or nonce missing\n");
342
1.76k
    goto error;
343
1.76k
  }
344
345
2.09k
  return ret;
346
4.94k
parse_error:
347
4.94k
  LM_ERR("parse error in <%.*s> around %ld\n", body.len, body.s, (long)(body.len));
348
7.67k
error:
349
7.67k
  return -1;
350
4.94k
}
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.96k
{
356
9.96k
  void **parsed;
357
9.96k
  struct authenticate_body *auth_body, *ret_auth;
358
9.96k
  int rc, prev_parsed;
359
360
9.96k
  parsed = &(authenticate->parsed);
361
9.96k
  prev_parsed = (*parsed != NULL);
362
9.96k
  ret_auth = NULL;
363
364
11.8k
  while(*parsed == NULL)
365
9.76k
  {
366
9.76k
    auth_body = pkg_malloc(sizeof(struct authenticate_body));
367
9.76k
    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.76k
    rc = parse_authenticate_body(authenticate->body, auth_body);
375
9.76k
    if (rc < 0) {
376
7.67k
      pkg_free(auth_body);
377
7.67k
      *picked_auth = ret_auth;
378
7.67k
      return -1;
379
7.67k
    }
380
381
2.09k
    if (rc == 0 && !ret_auth &&
382
341
        (md == NULL || md->matchf(auth_body, md)))
383
341
      ret_auth = auth_body;
384
385
2.09k
    *parsed = auth_body;
386
387
2.09k
    authenticate = authenticate->sibling;
388
2.09k
    if (authenticate)
389
1.84k
      parsed = &(authenticate->parsed);
390
249
    else
391
249
      break;
392
2.09k
  }
393
2.29k
  if (prev_parsed) {
394
4.09k
    while (!ret_auth && authenticate) {
395
2.04k
      if (authenticate->parsed &&
396
2.04k
          (md == NULL || md->matchf(authenticate->parsed, md)))
397
2.04k
        ret_auth = authenticate->parsed;
398
2.04k
      authenticate = authenticate->sibling;
399
2.04k
    }
400
2.04k
  }
401
2.29k
  *picked_auth = ret_auth;
402
403
2.29k
  return ret_auth ? 0 : -1;
404
9.96k
}
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
3.24k
{
416
3.24k
    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
3.15k
    return parse_authenticate_header(msg->www_authenticate, md,
422
3.15k
  picked_auth);
423
3.24k
}
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.95k
{
436
6.95k
    if ( !msg->proxy_authenticate &&
437
140
  (parse_headers(msg, HDR_PROXY_AUTHENTICATE_F,0)==-1 || !msg->proxy_authenticate)) {
438
140
  return -1;
439
140
    }
440
441
6.81k
    return parse_authenticate_header(msg->proxy_authenticate, md,
442
6.81k
  picked_auth);
443
6.95k
}
444
445
446
void free_authenticate(struct authenticate_body *authenticate_b)
447
2.09k
{
448
2.09k
    if (authenticate_b) {
449
2.09k
  pkg_free(authenticate_b);
450
2.09k
    }
451
452
2.09k
    return;
453
2.09k
}