/* * HTTP authentication * Copyright (c) 2010 Martin Storsjo * * This file is part of FFmpeg. * * FFmpeg 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. * * FFmpeg 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 FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "httpauth.h" #include "libavutil/base64.h" #include "libavutil/avstring.h" #include "avformat.h" #include static void parse_key_value(const char *params, void (*callback_get_buf)(HTTPAuthState *state, const char *key, int key_len, char **dest, int *dest_len), HTTPAuthState *state) { const char *ptr = params; /* Parse key=value pairs. */ for (;;) { const char *key; char *dest = NULL, *dest_end; int key_len, dest_len = 0; /* Skip whitespace and potential commas. */ while (*ptr && (isspace(*ptr) || *ptr == ',')) ptr++; if (!*ptr) break; key = ptr; if (!(ptr = strchr(key, '='))) break; ptr++; key_len = ptr - key; callback_get_buf(state, key, key_len, &dest, &dest_len); dest_end = dest + dest_len - 1; if (*ptr == '\"') { ptr++; while (*ptr && *ptr != '\"') { if (*ptr == '\\') { if (!ptr[1]) break; if (dest && dest < dest_end) *dest++ = ptr[1]; ptr += 2; } else { if (dest && dest < dest_end) *dest++ = *ptr; ptr++; } } if (*ptr == '\"') ptr++; } else { for (; *ptr && !(isspace(*ptr) || *ptr == ','); ptr++) if (dest && dest < dest_end) *dest++ = *ptr; } if (dest) *dest = 0; } } static void handle_basic_params(HTTPAuthState *state, const char *key, int key_len, char **dest, int *dest_len) { if (!strncmp(key, "realm=", key_len)) { *dest = state->realm; *dest_len = sizeof(state->realm); } } void ff_http_auth_handle_header(HTTPAuthState *state, const char *key, const char *value) { if (!state) return; if (!strcmp(key, "WWW-Authenticate")) { const char *p; if (av_stristart(value, "Basic ", &p) && state->auth_type <= HTTP_AUTH_BASIC) { state->auth_type = HTTP_AUTH_BASIC; state->realm[0] = 0; parse_key_value(p, handle_basic_params, state); } } } char *ff_http_auth_create_response(HTTPAuthState *state, const char *auth, const char *path, const char *method) { char *authstr = NULL; if (!auth || !strchr(auth, ':')) return NULL; if (state->auth_type == HTTP_AUTH_BASIC) { int auth_b64_len = (strlen(auth) + 2) / 3 * 4 + 1; int len = auth_b64_len + 30; char *ptr; authstr = av_malloc(len); if (!authstr) return NULL; snprintf(authstr, len, "Authorization: Basic "); ptr = authstr + strlen(authstr); av_base64_encode(ptr, auth_b64_len, auth, strlen(auth)); av_strlcat(ptr, "\r\n", len); } return authstr; }