Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/src/misc/   (VLC Media Plyer ©)  Datei vom 23.9.2026 mit Größe 18 kB image not shown  

Quelle  keystore.c   Sprache: C

 

/*****************************************************************************
 * keystore.c:
 *****************************************************************************
 * Copyright (C) 2015-2016  VLC authors, VideoLAN and VideoLabs
 *
 * This program 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.
 *
 * This program 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 this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/


#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <vlc_common.h>
#include <vlc_dialog.h>
#include <vlc_keystore.h>
#include <vlc_modules.h>
#include <vlc_url.h>
#include <vlc_interrupt.h>
#include "../libvlc.h"

#include <assert.h>
#include <limits.h>

static vlc_keystore *
keystore_create(vlc_object_t *p_parent, const char *psz_name)
{
    vlc_keystore *p_keystore = vlc_custom_create(p_parent, sizeof (*p_keystore),
                                                 "keystore");
    if (unlikely(p_keystore == NULL))
        return NULL;

    p_keystore->p_module = module_need(p_keystore, "keystore", psz_name, true);
    if (p_keystore->p_module == NULL)
    {
        vlc_object_delete(p_keystore);
        return NULL;
    }
    assert(p_keystore->pf_store);
    assert(p_keystore->pf_find);
    assert(p_keystore->pf_remove);

    return p_keystore;
}

#undef vlc_keystore_create
vlc_keystore *
vlc_keystore_create(vlc_object_t *p_parent)
{
    assert(p_parent);

    char *modlist = var_InheritString(p_parent, "keystore");
    vlc_keystore *p_keystore = keystore_create(p_parent, modlist);

    free(modlist);
    return p_keystore;
}

void
vlc_keystore_release(vlc_keystore *p_keystore)
{
    assert(p_keystore);
    module_unneed(p_keystore, p_keystore->p_module);

    vlc_object_delete(p_keystore);
}

int
vlc_keystore_store(vlc_keystore *p_keystore,
                   const char * const ppsz_values[KEY_MAX],
                   const uint8_t *p_secret, ssize_t i_secret_len,
                   const char *psz_label)
{
    assert(p_keystore && ppsz_values && p_secret && i_secret_len);

    if (!ppsz_values[KEY_PROTOCOL] || !ppsz_values[KEY_SERVER])
    {
        msg_Err(p_keystore, "invalid store request: "
                "protocol and server should be valid");
        return VLC_EGENERIC;
    }
    if (ppsz_values[KEY_PORT])
    {
        long int i_port = strtol(ppsz_values[KEY_PORT], NULL, 10);
        if (i_port == LONG_MIN || i_port == LONG_MAX)
        {
            msg_Err(p_keystore, "invalid store request: "
                    "port is not valid number");
            return VLC_EGENERIC;
        }
    }
    if (i_secret_len < 0)
        i_secret_len = strlen((const char *)p_secret) + 1;
    return p_keystore->pf_store(p_keystore, ppsz_values, p_secret, i_secret_len,
                                psz_label);
}

unsigned int
vlc_keystore_find(vlc_keystore *p_keystore,
                  const char * const ppsz_values[KEY_MAX],
                  vlc_keystore_entry **pp_entries)
{
    assert(p_keystore && ppsz_values && pp_entries);
    return p_keystore->pf_find(p_keystore, ppsz_values, pp_entries);
}

unsigned int
vlc_keystore_remove(vlc_keystore *p_keystore,
                    const char *const ppsz_values[KEY_MAX])
{
    assert(p_keystore && ppsz_values);
    return p_keystore->pf_remove(p_keystore, ppsz_values);
}

void
vlc_keystore_release_entries(vlc_keystore_entry *p_entries, unsigned int i_count)
{
    for (unsigned int i = 0; i < i_count; ++i)
        vlc_keystore_release_entry(&p_entries[i]);
    free(p_entries);
}

int
libvlc_InternalKeystoreInit(libvlc_int_t *p_libvlc)
{
    assert(p_libvlc != NULL);
    libvlc_priv_t *p_priv = libvlc_priv(p_libvlc);

    p_priv->p_memory_keystore = keystore_create(VLC_OBJECT(p_libvlc), "memory");
    return p_priv->p_memory_keystore != NULL ? VLC_SUCCESS : VLC_EGENERIC;
}

void
libvlc_InternalKeystoreClean(libvlc_int_t *p_libvlc)
{
    assert(p_libvlc != NULL);
    libvlc_priv_t *p_priv = libvlc_priv(p_libvlc);

    if (p_priv->p_memory_keystore != NULL)
    {
        vlc_keystore_release(p_priv->p_memory_keystore);
        p_priv->p_memory_keystore = NULL;
    }
}

static vlc_keystore *
get_memory_keystore(vlc_object_t *p_obj)
{
    return libvlc_priv(vlc_object_instance(p_obj))->p_memory_keystore;
}

static vlc_keystore_entry *
find_closest_path(vlc_keystore_entry *p_entries, unsigned i_count,
                  const char *psz_path)
{
    vlc_keystore_entry *p_match_entry = NULL;
    size_t i_last_pathlen = 0;
    char *psz_decoded_path = vlc_uri_decode_duplicate(psz_path);
    if (psz_decoded_path == NULL)
        return NULL;

    /* Try to find the entry that has the closest path to psz_url */
    for (unsigned int i = 0; i < i_count; ++i)
    {
        vlc_keystore_entry *p_entry = &p_entries[i];
        const char *psz_entry_path = p_entry->ppsz_values[KEY_PATH];
        if (psz_entry_path == NULL)
        {
            if (p_match_entry == NULL)
                p_match_entry = p_entry;
            continue;
        }
        size_t i_entry_pathlen = strlen(psz_entry_path);

        if (strncasecmp(psz_decoded_path, psz_entry_path, i_entry_pathlen) == 0
         && i_entry_pathlen > i_last_pathlen)
        {
            i_last_pathlen = i_entry_pathlen;
            p_match_entry = p_entry;
        }
    }
    free(psz_decoded_path);
    return p_match_entry;
}

static bool
is_credential_valid(vlc_credential *p_credential)
{
    if (p_credential->psz_username && p_credential->psz_password)
        return true;
    p_credential->psz_password = NULL;
    return false;
}

static bool
is_url_valid(const vlc_url_t *p_url)
{
    return p_url && p_url->psz_protocol && p_url->psz_protocol[0]
        && p_url->psz_host && p_url->psz_host[0];
}

/* Default port for each protocol */
static struct
{
    const char *    psz_protocol;
    uint16_t        i_port;
} protocol_default_ports [] = {
    { "rtsp", 80 },
    { "http", 80 },
    { "https", 443 },
    { "ftp", 21 },
    { "sftp", 22 },
    { "smb", 445 },
};

/* Don't store a port if it's the default one */
static bool
protocol_set_port(const vlc_url_t *p_url, char *psz_port)
{
    int i_port = -1;

    if (p_url->i_port != 0 && p_url->i_port <= UINT16_MAX)
        i_port = p_url->i_port;
    else
    {
        for (unsigned int i = 0; i < ARRAY_SIZE(protocol_default_ports); ++i)
        {
            if (strcasecmp(p_url->psz_protocol,
                           protocol_default_ports[i].psz_protocol) == 0)
            {
                i_port = protocol_default_ports[i].i_port;
                break;
            }
        }
    }
    if (i_port != -1)
    {
        sprintf(psz_port, "%" PRIu16, (uint16_t) i_port);
        return true;
    }
    return false;
}

static bool
protocol_is_smb(const vlc_url_t *p_url)
{
    return strcasecmp(p_url->psz_protocol, "smb") == 0;
}

static bool
protocol_store_path(const vlc_url_t *p_url)
{
    return p_url->psz_path
      && (strncasecmp(p_url->psz_protocol, "http", 4) == 0
      || strcasecmp(p_url->psz_protocol, "rtsp") == 0
      || protocol_is_smb(p_url));
}

/* Split domain;user in userinfo */
static void
smb_split_domain(vlc_credential *p_credential)
{
    const char *psz_delim = strchr(p_credential->psz_username, ';');
    if (psz_delim == NULL)
        return;

    size_t i_len = psz_delim - p_credential->psz_username;
    if (i_len > 0)
    {
        free(p_credential->psz_split_domain);
        p_credential->psz_split_domain =
            strndup(p_credential->psz_username, i_len);
        p_credential->psz_realm = p_credential->psz_split_domain;
    }
    p_credential->psz_username = psz_delim + 1;
}

static void
credential_find_keystore(vlc_credential *p_credential, vlc_keystore *p_keystore)
{
    const vlc_url_t *p_url = p_credential->p_url;

    const char *ppsz_values[KEY_MAX] = { 0 };
    ppsz_values[KEY_PROTOCOL] = p_url->psz_protocol;
    ppsz_values[KEY_USER] = p_credential->psz_username;
    ppsz_values[KEY_SERVER] = p_url->psz_host;
    /* don't try to match with the path */
    ppsz_values[KEY_REALM] = p_credential->psz_realm;
    ppsz_values[KEY_AUTHTYPE] = p_credential->psz_authtype;
    char psz_port[21];
    if (protocol_set_port(p_url, psz_port))
        ppsz_values[KEY_PORT] = psz_port;

    vlc_keystore_entry *p_entries;
    unsigned int i_entries_count;
    i_entries_count = vlc_keystore_find(p_keystore, ppsz_values, &p_entries);

    /* Remove last entries after vlc_keystore_find call since
     * p_credential->psz_username (default username) can be a pointer to an
     * entry */

    if (p_credential->i_entries_count > 0)
    {
        vlc_keystore_release_entries(p_credential->p_entries,
                                     p_credential->i_entries_count);
        p_credential->psz_username = NULL;
    }
    p_credential->p_entries = p_entries;
    p_credential->i_entries_count = i_entries_count;

    if (p_credential->i_entries_count > 0)
    {
        vlc_keystore_entry *p_entry;

        if (protocol_store_path(p_url))
            p_entry = find_closest_path(p_credential->p_entries,
                                        p_credential->i_entries_count,
                                        p_url->psz_path);
        else
            p_entry = &p_credential->p_entries[0];

        if (!p_entry || p_entry->p_secret[p_entry->i_secret_len - 1] != '\0')
        {
            vlc_keystore_release_entries(p_credential->p_entries,
                                         p_credential->i_entries_count);
            p_credential->i_entries_count = 0;
        }
        else
        {
            p_credential->psz_password = (const char *)p_entry->p_secret;
            p_credential->psz_username = p_entry->ppsz_values[KEY_USER];
            p_credential->psz_realm = p_entry->ppsz_values[KEY_REALM];
            p_credential->psz_authtype = p_entry->ppsz_values[KEY_AUTHTYPE];
            p_credential->b_from_keystore = true;
        }
    }
}

void
vlc_credential_init(vlc_credential *p_credential, const vlc_url_t *p_url)
{
    assert(p_credential);

    memset(p_credential, 0, sizeof(*p_credential));
    p_credential->i_get_order = GET_FROM_URL;
    p_credential->p_url = p_url;
}

void
vlc_credential_clean(vlc_credential *p_credential)
{
    if (p_credential->i_entries_count > 0)
        vlc_keystore_release_entries(p_credential->p_entries,
                                     p_credential->i_entries_count);
    if (p_credential->p_keystore)
        vlc_keystore_release(p_credential->p_keystore);

    free(p_credential->psz_split_domain);
    free(p_credential->psz_var_username);
    free(p_credential->psz_var_password);
    free(p_credential->psz_dialog_username);
    free(p_credential->psz_dialog_password);
}

#undef vlc_credential_get
int
vlc_credential_get(vlc_credential *p_credential, vlc_object_t *p_parent,
                   const char *psz_option_username,
                   const char *psz_option_password,
                   const char *psz_dialog_title,
                   const char *psz_dialog_fmt, ...)
{
    assert(p_credential && p_parent);
    const vlc_url_t *p_url = p_credential->p_url;

    if (!is_url_valid(p_url))
    {
        msg_Err(p_parent, "vlc_credential_get: invalid url");
        return -EINVAL;
    }

    p_credential->b_from_keystore = false;
    /* Don't set username to NULL, we may want to use the last one set */
    p_credential->psz_password = NULL;

    while (!is_credential_valid(p_credential))
    {
        /* First, fetch credential from URL (if any).
         * Secondly, fetch credential from VLC Options (if any).
         * Thirdly, fetch credential from keystore (if any) using user and realm
         * previously set by the caller, the URL or by VLC Options.
         * Finally, fetch credential from the dialog (if any). This last will be
         * repeated until user cancel the dialog. */


        switch (p_credential->i_get_order)
        {
        case GET_FROM_URL:
            p_credential->psz_username = p_url->psz_username;
            p_credential->psz_password = p_url->psz_password;

            if (p_credential->psz_password)
                msg_Warn(p_parent, "Password in a URI is DEPRECATED");

            if (p_url->psz_username && protocol_is_smb(p_url))
                smb_split_domain(p_credential);
            p_credential->i_get_order++;
            break;

        case GET_FROM_OPTION:
            free(p_credential->psz_var_username);
            free(p_credential->psz_var_password);
            p_credential->psz_var_username =
            p_credential->psz_var_password = NULL;

            if (psz_option_username)
                p_credential->psz_var_username =
                    var_InheritString(p_parent, psz_option_username);
            if (psz_option_password)
                p_credential->psz_var_password =
                    var_InheritString(p_parent, psz_option_password);

            if (p_credential->psz_var_username)
                p_credential->psz_username = p_credential->psz_var_username;
            if (p_credential->psz_var_password)
                p_credential->psz_password = p_credential->psz_var_password;

            p_credential->i_get_order++;
            break;

        case GET_FROM_MEMORY_KEYSTORE:
        {
            vlc_keystore *p_keystore = get_memory_keystore(p_parent);
            if (p_keystore != NULL)
                credential_find_keystore(p_credential, p_keystore);
            p_credential->i_get_order++;
            break;
        }

        case GET_FROM_KEYSTORE:
            if (p_credential->p_keystore == NULL)
                p_credential->p_keystore = vlc_keystore_create(p_parent);
            if (p_credential->p_keystore != NULL)
                credential_find_keystore(p_credential, p_credential->p_keystore);

            if (vlc_killed())
                return -EINTR;

            p_credential->i_get_order++;
            break;

        default:
        case GET_FROM_DIALOG:
            if (!psz_dialog_title || !psz_dialog_fmt)
                return -ENOENT;
            char *psz_dialog_username = NULL;
            char *psz_dialog_password = NULL;
            va_list ap;
            va_start(ap, psz_dialog_fmt);
            bool *p_store = p_credential->p_keystore != NULL ?
                            &p_credential->b_store : NULL;
            int i_ret =
                vlc_dialog_wait_login_va(p_parent,
                                         &psz_dialog_username,
                                         &psz_dialog_password, p_store,
                                         p_credential->psz_username,
                                         psz_dialog_title, psz_dialog_fmt, ap);
            va_end(ap);

            /* Free previous dialog strings after vlc_dialog_wait_login_va call
             * since p_credential->psz_username (default username) can be a
             * pointer to p_credential->psz_dialog_username */

            free(p_credential->psz_dialog_username);
            free(p_credential->psz_dialog_password);
            p_credential->psz_dialog_username = psz_dialog_username;
            p_credential->psz_dialog_password = psz_dialog_password;

            if (i_ret != 1)
            {
                p_credential->psz_username = p_credential->psz_password = NULL;
                return vlc_killed() ? -EINTR : -ENOENT;
            }

            p_credential->psz_username = p_credential->psz_dialog_username;
            p_credential->psz_password = p_credential->psz_dialog_password;

            if (protocol_is_smb(p_url))
                smb_split_domain(p_credential);

            break;
        }
    }
    return is_credential_valid(p_credential) ? 0 : -ENOENT;
}

#undef vlc_credential_store
bool
vlc_credential_store(vlc_credential *p_credential, vlc_object_t *p_parent)
{
    if (!is_credential_valid(p_credential))
        return false;
    /* Don't need to store again */
    if (p_credential->b_from_keystore)
        return p_credential->b_from_keystore;

    vlc_keystore *p_keystore;
    if (p_credential->b_store)
    {
        /* Store in permanent keystore */
        assert(p_credential->p_keystore != NULL);
        p_keystore = p_credential->p_keystore;
    }
    else
    {
        /* Store in memory keystore */
        p_keystore = get_memory_keystore(p_parent);
    }
    if (p_keystore == NULL)
        return false;

    const vlc_url_t *p_url = p_credential->p_url;

    char *psz_path = NULL;
    if (protocol_store_path(p_url)
     && (psz_path =  vlc_uri_decode_duplicate(p_url->psz_path)) != NULL)
    {
        char *p_slash;
        if (protocol_is_smb(p_url))
        {
            /* Remove all characters after the first slash (store the share but
             * not the path) */

            p_slash = strchr(psz_path + 1, '/');
        }
        else
        {
            /* Remove all characters after the last slash (store the path
             * without the filename) */

            p_slash = strrchr(psz_path + 1, '/');
        }
        if (p_slash && psz_path != p_slash)
            *p_slash = '\0';
    }

    const char *ppsz_values[KEY_MAX] = { 0 };
    ppsz_values[KEY_PROTOCOL] = p_url->psz_protocol;
    ppsz_values[KEY_USER] = p_credential->psz_username;
    ppsz_values[KEY_SERVER] = p_url->psz_host;
    ppsz_values[KEY_PATH] = psz_path;
    ppsz_values[KEY_REALM] = p_credential->psz_realm;
    ppsz_values[KEY_AUTHTYPE] = p_credential->psz_authtype;

    char psz_port[21];
    if (protocol_set_port(p_url, psz_port))
        ppsz_values[KEY_PORT] = psz_port;

    char *psz_label;
    if (asprintf(&psz_label, "LibVLC password for %s://%s%s",
                 p_url->psz_protocol, p_url->psz_host,
                 psz_path ? psz_path : "") == -1)
    {
        free(psz_path);
        return false;
    }

    const uint8_t *p_password = (const uint8_t *)
        (p_credential->psz_password != NULL ? p_credential->psz_password : "");

    bool b_ret = vlc_keystore_store(p_keystore, ppsz_values, p_password,
                                    -1, psz_label) == VLC_SUCCESS;
    free(psz_label);
    free(psz_path);
    return b_ret;
}

Messung
CHZG
839710093

¤ Dauer der Verarbeitung: 0.3 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.