parse_identity.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Copyright (c) 2007 iptelorg GmbH
00005  *
00006  * This file is part of ser, a free SIP server.
00007  *
00008  * ser is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * For a license to use the ser software under conditions
00014  * other than those described here, or to purchase support for this
00015  * software, please contact iptel.org by e-mail at the following addresses:
00016  *    info@iptel.org
00017  *
00018  * ser is distributed in the hope that it will be useful,
00019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021  * GNU General Public License for more details.
00022  *
00023  * You should have received a copy of the GNU General Public License
00024  * along with this program; if not, write to the Free Software
00025  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00026  */
00027 
00035 #include <string.h>
00036 #include "parse_identity.h"
00037 #include "parse_def.h"
00038 #include "parser_f.h"  /* eat_space_end and so on */
00039 #include "../mem/mem.h"
00040 #include "../ut.h"
00041 
00042 /*
00043  * Parse Identity header field
00044  */
00045 
00046 #define SP(_c) ((_c)=='\t' || (_c)==' ')
00047 inline static int isendofhash (char* p, char* end)
00048 {
00049         /* new header line */
00050         if ((p<end && *p=='"')
00051                 /* end of message */
00052                 || ((*p=='\n' || *p=='\r') && p+1==end))
00053                 return 1;
00054         else
00055                 return 0;
00056 }
00057 
00058 
00063 int movetomybuffer (char *pstart,
00064                                         char *pend,
00065                                         char *pcur,
00066                                         struct identity_body *ib)
00067 {
00068         char *phashend;
00069 
00070         for (phashend = pcur; !isendofhash(phashend, pend); phashend++);
00071 
00072         if (!(ib->hash.s=pkg_malloc(phashend-pstart))) {
00073                 LOG(L_ERR, "parse_identity: out of memory\n");
00074                 return -2;
00075         }
00076         ib->ballocated=1;
00077 
00078         memcpy(ib->hash.s, pstart, ib->hash.len);
00079 
00080         return 0;
00081 }
00082 
00083 
00084 void parse_identity(char *buffer, char* end, struct identity_body* ib)
00085 {
00086         char *p=NULL, *pstart=NULL;
00087 
00088         if (!buffer || !end || !ib)
00089                 goto error;
00090 
00091         ib->error=PARSE_ERROR;
00092 
00093         /* if there is a '"' sign then we'll step over it */
00094         *buffer == '"' ? (pstart = buffer + 1) : (pstart = buffer);
00095 
00096         ib->hash.s=pstart;
00097         ib->hash.len=0;
00098 
00099         for (p = pstart; p < end; p++) {
00100                 /* check the BASE64 alphabet */
00101                 if (((*p >= 'a' && *p <='z')
00102                         || (*p >= 'A' && *p <='Z')
00103                         || (*p >= '0' && *p <='9')
00104                         || (*p == '+' || *p == '/' || *p == '='))) {
00105                         if (ib->ballocated)
00106                                 ib->hash.s[ib->hash.len]=*p;
00107                         ib->hash.len++;
00108                         continue;
00109                 }
00110 
00111                 /* LWS */
00112                 if (*p=='\n' && p+1<end && SP(*(p+1))) {
00113                         /* p - 1 because we don't want to pass '\n' */
00114                         if (!ib->ballocated && (movetomybuffer(pstart, end, p-1, ib)))
00115                                 goto error;
00116                         /* p + 1 < end because 'continue' increases p so we'd skip \n
00117                            we need after this for loop */
00118                         for (p+=1; p + 1 < end && SP(*(p + 1)); p++);
00119                         continue;
00120                 }
00121                 if (*p=='\r' && p+2<end && *(p+1)=='\n' && SP(*(p+2))) {
00122                         if (!ib->ballocated && (movetomybuffer(pstart, end, p-1, ib)))
00123                                 goto error;
00124                         for (p+=2; p + 1 < end && SP(*(p + 1)); p++);
00125                         continue;
00126                 }
00127 
00128                 if (isendofhash(p, end))
00129                         break;
00130 
00131                 /* parse error */
00132                 goto parseerror;
00133         }
00134 
00135         /* this is the final quotation mark so we step over */
00136         ib->error=PARSE_OK;
00137         return ;
00138 
00139 parseerror:
00140         LOG( L_ERR , "ERROR: parse_identity: "
00141                 "unexpected char [0x%X]: <<%.*s>> .\n",
00142                 *p,(int)(p-buffer), ZSW(buffer));
00143 error:
00144         return ;
00145 }
00146 
00147 int parse_identity_header(struct sip_msg *msg)
00148 {
00149         struct identity_body* identity_b;
00150 
00151 
00152         if ( !msg->identity
00153                  && (parse_headers(msg,HDR_IDENTITY_F,0)==-1
00154                  || !msg->identity) ) {
00155                 LOG(L_ERR,"ERROR:parse_identity_header: bad msg or missing IDENTITY header\n");
00156                 goto error;
00157         }
00158 
00159         /* maybe the header is already parsed! */
00160         if (msg->identity->parsed)
00161                 return 0;
00162 
00163         identity_b=pkg_malloc(sizeof(*identity_b));
00164         if (identity_b==0){
00165                 LOG(L_ERR, "ERROR:parse_identity_header: out of memory\n");
00166                 goto error;
00167         }
00168         memset(identity_b, 0, sizeof(*identity_b));
00169 
00170         parse_identity(msg->identity->body.s,
00171                                    msg->identity->body.s + msg->identity->body.len+1,
00172                                    identity_b);
00173         if (identity_b->error==PARSE_ERROR){
00174                 free_identity(identity_b);
00175                 goto error;
00176         }
00177         msg->identity->parsed=(void*)identity_b;
00178 
00179         return 0;
00180 error:
00181         return -1;
00182 }
00183 
00184 void free_identity(struct identity_body *ib)
00185 {
00186         if (ib->ballocated)
00187                 pkg_free(ib->hash.s);
00188         pkg_free(ib);
00189 }