/*
The oSIP library implements the Session Initiation Protocol (SIP -rfc3261-)
Copyright (C) 2001,2002,2003,2004,2005 Aymeric MOIZARD jack@atosc.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <osipparser2/osip_port.h>
#include <osipparser2/osip_message.h>
#include <osipparser2/osip_parser.h>
#include "parser.h"
int
osip_www_authenticate_init (osip_www_authenticate_t ** dest)
{
*dest =
(osip_www_authenticate_t *) osip_malloc (sizeof (osip_www_authenticate_t));
if (*dest == NULL)
return -1;
memset (*dest, 0, sizeof (osip_www_authenticate_t));
return 0;
}
/* fills the www-authenticate header of message. */
/* INPUT : char *hvalue | value of header. */
/* OUTPUT: osip_message_t *sip | structure to save results. */
/* returns -1 on error. */
int
osip_message_set_www_authenticate (osip_message_t * sip, const char *hvalue)
{
osip_www_authenticate_t *www_authenticate;
int i;
if (hvalue == NULL || hvalue[0] == '\0')
return 0;
if (sip == NULL || sip->www_authenticates == NULL)
return -1;
i = osip_www_authenticate_init (&www_authenticate);
if (i != 0)
return -1;
i = osip_www_authenticate_parse (www_authenticate, hvalue);
if (i != 0)
{
osip_www_authenticate_free (www_authenticate);
return -1;
}
sip->message_property = 2;
osip_list_add (sip->www_authenticates, www_authenticate, -1);
return 0;
}
int
__osip_quoted_string_set (const char *name, const char *str,
char **result, const char **next)
{
*next = str;
if (*result != NULL)
return 0; /* already parsed */
*next = NULL;
while ((' ' == *str) || ('\t' == *str) || (',' == *str))
if (*str)
str++;
else
return -1; /* bad header format */
if (strlen (str) <= strlen (name))
return -1; /* bad header format... */
if (osip_strncasecmp (name, str, strlen (name)) == 0)
{
const char *quote1;
const char *quote2;
const char *tmp;
const char *hack = strchr (str, '=');
if (hack == NULL)
return -1;
while (' ' == *(hack - 1)) /* get rid of extra spaces */
hack--;
if ((size_t) (hack - str) != strlen (name))
{
*next = str;
return 0;
}
quote1 = __osip_quote_find (str);
if (quote1 == NULL)
return -1; /* bad header format... */
quote2 = __osip_quote_find (quote1 + 1);
if (quote2 == NULL)
return -1; /* bad header format... */
if (quote2 - quote1 == 1)
{
/* this is a special case! The quote contains nothing! */
/* example: Digest opaque="",cnonce="" */
/* in this case, we just forget the parameter... this */
/* this should prevent from user manipulating empty */
/* strings */
tmp = quote2 + 1; /* next element start here */
for (; *tmp == ' ' || *tmp == '\t'; tmp++)
{
}
for (; *tmp == '\n' || *tmp == '\r'; tmp++)
{
} /* skip LWS */
*next = NULL;
if (*tmp == '\0') /* end of header detected */
return 0;
if (*tmp != '\t' && *tmp != ' ')
/* LWS here ? */
*next = tmp;
else
{ /* it is: skip it... */
for (; *tmp == ' ' || *tmp == '\t'; tmp++)
{
}
if (*tmp == '\0') /* end of header detected */
return 0;
*next = tmp;
}
return 0;
}
*result = (char *) osip_malloc (quote2 - quote1 + 3);
if (*result == NULL)
return -1;
osip_strncpy (*result, quote1, quote2 - quote1 + 1);
tmp = quote2 + 1; /* next element start here */
for (; *tmp == ' ' || *tmp == '\t'; tmp++)
{
}
for (; *tmp == '\n' || *tmp == '\r'; tmp++)
{
} /* skip LWS */
*next = NULL;
if (*tmp == '\0') /* end of header detected */
return 0;
if (*tmp != '\t' && *tmp != ' ')
/* LWS here ? */
*next = tmp;
else
{ /* it is: skip it... */
for (; *tmp == ' ' || *tmp == '\t'; tmp++)
{
}
if (*tmp == '\0') /* end of header detected */
return 0;
*next = tmp;
}
} else
*next = str; /* wrong header asked! */
return 0;
}
int
__osip_token_set (const char *name, const char *str, char **result,
const char **next)
{
const char *beg;
const char *tmp;
*next = str;
if (*result != NULL)
return 0; /* already parsed */
*next = NULL;
beg = strchr (str, '=');
if (beg == NULL)
return -1; /* bad header format... */
if (strlen (str) < 6)
return 0; /* end of header... */
while ((' ' == *str) || ('\t' == *str) || (',' == *str))
if (*str)
str++;
else
return -1; /* bad header format */
if (osip_strncasecmp (name, str, strlen (name)) == 0)
{
const char *end;
end = strchr (str, ',');
if (end == NULL)
end = str + strlen (str); /* This is the end of the header */
if (end - beg < 2)
return -1;
*result = (char *) osip_malloc (end - beg);
if (*result == NULL)
return -1;
osip_clrncpy (*result, beg + 1, end - beg - 1);
/* make sure the element does not contain more parameter */
tmp = (*end) ? (end + 1) : end;
for (; *tmp == ' ' || *tmp == '\t'; tmp++)
{
}
for (; *tmp == '\n' || *tmp == '\r'; tmp++)
{
} /* skip LWS */
*next = NULL;
if (*tmp == '\0') /* end of header detected */
return 0;
if (*tmp != '\t' && *tmp != ' ')
/* LWS here ? */
*next = tmp;
else
{ /* it is: skip it... */
for (; *tmp == ' ' || *tmp == '\t'; tmp++)
{
}
if (*tmp == '\0') /* end of header detected */
return 0;
*next = tmp;
}
} else
*next = str; /* next element start here */
return 0;
}
/* fills the www-authenticate strucuture. */
/* INPUT : char *hvalue | value of header. */
/* OUTPUT: osip_message_t *sip | structure to save results. */
/* returns -1 on error. */
/* TODO:
digest-challenge tken has no order preference??
verify many situations (extra SP....)
*/
int
osip_www_authenticate_parse (osip_www_authenticate_t * wwwa, const char *hvalue)
{
const char *space;
const char *next = NULL;
space = strchr (hvalue, ' '); /* SEARCH FOR SPACE */
if (space == NULL)
return -1;
if (space - hvalue + 1 < 2)
return -1;
wwwa->auth_type = (char *) osip_malloc (space - hvalue + 1);
if (wwwa->auth_type == NULL)
return -1;
osip_strncpy (wwwa->auth_type, hvalue, space - hvalue);
for (;;)
{
int parse_ok = 0;
if (__osip_quoted_string_set ("realm", space, &(wwwa->realm), &next))
return -1;
if (next == NULL)
return 0; /* end of header detected! */
else if (next != space)
{
space = next;
parse_ok++;
}
if (__osip_quoted_string_set ("domain", space, &(wwwa->domain), &next))
return -1;
if (next == NULL)
return 0; /* end of header detected! */
else if (next != space)
{
space = next;
parse_ok++;
}
if (__osip_quoted_string_set ("nonce", space, &(wwwa->nonce), &next))
return -1;
if (next == NULL)
return 0; /* end of header detected! */
else if (next != space)
{
space = next;
parse_ok++;
}
if (__osip_quoted_string_set ("opaque", space, &(wwwa->opaque), &next))
return -1;
if (next == NULL)
return 0; /* end of header detected! */
else if (next != space)
{
space = next;
parse_ok++;
}
if (__osip_token_set ("stale", space, &(wwwa->stale), &next))
return -1;
if (next == NULL)
return 0; /* end of header detected! */
else if (next != space)
{
space = next;
parse_ok++;
}
if (__osip_token_set ("algorithm", space, &(wwwa->algorithm), &next))
return -1;
if (next == NULL)
return 0; /* end of header detected! */
else if (next != space)
{
space = next;
parse_ok++;
}
if (__osip_quoted_string_set ("qop", space, &(wwwa->qop_options), &next))
return -1;
if (next == NULL)
return 0; /* end of header detected! */
else if (next != space)
{
space = next;
parse_ok++;
}
if (0 == parse_ok)
{
char *quote1, *quote2, *tmp;
/* CAUTION */
/* parameter not understood!!! I'm too lazy to handle IT */
/* let's simply bypass it */
if (strlen (space) < 1)
return 0;
tmp = strchr (space + 1, ',');
if (tmp == NULL) /* it was the last header */
return 0;
quote1 = __osip_quote_find (space);
if ((quote1 != NULL) && (quote1 < tmp)) /* this may be a quoted string! */
{
quote2 = __osip_quote_find (quote1 + 1);
if (quote2 == NULL)
return -1; /* bad header format... */
if (tmp < quote2) /* the comma is inside the quotes! */
space = strchr (quote2, ',');
else
space = tmp;
if (space == NULL) /* it was the last header */
return 0;
} else
space = tmp;
/* continue parsing... */
}
}
return 0; /* ok */
}
/* returns the www_authenticate header. */
/* INPUT : osip_message_t *sip | sip message. */
/* returns null on error. */
int
osip_message_get_www_authenticate (const osip_message_t * sip, int pos,
osip_www_authenticate_t ** dest)
{
osip_www_authenticate_t *www_authenticate;
*dest = NULL;
if (osip_list_size (sip->www_authenticates) <= pos)
return -1; /* does not exist */
www_authenticate =
(osip_www_authenticate_t *) osip_list_get (sip->www_authenticates, pos);
*dest = www_authenticate;
return pos;
}
char *
osip_www_authenticate_get_auth_type (osip_www_authenticate_t * www_authenticate)
{
return www_authenticate->auth_type;
}
void
osip_www_authenticate_set_auth_type (osip_www_authenticate_t *
www_authenticate, char *auth_type)
{
www_authenticate->auth_type = (char *) auth_type;
}
char *
osip_www_authenticate_get_realm (osip_www_authenticate_t * www_authenticate)
{
return www_authenticate->realm;
}
void
osip_www_authenticate_set_realm (osip_www_authenticate_t * www_authenticate,
char *realm)
{
www_authenticate->realm = (char *) realm;
}
char *
osip_www_authenticate_get_domain (osip_www_authenticate_t * www_authenticate)
{
return www_authenticate->domain;
}
void
osip_www_authenticate_set_domain (osip_www_authenticate_t * www_authenticate,
char *domain)
{
www_authenticate->domain = (char *) domain;
}
char *
osip_www_authenticate_get_nonce (osip_www_authenticate_t * www_authenticate)
{
return www_authenticate->nonce;
}
void
osip_www_authenticate_set_nonce (osip_www_authenticate_t * www_authenticate,
char *nonce)
{
www_authenticate->nonce = (char *) nonce;
}
char *
osip_www_authenticate_get_stale (osip_www_authenticate_t * www_authenticate)
{
return www_authenticate->stale;
}
void
osip_www_authenticate_set_stale (osip_www_authenticate_t * www_authenticate,
char *stale)
{
www_authenticate->stale = (char *) stale;
}
char *
osip_www_authenticate_get_opaque (osip_www_authenticate_t * www_authenticate)
{
return www_authenticate->opaque;
}
void
osip_www_authenticate_set_opaque (osip_www_authenticate_t * www_authenticate,
char *opaque)
{
www_authenticate->opaque = (char *) opaque;
}
char *
osip_www_authenticate_get_algorithm (osip_www_authenticate_t * www_authenticate)
{
return www_authenticate->algorithm;
}
void
osip_www_authenticate_set_algorithm (osip_www_authenticate_t *
www_authenticate, char *algorithm)
{
www_authenticate->algorithm = (char *) algorithm;
}
char *
osip_www_authenticate_get_qop_options (osip_www_authenticate_t * www_authenticate)
{
return www_authenticate->qop_options;
}
void
osip_www_authenticate_set_qop_options (osip_www_authenticate_t *
www_authenticate, char *qop_options)
{
www_authenticate->qop_options = (char *) qop_options;
}
/* returns the www_authenticate header as a string. */
/* INPUT : osip_www_authenticate_t *www_authenticate | www_authenticate header. */
/* returns null on error. */
int
osip_www_authenticate_to_str (const osip_www_authenticate_t * wwwa, char **dest)
{
size_t len;
char *tmp;
*dest = NULL;
if ((wwwa == NULL) || (wwwa->auth_type == NULL))
return -1;
len = strlen (wwwa->auth_type) + 1;
if (wwwa->realm != NULL)
len = len + strlen (wwwa->realm) + 7;
if (wwwa->nonce != NULL)
len = len + strlen (wwwa->nonce) + 8;
len = len + 2;
if (wwwa->domain != NULL)
len = len + strlen (wwwa->domain) + 9;
if (wwwa->opaque != NULL)
len = len + strlen (wwwa->opaque) + 9;
if (wwwa->stale != NULL)
len = len + strlen (wwwa->stale) + 8;
if (wwwa->algorithm != NULL)
len = len + strlen (wwwa->algorithm) + 12;
if (wwwa->qop_options != NULL)
len = len + strlen (wwwa->qop_options) + 6;
tmp = (char *) osip_malloc (len);
if (tmp == NULL)
return -1;
*dest = tmp;
tmp = osip_str_append (tmp, wwwa->auth_type);
if (wwwa->realm != NULL)
{
tmp = osip_strn_append (tmp, " realm=", 7);
tmp = osip_str_append (tmp, wwwa->realm);
}
if (wwwa->domain != NULL)
{
tmp = osip_strn_append (tmp, ", domain=", 9);
tmp = osip_str_append (tmp, wwwa->domain);
}
if (wwwa->nonce != NULL)
{
tmp = osip_strn_append (tmp, ", nonce=", 8);
tmp = osip_str_append (tmp, wwwa->nonce);
}
if (wwwa->opaque != NULL)
{
tmp = osip_strn_append (tmp, ", opaque=", 9);
tmp = osip_str_append (tmp, wwwa->opaque);
}
if (wwwa->stale != NULL)
{
tmp = osip_strn_append (tmp, ", stale=", 8);
tmp = osip_str_append (tmp, wwwa->stale);
}
if (wwwa->algorithm != NULL)
{
tmp = osip_strn_append (tmp, ", algorithm=", 12);
tmp = osip_str_append (tmp, wwwa->algorithm);
}
if (wwwa->qop_options != NULL)
{
tmp = osip_strn_append (tmp, ", qop=", 6);
tmp = osip_str_append (tmp, wwwa->qop_options);
}
if (wwwa->realm == NULL)
{
/* remove comma */
len = strlen (wwwa->auth_type);
if ((*dest)[len] == ',')
(*dest)[len] = ' ';
}
return 0;
}
/* deallocates a osip_www_authenticate_t structure. */
/* INPUT : osip_www_authenticate_t *www_authenticate | www_authenticate. */
void
osip_www_authenticate_free (osip_www_authenticate_t * www_authenticate)
{
if (www_authenticate == NULL)
return;
osip_free (www_authenticate->auth_type);
osip_free (www_authenticate->realm);
osip_free (www_authenticate->domain);
osip_free (www_authenticate->nonce);
osip_free (www_authenticate->opaque);
osip_free (www_authenticate->stale);
osip_free (www_authenticate->algorithm);
osip_free (www_authenticate->qop_options);
osip_free (www_authenticate);
}
int
osip_www_authenticate_clone (const osip_www_authenticate_t * wwwa,
osip_www_authenticate_t ** dest)
{
int i;
osip_www_authenticate_t *wa;
*dest = NULL;
if (wwwa == NULL)
return -1;
if (wwwa->auth_type == NULL)
return -1;
i = osip_www_authenticate_init (&wa);
if (i == -1) /* allocation failed */
return -1;
wa->auth_type = osip_strdup (wwwa->auth_type);
if (wwwa->realm != NULL)
wa->realm = osip_strdup (wwwa->realm);
if (wwwa->domain != NULL)
wa->domain = osip_strdup (wwwa->domain);
if (wwwa->nonce != NULL)
wa->nonce = osip_strdup (wwwa->nonce);
if (wwwa->opaque != NULL)
wa->opaque = osip_strdup (wwwa->opaque);
if (wwwa->stale != NULL)
wa->stale = osip_strdup (wwwa->stale);
if (wwwa->algorithm != NULL)
wa->algorithm = osip_strdup (wwwa->algorithm);
if (wwwa->qop_options != NULL)
wa->qop_options = osip_strdup (wwwa->qop_options);
*dest = wa;
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1