gsasl  1.8.0
mechtools.c
Go to the documentation of this file.
00001 /* mechtools.c --- Helper functions available for use by any mechanism.
00002  * Copyright (C) 2010-2012 Simon Josefsson
00003  *
00004  * This file is part of GNU SASL Library.
00005  *
00006  * GNU SASL Library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public License
00008  * as published by the Free Software Foundation; either version 2.1 of
00009  * the License, or (at your option) any later version.
00010  *
00011  * GNU SASL Library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with GNU SASL Library; if not, write to the Free
00018  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include "config.h"
00025 #endif
00026 
00027 /* Get specification. */
00028 #include "mechtools.h"
00029 
00030 /* Get strcmp. */
00031 #include <string.h>
00032 
00033 /* Get malloc, free. */
00034 #include <stdlib.h>
00035 
00036 /* Get asprintf. */
00037 #include <stdio.h>
00038 
00039 /* Get error codes. */
00040 #include <gsasl.h>
00041 
00042 /* Create in AUTHZID a newly allocated copy of STR where =2C is
00043    replaced with , and =3D is replaced with =.  Return GSASL_OK on
00044    success, GSASL_MALLOC_ERROR on memory errors, GSASL_PARSE_ERRORS if
00045    string contains any unencoded ',' or incorrectly encoded
00046    sequence.  */
00047 static int
00048 unescape_authzid (const char *str, size_t len, char **authzid)
00049 {
00050   char *p;
00051 
00052   if (memchr (str, ',', len) != NULL)
00053     return GSASL_MECHANISM_PARSE_ERROR;
00054 
00055   p = *authzid = malloc (len + 1);
00056   if (!p)
00057     return GSASL_MALLOC_ERROR;
00058 
00059   while (len > 0 && *str)
00060     {
00061       if (len >= 3 && str[0] == '=' && str[1] == '2' && str[2] == 'C')
00062         {
00063           *p++ = ',';
00064           str += 3;
00065           len -= 3;
00066         }
00067       else if (len >= 3 && str[0] == '=' && str[1] == '3' && str[2] == 'D')
00068         {
00069           *p++ = '=';
00070           str += 3;
00071           len -= 3;
00072         }
00073       else if (str[0] == '=')
00074         {
00075           free (*authzid);
00076           *authzid = NULL;
00077           return GSASL_MECHANISM_PARSE_ERROR;
00078         }
00079       else
00080         {
00081           *p++ = *str;
00082           str++;
00083           len--;
00084         }
00085     }
00086   *p = '\0';
00087 
00088   return GSASL_OK;
00089 }
00090 
00091 /* Parse the GS2 header containing flags and authorization identity.
00092    Put authorization identity (or NULL) in AUTHZID and length of
00093    header in HEADERLEN.  Return GSASL_OK on success or an error
00094    code.*/
00095 int
00096 _gsasl_parse_gs2_header (const char *data, size_t len,
00097                          char **authzid, size_t * headerlen)
00098 {
00099   char *authzid_endptr;
00100 
00101   if (len < 3)
00102     return GSASL_MECHANISM_PARSE_ERROR;
00103 
00104   if (strncmp (data, "n,,", 3) == 0)
00105     {
00106       *headerlen = 3;
00107       *authzid = NULL;
00108     }
00109   else if (strncmp (data, "n,a=", 4) == 0 &&
00110            (authzid_endptr = memchr (data + 4, ',', len - 4)))
00111     {
00112       int res;
00113 
00114       if (authzid_endptr == NULL)
00115         return GSASL_MECHANISM_PARSE_ERROR;
00116 
00117       res = unescape_authzid (data + 4, authzid_endptr - (data + 4), authzid);
00118       if (res != GSASL_OK)
00119         return res;
00120 
00121       *headerlen = authzid_endptr - data + 1;
00122     }
00123   else
00124     return GSASL_MECHANISM_PARSE_ERROR;
00125 
00126   return GSASL_OK;
00127 }
00128 
00129 /* Return newly allocated copy of STR with all occurrences of ','
00130    replaced with =2C and '=' with '=3D', or return NULL on memory
00131    allocation errors.  */
00132 static char *
00133 escape_authzid (const char *str)
00134 {
00135   char *out = malloc (strlen (str) * 3 + 1);
00136   char *p = out;
00137 
00138   if (!out)
00139     return NULL;
00140 
00141   while (*str)
00142     {
00143       if (*str == ',')
00144         {
00145           memcpy (p, "=2C", 3);
00146           p += 3;
00147         }
00148       else if (*str == '=')
00149         {
00150           memcpy (p, "=3D", 3);
00151           p += 3;
00152         }
00153       else
00154         {
00155           *p = *str;
00156           p++;
00157         }
00158       str++;
00159     }
00160   *p = '\0';
00161 
00162   return out;
00163 }
00164 
00165 /* Generate a newly allocated GS2 header, escaping authzid
00166    appropriately, and appending EXTRA. */
00167 int
00168 _gsasl_gs2_generate_header (bool nonstd, char cbflag,
00169                             const char *cbname, const char *authzid,
00170                             size_t extralen, const char *extra,
00171                             char **gs2h, size_t * gs2hlen)
00172 {
00173   int elen = extralen;
00174   char *gs2cbflag;
00175   int len;
00176 
00177   if (cbflag == 'p')
00178     len = asprintf (&gs2cbflag, "p=%s", cbname);
00179   else if (cbflag == 'n')
00180     len = asprintf (&gs2cbflag, "n");
00181   else if (cbflag == 'y')
00182     len = asprintf (&gs2cbflag, "y");
00183   else
00184     /* internal caller error */
00185     return GSASL_MECHANISM_PARSE_ERROR;
00186 
00187   if (len <= 0 || gs2cbflag == NULL)
00188     return GSASL_MALLOC_ERROR;
00189 
00190   if (authzid)
00191     {
00192       char *escaped_authzid = escape_authzid (authzid);
00193 
00194       if (!escaped_authzid)
00195         {
00196           free (gs2cbflag);
00197           return GSASL_MALLOC_ERROR;
00198         }
00199 
00200       len = asprintf (gs2h, "%s%s,a=%s,%.*s", nonstd ? "F," : "",
00201                       gs2cbflag, escaped_authzid, elen, extra);
00202 
00203       free (escaped_authzid);
00204     }
00205   else
00206     len = asprintf (gs2h, "%s%s,,%.*s", nonstd ? "F," : "", gs2cbflag,
00207                     elen, extra);
00208 
00209   free (gs2cbflag);
00210 
00211   if (len <= 0 || gs2h == NULL)
00212     return GSASL_MALLOC_ERROR;
00213 
00214   *gs2hlen = len;
00215 
00216   return GSASL_OK;
00217 }