| 1 | /* mechtools.c --- Helper functions available for use by any mechanism. | 
|---|
| 2 | * Copyright (C) 2010-2012 Simon Josefsson | 
|---|
| 3 | * | 
|---|
| 4 | * This file is part of GNU SASL Library. | 
|---|
| 5 | * | 
|---|
| 6 | * GNU SASL Library is free software; you can redistribute it and/or | 
|---|
| 7 | * modify it under the terms of the GNU Lesser General Public License | 
|---|
| 8 | * as published by the Free Software Foundation; either version 2.1 of | 
|---|
| 9 | * the License, or (at your option) any later version. | 
|---|
| 10 | * | 
|---|
| 11 | * GNU SASL Library is distributed in the hope that it will be useful, | 
|---|
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|---|
| 14 | * Lesser General Public License for more details. | 
|---|
| 15 | * | 
|---|
| 16 | * You should have received a copy of the GNU Lesser General Public | 
|---|
| 17 | * License along with GNU SASL Library; if not, write to the Free | 
|---|
| 18 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 
|---|
| 19 | * Boston, MA 02110-1301, USA. | 
|---|
| 20 | * | 
|---|
| 21 | */ | 
|---|
| 22 |  | 
|---|
| 23 | #ifdef HAVE_CONFIG_H | 
|---|
| 24 | #include "config.h" | 
|---|
| 25 | #endif | 
|---|
| 26 |  | 
|---|
| 27 | /* Get specification. */ | 
|---|
| 28 | #include "mechtools.h" | 
|---|
| 29 |  | 
|---|
| 30 | /* Get strcmp. */ | 
|---|
| 31 | #include <string.h> | 
|---|
| 32 |  | 
|---|
| 33 | /* Get malloc, free. */ | 
|---|
| 34 | #include <stdlib.h> | 
|---|
| 35 |  | 
|---|
| 36 | /* Get asprintf. */ | 
|---|
| 37 | #include <stdio.h> | 
|---|
| 38 |  | 
|---|
| 39 | /* Get error codes. */ | 
|---|
| 40 | #include <gsasl.h> | 
|---|
| 41 |  | 
|---|
| 42 | /* Create in AUTHZID a newly allocated copy of STR where =2C is | 
|---|
| 43 | replaced with , and =3D is replaced with =.  Return GSASL_OK on | 
|---|
| 44 | success, GSASL_MALLOC_ERROR on memory errors, GSASL_PARSE_ERRORS if | 
|---|
| 45 | string contains any unencoded ',' or incorrectly encoded | 
|---|
| 46 | sequence.  */ | 
|---|
| 47 | static int | 
|---|
| 48 | unescape_authzid (const char *str, size_t len, char **authzid) | 
|---|
| 49 | { | 
|---|
| 50 | char *p; | 
|---|
| 51 |  | 
|---|
| 52 | if (memchr (str, ',', len) != NULL) | 
|---|
| 53 | return GSASL_MECHANISM_PARSE_ERROR; | 
|---|
| 54 |  | 
|---|
| 55 | p = *authzid = malloc (len + 1); | 
|---|
| 56 | if (!p) | 
|---|
| 57 | return GSASL_MALLOC_ERROR; | 
|---|
| 58 |  | 
|---|
| 59 | while (len > 0 && *str) | 
|---|
| 60 | { | 
|---|
| 61 | if (len >= 3 && str[0] == '=' && str[1] == '2' && str[2] == 'C') | 
|---|
| 62 | { | 
|---|
| 63 | *p++ = ','; | 
|---|
| 64 | str += 3; | 
|---|
| 65 | len -= 3; | 
|---|
| 66 | } | 
|---|
| 67 | else if (len >= 3 && str[0] == '=' && str[1] == '3' && str[2] == 'D') | 
|---|
| 68 | { | 
|---|
| 69 | *p++ = '='; | 
|---|
| 70 | str += 3; | 
|---|
| 71 | len -= 3; | 
|---|
| 72 | } | 
|---|
| 73 | else if (str[0] == '=') | 
|---|
| 74 | { | 
|---|
| 75 | free (*authzid); | 
|---|
| 76 | *authzid = NULL; | 
|---|
| 77 | return GSASL_MECHANISM_PARSE_ERROR; | 
|---|
| 78 | } | 
|---|
| 79 | else | 
|---|
| 80 | { | 
|---|
| 81 | *p++ = *str; | 
|---|
| 82 | str++; | 
|---|
| 83 | len--; | 
|---|
| 84 | } | 
|---|
| 85 | } | 
|---|
| 86 | *p = '\0'; | 
|---|
| 87 |  | 
|---|
| 88 | return GSASL_OK; | 
|---|
| 89 | } | 
|---|
| 90 |  | 
|---|
| 91 | /* Parse the GS2 header containing flags and authorization identity. | 
|---|
| 92 | Put authorization identity (or NULL) in AUTHZID and length of | 
|---|
| 93 | header in HEADERLEN.  Return GSASL_OK on success or an error | 
|---|
| 94 | code.*/ | 
|---|
| 95 | int | 
|---|
| 96 | (const char *data, size_t len, | 
|---|
| 97 | char **authzid, size_t * ) | 
|---|
| 98 | { | 
|---|
| 99 | char *authzid_endptr; | 
|---|
| 100 |  | 
|---|
| 101 | if (len < 3) | 
|---|
| 102 | return GSASL_MECHANISM_PARSE_ERROR; | 
|---|
| 103 |  | 
|---|
| 104 | if (strncmp (data, "n,,", 3) == 0) | 
|---|
| 105 | { | 
|---|
| 106 | *headerlen = 3; | 
|---|
| 107 | *authzid = NULL; | 
|---|
| 108 | } | 
|---|
| 109 | else if (strncmp (data, "n,a=", 4) == 0 && | 
|---|
| 110 | (authzid_endptr = memchr (data + 4, ',', len - 4))) | 
|---|
| 111 | { | 
|---|
| 112 | int res; | 
|---|
| 113 |  | 
|---|
| 114 | if (authzid_endptr == NULL) | 
|---|
| 115 | return GSASL_MECHANISM_PARSE_ERROR; | 
|---|
| 116 |  | 
|---|
| 117 | res = unescape_authzid (data + 4, authzid_endptr - (data + 4), authzid); | 
|---|
| 118 | if (res != GSASL_OK) | 
|---|
| 119 | return res; | 
|---|
| 120 |  | 
|---|
| 121 | *headerlen = authzid_endptr - data + 1; | 
|---|
| 122 | } | 
|---|
| 123 | else | 
|---|
| 124 | return GSASL_MECHANISM_PARSE_ERROR; | 
|---|
| 125 |  | 
|---|
| 126 | return GSASL_OK; | 
|---|
| 127 | } | 
|---|
| 128 |  | 
|---|
| 129 | /* Return newly allocated copy of STR with all occurrences of ',' | 
|---|
| 130 | replaced with =2C and '=' with '=3D', or return NULL on memory | 
|---|
| 131 | allocation errors.  */ | 
|---|
| 132 | static char * | 
|---|
| 133 | escape_authzid (const char *str) | 
|---|
| 134 | { | 
|---|
| 135 | char *out = malloc (strlen (str) * 3 + 1); | 
|---|
| 136 | char *p = out; | 
|---|
| 137 |  | 
|---|
| 138 | if (!out) | 
|---|
| 139 | return NULL; | 
|---|
| 140 |  | 
|---|
| 141 | while (*str) | 
|---|
| 142 | { | 
|---|
| 143 | if (*str == ',') | 
|---|
| 144 | { | 
|---|
| 145 | memcpy (p, "=2C", 3); | 
|---|
| 146 | p += 3; | 
|---|
| 147 | } | 
|---|
| 148 | else if (*str == '=') | 
|---|
| 149 | { | 
|---|
| 150 | memcpy (p, "=3D", 3); | 
|---|
| 151 | p += 3; | 
|---|
| 152 | } | 
|---|
| 153 | else | 
|---|
| 154 | { | 
|---|
| 155 | *p = *str; | 
|---|
| 156 | p++; | 
|---|
| 157 | } | 
|---|
| 158 | str++; | 
|---|
| 159 | } | 
|---|
| 160 | *p = '\0'; | 
|---|
| 161 |  | 
|---|
| 162 | return out; | 
|---|
| 163 | } | 
|---|
| 164 |  | 
|---|
| 165 | /* Generate a newly allocated GS2 header, escaping authzid | 
|---|
| 166 | appropriately, and appending EXTRA. */ | 
|---|
| 167 | int | 
|---|
| 168 | (bool nonstd, char cbflag, | 
|---|
| 169 | const char *cbname, const char *authzid, | 
|---|
| 170 | size_t , const char *, | 
|---|
| 171 | char **gs2h, size_t * gs2hlen) | 
|---|
| 172 | { | 
|---|
| 173 | int elen = extralen; | 
|---|
| 174 | char *gs2cbflag; | 
|---|
| 175 | int len; | 
|---|
| 176 |  | 
|---|
| 177 | if (cbflag == 'p') | 
|---|
| 178 | len = asprintf (&gs2cbflag, "p=%s", cbname); | 
|---|
| 179 | else if (cbflag == 'n') | 
|---|
| 180 | len = asprintf (&gs2cbflag, "n"); | 
|---|
| 181 | else if (cbflag == 'y') | 
|---|
| 182 | len = asprintf (&gs2cbflag, "y"); | 
|---|
| 183 | else | 
|---|
| 184 | /* internal caller error */ | 
|---|
| 185 | return GSASL_MECHANISM_PARSE_ERROR; | 
|---|
| 186 |  | 
|---|
| 187 | if (len <= 0 || gs2cbflag == NULL) | 
|---|
| 188 | return GSASL_MALLOC_ERROR; | 
|---|
| 189 |  | 
|---|
| 190 | if (authzid) | 
|---|
| 191 | { | 
|---|
| 192 | char *escaped_authzid = escape_authzid (authzid); | 
|---|
| 193 |  | 
|---|
| 194 | if (!escaped_authzid) | 
|---|
| 195 | { | 
|---|
| 196 | free (gs2cbflag); | 
|---|
| 197 | return GSASL_MALLOC_ERROR; | 
|---|
| 198 | } | 
|---|
| 199 |  | 
|---|
| 200 | len = asprintf (gs2h, "%s%s,a=%s,%.*s", nonstd ? "F,": "", | 
|---|
| 201 | gs2cbflag, escaped_authzid, elen, extra); | 
|---|
| 202 |  | 
|---|
| 203 | free (escaped_authzid); | 
|---|
| 204 | } | 
|---|
| 205 | else | 
|---|
| 206 | len = asprintf (gs2h, "%s%s,,%.*s", nonstd ? "F,": "", gs2cbflag, | 
|---|
| 207 | elen, extra); | 
|---|
| 208 |  | 
|---|
| 209 | free (gs2cbflag); | 
|---|
| 210 |  | 
|---|
| 211 | if (len <= 0 || gs2h == NULL) | 
|---|
| 212 | return GSASL_MALLOC_ERROR; | 
|---|
| 213 |  | 
|---|
| 214 | *gs2hlen = len; | 
|---|
| 215 |  | 
|---|
| 216 | return GSASL_OK; | 
|---|
| 217 | } | 
|---|
| 218 |  | 
|---|