and added files
[bcm963xx.git] / userapps / opensource / libosip2 / src / osipparser2 / osip_www_authenticate.c
1 /*
2   The oSIP library implements the Session Initiation Protocol (SIP -rfc3261-)
3   Copyright (C) 2001,2002,2003  Aymeric MOIZARD jack@atosc.org
4   
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9   
10   This library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14   
15   You should have received a copy of the GNU Lesser General Public
16   License along with this library; if not, write to the Free Software
17   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20
21 #include <stdlib.h>
22 #include <stdio.h>
23
24 #include <osipparser2/osip_port.h>
25 #include <osipparser2/osip_message.h>
26 #include <osipparser2/osip_parser.h>
27 #include "parser.h"
28
29 int
30 osip_www_authenticate_init (osip_www_authenticate_t ** dest)
31 {
32   *dest =
33     (osip_www_authenticate_t *)
34     osip_malloc (sizeof (osip_www_authenticate_t));
35   if (*dest == NULL)
36     return -1;
37   (*dest)->auth_type = NULL;
38   (*dest)->realm = NULL;
39   (*dest)->domain = NULL;       /* optionnal */
40   (*dest)->nonce = NULL;
41   (*dest)->opaque = NULL;       /* optionnal */
42   (*dest)->stale = NULL;        /* optionnal */
43   (*dest)->algorithm = NULL;    /* optionnal */
44   (*dest)->qop_options = NULL;  /* optionnal (contains a list of qop-value) */
45   (*dest)->auth_param = NULL;
46   return 0;
47 }
48
49 /* fills the www-authenticate header of message.               */
50 /* INPUT :  char *hvalue | value of header.   */
51 /* OUTPUT: osip_message_t *sip | structure to save results. */
52 /* returns -1 on error. */
53 int
54 osip_message_set_www_authenticate (osip_message_t * sip, const char *hvalue)
55 {
56   osip_www_authenticate_t *www_authenticate;
57   int i;
58
59   if (hvalue == NULL || hvalue[0] == '\0')
60     return 0;
61
62   if (sip == NULL || sip->www_authenticates == NULL)
63     return -1;
64   i = osip_www_authenticate_init (&www_authenticate);
65   if (i != 0)
66     return -1;
67   i = osip_www_authenticate_parse (www_authenticate, hvalue);
68   if (i != 0)
69     {
70       osip_www_authenticate_free (www_authenticate);
71       return -1;
72     }
73   sip->message_property = 2;
74   osip_list_add (sip->www_authenticates, www_authenticate, -1);
75   return 0;
76 }
77
78 int
79 __osip_quoted_string_set (const char *name, const char *str,
80                           char **result, const char **next)
81 {
82   *next = str;
83   if (*result != NULL)
84     return 0;                   /* already parsed */
85   *next = NULL;
86   while ((' ' == *str) || ('\t' == *str) || (',' == *str))
87     if (*str)
88       str++;
89     else
90       return -1;                /* bad header format */
91
92   if (strlen (str) <= strlen (name))
93     return -1;                  /* bad header format... */
94   if (osip_strncasecmp (name, str, strlen (name)) == 0)
95     {
96       const char *quote1;
97       const char *quote2;
98       const char *tmp;
99       const char *hack = strchr (str, '=');
100       
101       if (hack == NULL)
102         return -1;
103
104       while (' ' == *(hack - 1))        /* get rid of extra spaces */
105         hack--;
106       if ((size_t) (hack - str) != strlen (name))
107         {
108           *next = str;
109           return 0;
110         }
111
112       quote1 = __osip_quote_find (str);
113       if (quote1 == NULL)
114         return -1;              /* bad header format... */
115       quote2 = __osip_quote_find (quote1 + 1);
116       if (quote2 == NULL)
117         return -1;              /* bad header format... */
118       if (quote2 - quote1 == 1)
119         {
120           /* this is a special case! The quote contains nothing! */
121           /* example:   Digest opaque="",cnonce=""               */
122           /* in this case, we just forget the parameter... this  */
123           /* this should prevent from user manipulating empty    */
124           /* strings */
125           tmp = quote2 + 1;     /* next element start here */
126           for (; *tmp == ' ' || *tmp == '\t'; tmp++)
127             {
128             }
129           for (; *tmp == '\n' || *tmp == '\r'; tmp++)
130             {
131             }                   /* skip LWS */
132           *next = NULL;
133           if (*tmp == '\0')     /* end of header detected */
134             return 0;
135           if (*tmp != '\t' && *tmp != ' ')
136             /* LWS here ? */
137             *next = tmp;
138           else
139             {                   /* it is: skip it... */
140               for (; *tmp == ' ' || *tmp == '\t'; tmp++)
141                 {
142                 }
143               if (*tmp == '\0') /* end of header detected */
144                 return 0;
145               *next = tmp;
146             }
147           return 0;
148         }
149       *result = (char *) osip_malloc (quote2 - quote1 + 3);
150       if (*result == NULL)
151         return -1;
152       osip_strncpy (*result, quote1, quote2 - quote1 + 1);
153       tmp = quote2 + 1;         /* next element start here */
154       for (; *tmp == ' ' || *tmp == '\t'; tmp++)
155         {
156         }
157       for (; *tmp == '\n' || *tmp == '\r'; tmp++)
158         {
159         }                       /* skip LWS */
160       *next = NULL;
161       if (*tmp == '\0')         /* end of header detected */
162         return 0;
163       if (*tmp != '\t' && *tmp != ' ')
164         /* LWS here ? */
165         *next = tmp;
166       else
167         {                       /* it is: skip it... */
168           for (; *tmp == ' ' || *tmp == '\t'; tmp++)
169             {
170             }
171           if (*tmp == '\0')     /* end of header detected */
172             return 0;
173           *next = tmp;
174         }
175     }
176   else
177     *next = str;                /* wrong header asked! */
178   return 0;
179 }
180
181 int
182 __osip_token_set (const char *name, const char *str, char **result,
183                   const char **next)
184 {
185   const char *beg;
186   const char *tmp;
187
188   *next = str;
189   if (*result != NULL)
190     return 0;                   /* already parsed */
191   *next = NULL;
192
193   beg = strchr (str, '=');
194   if (beg == NULL)
195     return -1;                  /* bad header format... */
196
197   if (strlen (str) < 6)
198     return 0;                   /* end of header... */
199
200   while ((' ' == *str) || ('\t' == *str) || (',' == *str))
201     if (*str)
202       str++;
203     else
204       return -1;                /* bad header format */
205
206   if (osip_strncasecmp (name, str, strlen (name)) == 0)
207     {
208       const char *end;
209
210       end = strchr (str, ',');
211       if (end == NULL)
212         end = str + strlen (str);       /* This is the end of the header */
213
214       if (end - beg < 2)
215         return -1;
216       *result = (char *) osip_malloc (end - beg);
217       if (*result == NULL)
218         return -1;
219       osip_strncpy (*result, beg + 1, end - beg - 1);
220       osip_clrspace (*result);
221
222       /* make sure the element does not contain more parameter */
223       tmp = (*end) ? (end + 1) : end;
224       for (; *tmp == ' ' || *tmp == '\t'; tmp++)
225         {
226         }
227       for (; *tmp == '\n' || *tmp == '\r'; tmp++)
228         {
229         }                       /* skip LWS */
230       *next = NULL;
231       if (*tmp == '\0')         /* end of header detected */
232         return 0;
233       if (*tmp != '\t' && *tmp != ' ')
234         /* LWS here ? */
235         *next = tmp;
236       else
237         {                       /* it is: skip it... */
238           for (; *tmp == ' ' || *tmp == '\t'; tmp++)
239             {
240             }
241           if (*tmp == '\0')     /* end of header detected */
242             return 0;
243           *next = tmp;
244         }
245     }
246   else
247     *next = str;                /* next element start here */
248   return 0;
249 }
250
251 /* fills the www-authenticate strucuture.                      */
252 /* INPUT : char *hvalue | value of header.         */
253 /* OUTPUT: osip_message_t *sip | structure to save results. */
254 /* returns -1 on error. */
255 /* TODO:
256    digest-challenge tken has no order preference??
257    verify many situations (extra SP....)
258 */
259 int
260 osip_www_authenticate_parse (osip_www_authenticate_t * wwwa,
261                              const char *hvalue)
262 {
263   const char *space;
264   const char *next = NULL;
265
266   space = strchr (hvalue, ' '); /* SEARCH FOR SPACE */
267   if (space == NULL)
268     return -1;
269
270   if (space - hvalue + 1 < 2)
271     return -1;
272   wwwa->auth_type = (char *) osip_malloc (space - hvalue + 1);
273   if (wwwa->auth_type == NULL)
274     return -1;
275   osip_strncpy (wwwa->auth_type, hvalue, space - hvalue);
276
277   for (;;)
278     {
279       int parse_ok = 0;
280
281       if (__osip_quoted_string_set ("realm", space, &(wwwa->realm), &next))
282         return -1;
283       if (next == NULL)
284         return 0;               /* end of header detected! */
285       else if (next != space)
286         {
287           space = next;
288           parse_ok++;
289         }
290       if (__osip_quoted_string_set ("domain", space, &(wwwa->domain), &next))
291         return -1;
292       if (next == NULL)
293         return 0;               /* end of header detected! */
294       else if (next != space)
295         {
296           space = next;
297           parse_ok++;
298         }
299       if (__osip_quoted_string_set ("nonce", space, &(wwwa->nonce), &next))
300         return -1;
301       if (next == NULL)
302         return 0;               /* end of header detected! */
303       else if (next != space)
304         {
305           space = next;
306           parse_ok++;
307         }
308       if (__osip_quoted_string_set ("opaque", space, &(wwwa->opaque), &next))
309         return -1;
310       if (next == NULL)
311         return 0;               /* end of header detected! */
312       else if (next != space)
313         {
314           space = next;
315           parse_ok++;
316         }
317       if (__osip_token_set ("stale", space, &(wwwa->stale), &next))
318         return -1;
319       if (next == NULL)
320         return 0;               /* end of header detected! */
321       else if (next != space)
322         {
323           space = next;
324           parse_ok++;
325         }
326       if (__osip_token_set ("algorithm", space, &(wwwa->algorithm), &next))
327         return -1;
328       if (next == NULL)
329         return 0;               /* end of header detected! */
330       else if (next != space)
331         {
332           space = next;
333           parse_ok++;
334         }
335       if (__osip_quoted_string_set
336           ("qop", space, &(wwwa->qop_options), &next))
337         return -1;
338       if (next == NULL)
339         return 0;               /* end of header detected! */
340       else if (next != space)
341         {
342           space = next;
343           parse_ok++;
344         }
345       if (0 == parse_ok)
346         {
347           char *quote1, *quote2, *tmp;
348
349           /* CAUTION */
350           /* parameter not understood!!! I'm too lazy to handle IT */
351           /* let's simply bypass it */
352           if (strlen (space) < 1)
353             return 0;
354           tmp = strchr (space + 1, ',');
355           if (tmp == NULL)      /* it was the last header */
356             return 0;
357           quote1 = __osip_quote_find (space);
358           if ((quote1 != NULL) && (quote1 < tmp))       /* this may be a quoted string! */
359             {
360               quote2 = __osip_quote_find (quote1 + 1);
361               if (quote2 == NULL)
362                 return -1;      /* bad header format... */
363               if (tmp < quote2) /* the comma is inside the quotes! */
364                 space = strchr (quote2, ',');
365               else
366                 space = tmp;
367               if (space == NULL)        /* it was the last header */
368                 return 0;
369             }
370           else
371             space = tmp;
372           /* continue parsing... */
373         }
374     }
375   return 0;                     /* ok */
376 }
377
378 /* returns the www_authenticate header.            */
379 /* INPUT : osip_message_t *sip | sip message.   */
380 /* returns null on error. */
381 int
382 osip_message_get_www_authenticate (const osip_message_t * sip, int pos,
383                                    osip_www_authenticate_t ** dest)
384 {
385   osip_www_authenticate_t *www_authenticate;
386
387   *dest = NULL;
388   if (osip_list_size (sip->www_authenticates) <= pos)
389     return -1;                  /* does not exist */
390
391   www_authenticate =
392     (osip_www_authenticate_t *) osip_list_get (sip->www_authenticates, pos);
393
394   *dest = www_authenticate;
395   return pos;
396 }
397
398 char *
399 osip_www_authenticate_get_auth_type (osip_www_authenticate_t *
400                                      www_authenticate)
401 {
402   return www_authenticate->auth_type;
403 }
404
405 void
406 osip_www_authenticate_set_auth_type (osip_www_authenticate_t *
407                                      www_authenticate, char *auth_type)
408 {
409   www_authenticate->auth_type = (char *) auth_type;
410 }
411
412 char *
413 osip_www_authenticate_get_realm (osip_www_authenticate_t * www_authenticate)
414 {
415   return www_authenticate->realm;
416 }
417
418 void
419 osip_www_authenticate_set_realm (osip_www_authenticate_t * www_authenticate,
420                                  char *realm)
421 {
422   www_authenticate->realm = (char *) realm;
423 }
424
425 char *
426 osip_www_authenticate_get_domain (osip_www_authenticate_t * www_authenticate)
427 {
428   return www_authenticate->domain;
429 }
430
431 void
432 osip_www_authenticate_set_domain (osip_www_authenticate_t * www_authenticate,
433                                   char *domain)
434 {
435   www_authenticate->domain = (char *) domain;
436 }
437
438 char *
439 osip_www_authenticate_get_nonce (osip_www_authenticate_t * www_authenticate)
440 {
441   return www_authenticate->nonce;
442 }
443
444 void
445 osip_www_authenticate_set_nonce (osip_www_authenticate_t * www_authenticate,
446                                  char *nonce)
447 {
448   www_authenticate->nonce = (char *) nonce;
449 }
450
451 char *
452 osip_www_authenticate_get_stale (osip_www_authenticate_t * www_authenticate)
453 {
454   return www_authenticate->stale;
455 }
456
457 void
458 osip_www_authenticate_set_stale (osip_www_authenticate_t * www_authenticate,
459                                  char *stale)
460 {
461   www_authenticate->stale = (char *) stale;
462 }
463
464 char *
465 osip_www_authenticate_get_opaque (osip_www_authenticate_t * www_authenticate)
466 {
467   return www_authenticate->opaque;
468 }
469
470 void
471 osip_www_authenticate_set_opaque (osip_www_authenticate_t * www_authenticate,
472                                   char *opaque)
473 {
474   www_authenticate->opaque = (char *) opaque;
475 }
476
477 char *
478 osip_www_authenticate_get_algorithm (osip_www_authenticate_t *
479                                      www_authenticate)
480 {
481   return www_authenticate->algorithm;
482 }
483
484 void
485 osip_www_authenticate_set_algorithm (osip_www_authenticate_t *
486                                      www_authenticate, char *algorithm)
487 {
488   www_authenticate->algorithm = (char *) algorithm;
489 }
490
491 char *
492 osip_www_authenticate_get_qop_options (osip_www_authenticate_t *
493                                        www_authenticate)
494 {
495   return www_authenticate->qop_options;
496 }
497
498 void
499 osip_www_authenticate_set_qop_options (osip_www_authenticate_t *
500                                        www_authenticate, char *qop_options)
501 {
502   www_authenticate->qop_options = (char *) qop_options;
503 }
504
505
506
507 /* returns the www_authenticate header as a string.          */
508 /* INPUT : osip_www_authenticate_t *www_authenticate | www_authenticate header.  */
509 /* returns null on error. */
510 int
511 osip_www_authenticate_to_str (const osip_www_authenticate_t * wwwa,
512                               char **dest)
513 {
514   size_t len;
515   char *tmp;
516
517   *dest = NULL;
518   if ((wwwa == NULL) || (wwwa->auth_type == NULL) || (wwwa->realm == NULL)
519       || (wwwa->nonce == NULL))
520     return -1;
521
522   len = strlen (wwwa->auth_type) + 1;
523
524   if (wwwa->realm != NULL)
525     len = len + strlen (wwwa->realm) + 7;
526   if (wwwa->nonce != NULL)
527     len = len + strlen (wwwa->nonce) + 8;
528   len = len + 2;
529   if (wwwa->domain != NULL)
530     len = len + strlen (wwwa->domain) + 9;
531   if (wwwa->opaque != NULL)
532     len = len + strlen (wwwa->opaque) + 9;
533   if (wwwa->stale != NULL)
534     len = len + strlen (wwwa->stale) + 8;
535   if (wwwa->algorithm != NULL)
536     len = len + strlen (wwwa->algorithm) + 12;
537   if (wwwa->qop_options != NULL)
538     len = len + strlen (wwwa->qop_options) + 6;
539
540   tmp = (char *) osip_malloc (len);
541   if (tmp == NULL)
542     return -1;
543   *dest = tmp;
544
545   osip_strncpy (tmp, wwwa->auth_type, strlen (wwwa->auth_type));
546   tmp = tmp + strlen (tmp);
547
548   if (wwwa->realm != NULL)
549     {
550       osip_strncpy (tmp, " realm=", 7);
551       tmp = tmp + 7;
552       osip_strncpy (tmp, wwwa->realm, strlen (wwwa->realm));
553       tmp = tmp + strlen (tmp);
554     }
555   if (wwwa->domain != NULL)
556     {
557       osip_strncpy (tmp, ", domain=", 9);
558       tmp = tmp + 9;
559       osip_strncpy (tmp, wwwa->domain, strlen (wwwa->domain));
560       tmp = tmp + strlen (tmp);
561     }
562   if (wwwa->nonce != NULL)
563     {
564       osip_strncpy (tmp, ", nonce=", 8);
565       tmp = tmp + 8;
566       osip_strncpy (tmp, wwwa->nonce, strlen (wwwa->nonce));
567       tmp = tmp + strlen (tmp);
568     }
569   if (wwwa->opaque != NULL)
570     {
571       osip_strncpy (tmp, ", opaque=", 9);
572       tmp = tmp + 9;
573       osip_strncpy (tmp, wwwa->opaque, strlen (wwwa->opaque));
574       tmp = tmp + strlen (tmp);
575     }
576   if (wwwa->stale != NULL)
577     {
578       osip_strncpy (tmp, ", stale=", 8);
579       tmp = tmp + 8;
580       osip_strncpy (tmp, wwwa->stale, strlen (wwwa->stale));
581       tmp = tmp + strlen (tmp);
582     }
583   if (wwwa->algorithm != NULL)
584     {
585       osip_strncpy (tmp, ", algorithm=", 12);
586       tmp = tmp + 12;
587       osip_strncpy (tmp, wwwa->algorithm, strlen (wwwa->algorithm));
588       tmp = tmp + strlen (tmp);
589     }
590   if (wwwa->qop_options != NULL)
591     {
592       osip_strncpy (tmp, ", qop=", 6);
593       tmp = tmp + 6;
594       osip_strncpy (tmp, wwwa->qop_options, strlen (wwwa->qop_options));
595       tmp = tmp + strlen (tmp);
596     }
597
598   return 0;
599 }
600
601 /* deallocates a osip_www_authenticate_t structure.  */
602 /* INPUT : osip_www_authenticate_t *www_authenticate | www_authenticate. */
603 void
604 osip_www_authenticate_free (osip_www_authenticate_t * www_authenticate)
605 {
606   if (www_authenticate == NULL)
607     return;
608
609   osip_free (www_authenticate->auth_type);
610   osip_free (www_authenticate->realm);
611   osip_free (www_authenticate->domain);
612   osip_free (www_authenticate->nonce);
613   osip_free (www_authenticate->opaque);
614   osip_free (www_authenticate->stale);
615   osip_free (www_authenticate->algorithm);
616   osip_free (www_authenticate->qop_options);
617
618   osip_free (www_authenticate);
619 }
620
621 int
622 osip_www_authenticate_clone (const osip_www_authenticate_t * wwwa,
623                              osip_www_authenticate_t ** dest)
624 {
625   int i;
626   osip_www_authenticate_t *wa;
627
628   *dest = NULL;
629   if (wwwa == NULL)
630     return -1;
631   if (wwwa->auth_type == NULL)
632     return -1;
633   if (wwwa->realm == NULL)
634     return -1;
635   if (wwwa->nonce == NULL)
636     return -1;
637
638   i = osip_www_authenticate_init (&wa);
639   if (i == -1)                  /* allocation failed */
640     return -1;
641   wa->auth_type = osip_strdup (wwwa->auth_type);
642   wa->realm = osip_strdup (wwwa->realm);
643   if (wwwa->domain != NULL)
644     wa->domain = osip_strdup (wwwa->domain);
645   wa->nonce = osip_strdup (wwwa->nonce);
646   if (wwwa->opaque != NULL)
647     wa->opaque = osip_strdup (wwwa->opaque);
648   if (wwwa->stale != NULL)
649     wa->stale = osip_strdup (wwwa->stale);
650   if (wwwa->algorithm != NULL)
651     wa->algorithm = osip_strdup (wwwa->algorithm);
652   if (wwwa->qop_options != NULL)
653     wa->qop_options = osip_strdup (wwwa->qop_options);
654
655   *dest = wa;
656   return 0;
657 }