basicauth.c (10404B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2010, 2011, 2012 Daniel Pittman and Christian Grothoff 4 Copyright (C) 2014-2023 Evgeny Grin (Karlson2k) 5 6 This library is free software; you can redistribute it and/or 7 modify it under the terms of the GNU Lesser General Public 8 License as published by the Free Software Foundation; either 9 version 2.1 of the License, or (at your option) any later version. 10 11 This 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 this library; if not, write to the Free Software 18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 /** 21 * @file basicauth.c 22 * @brief Implements HTTP basic authentication methods 23 * @author Amr Ali 24 * @author Matthieu Speder 25 * @author Karlson2k (Evgeny Grin) 26 */ 27 #include "basicauth.h" 28 #include "gen_auth.h" 29 #include "platform.h" 30 #include "mhd_limits.h" 31 #include "internal.h" 32 #include "mhd_compat.h" 33 #include "mhd_str.h" 34 35 36 /** 37 * Get the username and password from the Basic Authorisation header 38 * sent by the client 39 * 40 * @param connection the MHD connection structure 41 * @return NULL if no valid Basic Authentication header is present in 42 * current request, or 43 * pointer to structure with username and password, which must be 44 * freed by #MHD_free(). 45 * @note Available since #MHD_VERSION 0x00097701 46 * @ingroup authentication 47 */ 48 _MHD_EXTERN struct MHD_BasicAuthInfo * 49 MHD_basic_auth_get_username_password3 (struct MHD_Connection *connection) 50 { 51 const struct MHD_RqBAuth *params; 52 size_t decoded_max_len; 53 struct MHD_BasicAuthInfo *ret; 54 55 params = MHD_get_rq_bauth_params_ (connection); 56 57 if (NULL == params) 58 return NULL; 59 60 if ((NULL == params->token68.str) || (0 == params->token68.len)) 61 return NULL; 62 63 decoded_max_len = MHD_base64_max_dec_size_ (params->token68.len); 64 ret = (struct MHD_BasicAuthInfo *) malloc (sizeof(struct MHD_BasicAuthInfo) 65 + decoded_max_len + 1); 66 if (NULL != ret) 67 { 68 size_t decoded_len; 69 char *decoded; 70 71 decoded = (char *) (ret + 1); 72 decoded_len = MHD_base64_to_bin_n (params->token68.str, params->token68.len, 73 decoded, decoded_max_len); 74 mhd_assert (decoded_max_len >= decoded_len); 75 if (0 != decoded_len) 76 { 77 size_t username_len; 78 char *colon; 79 80 colon = memchr (decoded, ':', decoded_len); 81 if (NULL != colon) 82 { 83 size_t password_pos; 84 size_t password_len; 85 86 username_len = (size_t) (colon - decoded); 87 password_pos = username_len + 1; 88 password_len = decoded_len - password_pos; 89 ret->password = decoded + password_pos; 90 ret->password[password_len] = 0; /* Zero-terminate the string */ 91 ret->password_len = password_len; 92 } 93 else 94 { 95 username_len = decoded_len; 96 ret->password = NULL; 97 ret->password_len = 0; 98 } 99 ret->username = decoded; 100 ret->username[username_len] = 0; /* Zero-terminate the string */ 101 ret->username_len = username_len; 102 103 return ret; /* Success exit point */ 104 } 105 #ifdef HAVE_MESSAGES 106 else 107 MHD_DLOG (connection->daemon, 108 _ ("Error decoding Basic Authorization authentication.\n")); 109 #endif /* HAVE_MESSAGES */ 110 111 free (ret); 112 } 113 #ifdef HAVE_MESSAGES 114 else 115 { 116 MHD_DLOG (connection->daemon, 117 _ ("Failed to allocate memory to process " \ 118 "Basic Authorization authentication.\n")); 119 } 120 #endif /* HAVE_MESSAGES */ 121 122 return NULL; /* Failure exit point */ 123 } 124 125 126 /** 127 * Get the username and password from the basic authorization header sent by the client 128 * 129 * @param connection The MHD connection structure 130 * @param[out] password a pointer for the password, free using #MHD_free(). 131 * @return NULL if no username could be found, a pointer 132 * to the username if found, free using #MHD_free(). 133 * @deprecated use #MHD_basic_auth_get_username_password3() 134 * @ingroup authentication 135 */ 136 _MHD_EXTERN char * 137 MHD_basic_auth_get_username_password (struct MHD_Connection *connection, 138 char **password) 139 { 140 struct MHD_BasicAuthInfo *info; 141 142 info = MHD_basic_auth_get_username_password3 (connection); 143 if (NULL == info) 144 return NULL; 145 146 /* For backward compatibility this function must return NULL if 147 * no password is provided */ 148 if (NULL != info->password) 149 { 150 char *username; 151 152 username = malloc (info->username_len + 1); 153 if (NULL != username) 154 { 155 memcpy (username, info->username, info->username_len + 1); 156 mhd_assert (0 == username[info->username_len]); 157 if (NULL != password) 158 { 159 *password = malloc (info->password_len + 1); 160 if (NULL != *password) 161 { 162 memcpy (*password, info->password, info->password_len + 1); 163 mhd_assert (0 == (*password)[info->password_len]); 164 165 free (info); 166 return username; /* Success exit point */ 167 } 168 #ifdef HAVE_MESSAGES 169 else 170 MHD_DLOG (connection->daemon, 171 _ ("Failed to allocate memory.\n")); 172 #endif /* HAVE_MESSAGES */ 173 } 174 else 175 { 176 free (info); 177 return username; /* Success exit point */ 178 } 179 180 free (username); 181 } 182 #ifdef HAVE_MESSAGES 183 else 184 MHD_DLOG (connection->daemon, 185 _ ("Failed to allocate memory.\n")); 186 #endif /* HAVE_MESSAGES */ 187 188 } 189 free (info); 190 if (NULL != password) 191 *password = NULL; 192 return NULL; /* Failure exit point */ 193 } 194 195 196 /** 197 * Queues a response to request basic authentication from the client. 198 * 199 * The given response object is expected to include the payload for 200 * the response; the "WWW-Authenticate" header will be added and the 201 * response queued with the 'UNAUTHORIZED' status code. 202 * 203 * See RFC 7617#section-2 for details. 204 * 205 * The @a response is modified by this function. The modified response object 206 * can be used to respond subsequent requests by #MHD_queue_response() 207 * function with status code #MHD_HTTP_UNAUTHORIZED and must not be used again 208 * with MHD_queue_basic_auth_required_response3() function. The response could 209 * be destroyed right after call of this function. 210 * 211 * @param connection the MHD connection structure 212 * @param realm the realm presented to the client 213 * @param prefer_utf8 if not set to #MHD_NO, parameter'charset="UTF-8"' will 214 * be added, indicating for client that UTF-8 encoding 215 * is preferred 216 * @param response the response object to modify and queue; the NULL 217 * is tolerated 218 * @return #MHD_YES on success, #MHD_NO otherwise 219 * @note Available since #MHD_VERSION 0x00097704 220 * @ingroup authentication 221 */ 222 _MHD_EXTERN enum MHD_Result 223 MHD_queue_basic_auth_required_response3 (struct MHD_Connection *connection, 224 const char *realm, 225 int prefer_utf8, 226 struct MHD_Response *response) 227 { 228 static const char prefix[] = "Basic realm=\""; 229 static const char suff_charset[] = "\", charset=\"UTF-8\""; 230 static const size_t prefix_len = MHD_STATICSTR_LEN_ (prefix); 231 static const size_t suff_simple_len = MHD_STATICSTR_LEN_ ("\""); 232 static const size_t suff_charset_len = 233 MHD_STATICSTR_LEN_ (suff_charset); 234 enum MHD_Result ret; 235 char *h_str; 236 size_t h_maxlen; 237 size_t suffix_len; 238 size_t realm_len; 239 size_t realm_quoted_len; 240 size_t pos; 241 242 if (NULL == response) 243 return MHD_NO; 244 245 suffix_len = (0 == prefer_utf8) ? suff_simple_len : suff_charset_len; 246 realm_len = strlen (realm); 247 h_maxlen = prefix_len + realm_len * 2 + suffix_len; 248 249 h_str = (char *) malloc (h_maxlen + 1); 250 if (NULL == h_str) 251 { 252 #ifdef HAVE_MESSAGES 253 MHD_DLOG (connection->daemon, 254 "Failed to allocate memory for Basic Authentication header.\n"); 255 #endif /* HAVE_MESSAGES */ 256 return MHD_NO; 257 } 258 memcpy (h_str, prefix, prefix_len); 259 pos = prefix_len; 260 realm_quoted_len = MHD_str_quote (realm, realm_len, h_str + pos, 261 h_maxlen - prefix_len - suffix_len); 262 pos += realm_quoted_len; 263 mhd_assert (pos + suffix_len <= h_maxlen); 264 if (0 == prefer_utf8) 265 { 266 h_str[pos++] = '\"'; 267 h_str[pos++] = 0; /* Zero terminate the result */ 268 mhd_assert (pos <= h_maxlen + 1); 269 } 270 else 271 { 272 /* Copy with the final zero-termination */ 273 mhd_assert (pos + suff_charset_len <= h_maxlen); 274 memcpy (h_str + pos, suff_charset, suff_charset_len + 1); 275 mhd_assert (0 == h_str[pos + suff_charset_len]); 276 } 277 278 ret = MHD_add_response_header (response, 279 MHD_HTTP_HEADER_WWW_AUTHENTICATE, 280 h_str); 281 free (h_str); 282 if (MHD_NO != ret) 283 { 284 ret = MHD_queue_response (connection, 285 MHD_HTTP_UNAUTHORIZED, 286 response); 287 } 288 else 289 { 290 #ifdef HAVE_MESSAGES 291 MHD_DLOG (connection->daemon, 292 _ ("Failed to add Basic Authentication header.\n")); 293 #endif /* HAVE_MESSAGES */ 294 } 295 return ret; 296 } 297 298 299 /** 300 * Queues a response to request basic authentication from the client 301 * The given response object is expected to include the payload for 302 * the response; the "WWW-Authenticate" header will be added and the 303 * response queued with the 'UNAUTHORIZED' status code. 304 * 305 * @param connection The MHD connection structure 306 * @param realm the realm presented to the client 307 * @param response response object to modify and queue; the NULL is tolerated 308 * @return #MHD_YES on success, #MHD_NO otherwise 309 * @deprecated use MHD_queue_basic_auth_required_response3() 310 * @ingroup authentication 311 */ 312 _MHD_EXTERN enum MHD_Result 313 MHD_queue_basic_auth_fail_response (struct MHD_Connection *connection, 314 const char *realm, 315 struct MHD_Response *response) 316 { 317 return MHD_queue_basic_auth_required_response3 (connection, realm, MHD_NO, 318 response); 319 } 320 321 322 /* end of basicauth.c */