>From ab1cb5d40765383ea1c11eca9c3d641f9d49bdd8 Mon Sep 17 00:00:00 2001
From: Yclept Nemo <pscjtwjdjtAhnbjm/dpn>
Date: Mon, 18 May 2015 14:07:13 -0400
Subject: [PATCH] smbclient auth support

There is now a backend block which in turns provides several password
configuration backends:

Configuration file:
    backend {
        name                "smbclient"
        password_backend    "config"
        username            "ExampleName"
        password            "ExamplePassword"
    }
Libsecret (keyring):
    backend {
        name                "smbclient"
        password_backend    "libsecret"
        username            "ExampleName"
    }

Some values are optional:
    backend {
        name        "smbclient"
        workgroup   "FANCYWORKGROUP"
        username    "ExampleName"
    }

Defaults:
    workgroup           "WORKGROUP"
    username            ""
    password            ""
    password_backend    "config"

Use scripts/mpd.secret.py to store a secret (password) and optionally
create a new collection (keyring).
---
 .gitignore                     |   1 +
 Makefile.am                    |  12 +++-
 configure.ac                   |   5 ++
 scripts/mpd.secret.py          | 111 +++++++++++++++++++++++++++++++
 src/config/ConfigOption.hxx    |   1 +
 src/config/ConfigTemplates.cxx |   1 +
 src/lib/smbclient/Init.cxx     | 144
++++++++++++++++++++++++++++++++++++++---
 src/lib/smbclient/Init.hxx     |  63 +++++++++++++++++-
 8 files changed, 323 insertions(+), 15 deletions(-)
 create mode 100755 scripts/mpd.secret.py

diff --git a/.gitignore b/.gitignore
index ba6d3b3..e28c23b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@
 *.lo
 *.o
 *.exe
+*.*.swp

 *~

diff --git a/Makefile.am b/Makefile.am
index c6bcfa1..bda719a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -611,12 +611,14 @@ libstorage_a_SOURCES = \

 libstorage_a_CPPFLAGS = $(AM_CPPFLAGS) \
     $(NFS_CFLAGS) \
-    $(SMBCLIENT_CFLAGS)
+    $(SMBCLIENT_CFLAGS) \
+    $(LIBSECRET_CFLAGS)

 STORAGE_LIBS = \
     libstorage.a \
     $(NFS_LIBS) \
-    $(SMBCLIENT_LIBS)
+    $(SMBCLIENT_LIBS) \
+    $(LIBSECRET_LIBS)

 if ENABLE_SMBCLIENT
 libstorage_a_SOURCES += \
@@ -651,7 +653,8 @@ libneighbor_a_SOURCES = \
     src/neighbor/NeighborPlugin.hxx

 libneighbor_a_CPPFLAGS = $(AM_CPPFLAGS) \
-    $(SMBCLIENT_CFLAGS)
+    $(SMBCLIENT_CFLAGS) \
+    $(LIBSECRET_CFLAGS)

 if ENABLE_SMBCLIENT
 libneighbor_a_SOURCES += \
@@ -661,6 +664,7 @@ endif

 NEIGHBOR_LIBS = \
     $(SMBCLIENT_LIBS) \
+    $(LIBSECRET_LIBS) \
     libneighbor.a

 if ENABLE_UPNP
@@ -1165,6 +1169,7 @@ libinput_a_SOURCES = \
 libinput_a_CPPFLAGS = $(AM_CPPFLAGS) \
     $(CURL_CFLAGS) \
     $(SMBCLIENT_CFLAGS) \
+    $(LIBSECRET_CFLAGS) \
     $(NFS_CFLAGS) \
     $(CDIO_PARANOIA_CFLAGS) \
     $(FFMPEG_CFLAGS) \
@@ -1174,6 +1179,7 @@ INPUT_LIBS = \
     libinput.a \
     $(CURL_LIBS) \
     $(SMBCLIENT_LIBS) \
+    $(LIBSECRET_LIBS) \
     $(NFS_LIBS) \
     $(CDIO_PARANOIA_LIBS) \
     $(FFMPEG_LIBS2) \
diff --git a/configure.ac b/configure.ac
index dfd208a..82f814d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -709,6 +709,10 @@ dnl ----------------------------------- CURL
----------------------------------
 MPD_ENABLE_AUTO_PKG(curl, CURL, [libcurl >= 7.18],
     [libcurl HTTP streaming], [libcurl not found])

+dnl --------------------------------- LIBSECRET
-------------------------------
+MPD_ENABLE_AUTO_PKG(libsecret, LIBSECRET, [libsecret-1],
+    [libsecret password support], [libsecret not found])
+
 dnl ----------------------------------- smbclient
-----------------------------
 MPD_ENABLE_AUTO_PKG_LIB(smbclient, SMBCLIENT, [smbclient >= 0.2],
     [smbclient], [smbc_init], [-lsmbclient], [],
@@ -1421,6 +1425,7 @@ results(soxr, [libsoxr])
 results(libmpdclient, [libmpdclient])
 results(inotify, [inotify])
 results(sqlite, [SQLite])
+results(libsecret, [LIBSECRET])

 printf '\nMetadata support:\n\t'
 results(id3,[ID3])
diff --git a/scripts/mpd.secret.py b/scripts/mpd.secret.py
new file mode 100755
index 0000000..30cb497
--- /dev/null
+++ b/scripts/mpd.secret.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2003-2015 The Music Player Daemon Project
+# http://www.musicpd.org
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 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 General Public License for more details.
+#
+# You should have received a copy of the GNU 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.
+#
+
+
+import getpass
+from gi.repository import Secret
+
+
+mpd_schema_attributes =\
+    { "server"    : Secret.SchemaAttributeType.STRING
+    , "share"     : Secret.SchemaAttributeType.STRING
+    , "workgroup" : Secret.SchemaAttributeType.STRING
+    , "username"  : Secret.SchemaAttributeType.STRING
+    }
+
+mpd_schema = Secret.Schema.new\
+    ( "org.mpd.smbclient.password"
+    , Secret.SchemaFlags.NONE
+    , mpd_schema_attributes
+    )
+
+mpd_default_input_data =\
+    { "collection"  : { "default": "MusicPD" }
+    , "password"    : { "secret": True }
+    , "server"      : { }
+    , "share"       : { }
+    , "workgroup"   : { "default": "WORKGROUP" }
+    , "username"    : { }
+    }
+
+
+def mpd_prompt(prompt, default=None, secret=False):
+    if default is None:
+        prompt = "{}: ".format(prompt)
+    else:
+        prompt = "{} [{}]: ".format(prompt, default)
+    string = ""
+    while not string:
+        if secret:
+            string = getpass.getpass(prompt)
+        else:
+            string = input(prompt)
+        if not string and default is not None:
+            string = default
+            break
+    return string
+
+def mpd_main():
+    input_data = mpd_input(mpd_default_input_data)
+    mpd_collection_ensure(input_data["collection"])
+    mpd_password_store(input_data)
+
+def mpd_input(input_data_arguments):
+    input_data = {}
+    print("<Enter> for default values (in parentheses)")
+    for attribute, arguments in sorted(input_data_arguments.items()):
+        input_data[attribute] = mpd_prompt(attribute, **arguments)
+    return input_data
+
+def mpd_collection_ensure(label):
+    service = Secret.Service.get_sync(Secret.ServiceFlags.LOAD_COLLECTIONS)
+    collections = Secret.Service.get_collections(service)
+    labels = [collection.get_label() for collection in collections]
+
+    if label not in labels:
+        Secret.Collection.create_sync\
+            ( service
+            , label
+            , None
+            , Secret.CollectionCreateFlags.COLLECTION_CREATE_NONE
+            , None
+            )
+
+def mpd_input_to_attributes(d):
+    return {k:v for k,v in d.items() if k in mpd_schema_attributes}
+
+def mpd_input_get_collection_path(input_data):
+    return
"/org/freedesktop/secrets/collection/{}".format(input_data["collection"])
+
+def mpd_input_get_password_label(input_data):
+    return "Smbclient Password: {}".format(input_data["server"])
+
+def mpd_password_store(input_data):
+    Secret.password_store_sync\
+        ( mpd_schema
+        , mpd_input_to_attributes(input_data)
+        , mpd_input_get_collection_path(input_data)
+        , mpd_input_get_password_label(input_data)
+        , input_data["password"]
+        , None
+        )
+
+if __name__ == "__main__":
+    mpd_main()
diff --git a/src/config/ConfigOption.hxx b/src/config/ConfigOption.hxx
index 5acd6fd..8d11a3f 100644
--- a/src/config/ConfigOption.hxx
+++ b/src/config/ConfigOption.hxx
@@ -90,6 +90,7 @@ enum class ConfigBlockOption {
     AUDIO_FILTER,
     DATABASE,
     NEIGHBORS,
+    BACKEND,
     MAX
 };

diff --git a/src/config/ConfigTemplates.cxx b/src/config/ConfigTemplates.cxx
index 6fbf025..d283e29 100644
--- a/src/config/ConfigTemplates.cxx
+++ b/src/config/ConfigTemplates.cxx
@@ -90,6 +90,7 @@ const ConfigTemplate config_block_templates[] = {
     { "filter", true },
     { "database", false },
     { "neighbors", true },
+    { "backend", "true" },
 };

 static constexpr unsigned n_config_block_templates =
diff --git a/src/lib/smbclient/Init.cxx b/src/lib/smbclient/Init.cxx
index 999e60f..991d02d 100644
--- a/src/lib/smbclient/Init.cxx
+++ b/src/lib/smbclient/Init.cxx
@@ -22,22 +22,146 @@
 #include "Mutex.hxx"
 #include "thread/Mutex.hxx"
 #include "util/Error.hxx"
+#include "config/ConfigGlobal.hxx"

 #include <libsmbclient.h>

 #include <string.h>

-static void
-mpd_smbc_get_auth_data(gcc_unused const char *srv,
-               gcc_unused const char *shr,
-               char *wg, gcc_unused int wglen,
-               char *un, gcc_unused int unlen,
-               char *pw, gcc_unused int pwlen)
+
+#ifdef ENABLE_LIBSECRET
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+const SecretSchema mpd_schema =
+    { "org.mpd.smbclient.password"
+    , SECRET_SCHEMA_NONE
+    , { { "server"
+        , SECRET_SCHEMA_ATTRIBUTE_STRING
+        }
+      , { "share"
+        , SECRET_SCHEMA_ATTRIBUTE_STRING
+        }
+      , { "workgroup"
+        , SECRET_SCHEMA_ATTRIBUTE_STRING
+        }
+      , { "username"
+        , SECRET_SCHEMA_ATTRIBUTE_STRING
+        }
+      , { "NULL"
+        , (SecretSchemaAttributeType)0
+        }
+      }
+    };
+#pragma GCC diagnostic pop
+#endif
+
+#ifdef ENABLE_LIBSECRET
+const char*
+mpd_smbc_get_auth_data_secret
+    ( SmbAuthData* smb_auth_data
+    )
 {
-    // TODO: implement
-    strcpy(wg, "WORKGROUP");
-    strcpy(un, "");
-    strcpy(pw, "");
+    GError *error = NULL;
+
+    // When to free?
+    const char* password = (const char*)secret_password_lookup_sync
+        ( &mpd_schema , NULL , &error
+        , "server", smb_auth_data->server
+        , "share", smb_auth_data->share
+        , "workgroup", smb_auth_data->workgroup
+        , "username", smb_auth_data->username
+        , NULL
+        );
+
+    if (error != NULL) {
+        g_error_free(error);
+        return "";
+    }
+
+    if (password == NULL) {
+        return "";
+    }
+
+    return password;
+}
+#endif
+
+const char*
+mpd_smbc_get_auth_data_password
+    ( SmbAuthData* smb_auth_data
+    , const ConfigBlock* block
+    )
+{   const char* password_backend =
block->GetBlockValue("password_backend", "config");
+
+    if (strcmp(password_backend, "config") == 0) {
+        return block->GetBlockValue("password", "");
+    }
+#ifdef ENABLE_LIBSECRET
+    if (strcmp(password_backend, "libsecret") == 0)
+        return mpd_smbc_get_auth_data_secret(smb_auth_data);
+#endif
+    return "";
+}
+
+SmbAuthData
+mpd_smbc_get_auth_data_default()
+{   return { .server    = ""
+           , .share     = ""
+           , .workgroup = "WORKGROUP"
+           , .username  = ""
+           , .password  = ""
+           };
+}
+
+void
+mpd_smbc_get_auth_data_config
+    ( SmbAuthData* smb_auth_data
+    )
+{   const ConfigBlock* block =
config_get_block(ConfigBlockOption::BACKEND);
+
+    if (block == nullptr)
+        return;
+
+    const char* backend_name = block->GetBlockValue("name", "");
+
+    if (strcmp(backend_name, "smbclient") != 0)
+        return;
+
+    smb_auth_data->workgroup = block->GetBlockValue("workgroup",
"WORKGROUP");
+    smb_auth_data->username = block->GetBlockValue("username", "");
+    smb_auth_data->password =
mpd_smbc_get_auth_data_password(smb_auth_data, block);
+}
+
+void
+mpd_smbc_set_auth_data
+    ( char* destination
+    , const char* source
+    , size_t num
+    )
+{   size_t source_len = strlen(source) + 1;
+    memcpy(destination, source, std::min(source_len, num));
+    if (source_len > num)
+        destination[num] = '\0';
+}
+
+void
+mpd_smbc_get_auth_data
+    ( const char* server
+    , const char* share
+    , char* workgroup,  int workgrouplen
+    , char* username,   int usernamelen
+    , char* password,   int passwordlen
+    )
+{   SmbAuthData smb_auth_data;
+
+    smb_auth_data = mpd_smbc_get_auth_data_default();
+    smb_auth_data.server = server;
+    smb_auth_data.share = share;
+    mpd_smbc_get_auth_data_config(&smb_auth_data);
+
+    mpd_smbc_set_auth_data(workgroup, smb_auth_data.workgroup,
workgrouplen);
+    mpd_smbc_set_auth_data(username, smb_auth_data.username, usernamelen);
+    mpd_smbc_set_auth_data(password, smb_auth_data.password, passwordlen);
 }

 bool
diff --git a/src/lib/smbclient/Init.hxx b/src/lib/smbclient/Init.hxx
index 1ccaec0..7f1994a 100644
--- a/src/lib/smbclient/Init.hxx
+++ b/src/lib/smbclient/Init.hxx
@@ -22,12 +22,71 @@

 #include "check.h"

+#include "config/Block.hxx"
+
+#ifdef ENABLE_LIBSECRET
+#include <libsecret/secret.h>
+#endif
+
+
 class Error;

-/**
+#ifdef ENABLE_LIBSECRET
+extern const SecretSchema mpd_schema;
+#endif
+
+struct SmbAuthData
+    { const char* server;
+      const char* share;
+      const char* workgroup;
+      const char* username;
+      const char* password;
+    };
+
+#ifdef ENABLE_LIBSECRET
+const char*
+mpd_smbc_get_auth_data_secret
+    ( SmbAuthData*
+    );
+#endif
+
+const char*
+mpd_smbc_get_auth_data_password
+    ( SmbAuthData*
+    , const ConfigBlock*
+    );
+
+SmbAuthData
+mpd_smbc_get_auth_data_default
+    ();
+
+void
+mpd_smbc_get_auth_data_config
+    ( SmbAuthData*
+    );
+
+void
+mpd_smbc_set_auth_data
+    ( char*
+    , const char*
+    , size_t
+    );
+
+void
+mpd_smbc_get_auth_data
+    ( const char*
+    , const char*
+    , char*, int
+    , char*, int
+    , char*, int
+    );
+
+/*
  * Initialize libsmbclient.
  */
 bool
-SmbclientInit(Error &error);
+SmbclientInit
+    (Error&
+    );

 #endif
-- 
2.1.4
From ab1cb5d40765383ea1c11eca9c3d641f9d49bdd8 Mon Sep 17 00:00:00 2001
From: Yclept Nemo <pscjtwjdjtAhnbjm/dpn>
Date: Mon, 18 May 2015 14:07:13 -0400
Subject: [PATCH] smbclient auth support

There is now a backend block which in turns provides several password
configuration backends:

Configuration file:
    backend {
        name                "smbclient"
        password_backend    "config"
        username            "ExampleName"
        password            "ExamplePassword"
    }
Libsecret (keyring):
    backend {
        name                "smbclient"
        password_backend    "libsecret"
        username            "ExampleName"
    }

Some values are optional:
    backend {
        name        "smbclient"
        workgroup   "FANCYWORKGROUP"
        username    "ExampleName"
    }

Defaults:
    workgroup           "WORKGROUP"
    username            ""
    password            ""
    password_backend    "config"

Use scripts/mpd.secret.py to store a secret (password) and optionally
create a new collection (keyring).
---
 .gitignore                     |   1 +
 Makefile.am                    |  12 +++-
 configure.ac                   |   5 ++
 scripts/mpd.secret.py          | 111 +++++++++++++++++++++++++++++++
 src/config/ConfigOption.hxx    |   1 +
 src/config/ConfigTemplates.cxx |   1 +
 src/lib/smbclient/Init.cxx     | 144 ++++++++++++++++++++++++++++++++++++++---
 src/lib/smbclient/Init.hxx     |  63 +++++++++++++++++-
 8 files changed, 323 insertions(+), 15 deletions(-)
 create mode 100755 scripts/mpd.secret.py

diff --git a/.gitignore b/.gitignore
index ba6d3b3..e28c23b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@
 *.lo
 *.o
 *.exe
+*.*.swp
 
 *~
 
diff --git a/Makefile.am b/Makefile.am
index c6bcfa1..bda719a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -611,12 +611,14 @@ libstorage_a_SOURCES = \
 
 libstorage_a_CPPFLAGS = $(AM_CPPFLAGS) \
 	$(NFS_CFLAGS) \
-	$(SMBCLIENT_CFLAGS)
+	$(SMBCLIENT_CFLAGS) \
+	$(LIBSECRET_CFLAGS)
 
 STORAGE_LIBS = \
 	libstorage.a \
 	$(NFS_LIBS) \
-	$(SMBCLIENT_LIBS)
+	$(SMBCLIENT_LIBS) \
+	$(LIBSECRET_LIBS)
 
 if ENABLE_SMBCLIENT
 libstorage_a_SOURCES += \
@@ -651,7 +653,8 @@ libneighbor_a_SOURCES = \
 	src/neighbor/NeighborPlugin.hxx
 
 libneighbor_a_CPPFLAGS = $(AM_CPPFLAGS) \
-	$(SMBCLIENT_CFLAGS)
+	$(SMBCLIENT_CFLAGS) \
+	$(LIBSECRET_CFLAGS)
 
 if ENABLE_SMBCLIENT
 libneighbor_a_SOURCES += \
@@ -661,6 +664,7 @@ endif
 
 NEIGHBOR_LIBS = \
 	$(SMBCLIENT_LIBS) \
+	$(LIBSECRET_LIBS) \
 	libneighbor.a
 
 if ENABLE_UPNP
@@ -1165,6 +1169,7 @@ libinput_a_SOURCES = \
 libinput_a_CPPFLAGS = $(AM_CPPFLAGS) \
 	$(CURL_CFLAGS) \
 	$(SMBCLIENT_CFLAGS) \
+	$(LIBSECRET_CFLAGS) \
 	$(NFS_CFLAGS) \
 	$(CDIO_PARANOIA_CFLAGS) \
 	$(FFMPEG_CFLAGS) \
@@ -1174,6 +1179,7 @@ INPUT_LIBS = \
 	libinput.a \
 	$(CURL_LIBS) \
 	$(SMBCLIENT_LIBS) \
+	$(LIBSECRET_LIBS) \
 	$(NFS_LIBS) \
 	$(CDIO_PARANOIA_LIBS) \
 	$(FFMPEG_LIBS2) \
diff --git a/configure.ac b/configure.ac
index dfd208a..82f814d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -709,6 +709,10 @@ dnl ----------------------------------- CURL ----------------------------------
 MPD_ENABLE_AUTO_PKG(curl, CURL, [libcurl >= 7.18],
 	[libcurl HTTP streaming], [libcurl not found])
 
+dnl --------------------------------- LIBSECRET -------------------------------
+MPD_ENABLE_AUTO_PKG(libsecret, LIBSECRET, [libsecret-1],
+	[libsecret password support], [libsecret not found])
+
 dnl ----------------------------------- smbclient -----------------------------
 MPD_ENABLE_AUTO_PKG_LIB(smbclient, SMBCLIENT, [smbclient >= 0.2],
 	[smbclient], [smbc_init], [-lsmbclient], [],
@@ -1421,6 +1425,7 @@ results(soxr, [libsoxr])
 results(libmpdclient, [libmpdclient])
 results(inotify, [inotify])
 results(sqlite, [SQLite])
+results(libsecret, [LIBSECRET])
 
 printf '\nMetadata support:\n\t'
 results(id3,[ID3])
diff --git a/scripts/mpd.secret.py b/scripts/mpd.secret.py
new file mode 100755
index 0000000..30cb497
--- /dev/null
+++ b/scripts/mpd.secret.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2003-2015 The Music Player Daemon Project
+# http://www.musicpd.org
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 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 General Public License for more details.
+#
+# You should have received a copy of the GNU 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.
+#
+
+
+import getpass
+from gi.repository import Secret
+
+
+mpd_schema_attributes =\
+    { "server"    : Secret.SchemaAttributeType.STRING
+    , "share"     : Secret.SchemaAttributeType.STRING
+    , "workgroup" : Secret.SchemaAttributeType.STRING
+    , "username"  : Secret.SchemaAttributeType.STRING
+    }
+
+mpd_schema = Secret.Schema.new\
+    ( "org.mpd.smbclient.password"
+    , Secret.SchemaFlags.NONE
+    , mpd_schema_attributes
+    )
+
+mpd_default_input_data =\
+    { "collection"  : { "default": "MusicPD" }
+    , "password"    : { "secret": True }
+    , "server"      : { }
+    , "share"       : { }
+    , "workgroup"   : { "default": "WORKGROUP" }
+    , "username"    : { }
+    }
+
+
+def mpd_prompt(prompt, default=None, secret=False):
+    if default is None:
+        prompt = "{}: ".format(prompt) 
+    else:
+        prompt = "{} [{}]: ".format(prompt, default)
+    string = ""
+    while not string:
+        if secret:
+            string = getpass.getpass(prompt)
+        else:
+            string = input(prompt)
+        if not string and default is not None:
+            string = default
+            break
+    return string
+
+def mpd_main():
+    input_data = mpd_input(mpd_default_input_data)
+    mpd_collection_ensure(input_data["collection"])
+    mpd_password_store(input_data)
+
+def mpd_input(input_data_arguments):
+    input_data = {}
+    print("<Enter> for default values (in parentheses)")
+    for attribute, arguments in sorted(input_data_arguments.items()):
+        input_data[attribute] = mpd_prompt(attribute, **arguments)
+    return input_data
+
+def mpd_collection_ensure(label):
+    service = Secret.Service.get_sync(Secret.ServiceFlags.LOAD_COLLECTIONS)
+    collections = Secret.Service.get_collections(service)
+    labels = [collection.get_label() for collection in collections]
+
+    if label not in labels:
+        Secret.Collection.create_sync\
+            ( service
+            , label
+            , None
+            , Secret.CollectionCreateFlags.COLLECTION_CREATE_NONE
+            , None
+            )
+
+def mpd_input_to_attributes(d):
+    return {k:v for k,v in d.items() if k in mpd_schema_attributes}
+
+def mpd_input_get_collection_path(input_data):
+    return "/org/freedesktop/secrets/collection/{}".format(input_data["collection"])
+
+def mpd_input_get_password_label(input_data):
+    return "Smbclient Password: {}".format(input_data["server"])
+
+def mpd_password_store(input_data):
+    Secret.password_store_sync\
+        ( mpd_schema
+        , mpd_input_to_attributes(input_data)
+        , mpd_input_get_collection_path(input_data)
+        , mpd_input_get_password_label(input_data)
+        , input_data["password"]
+        , None
+        )
+
+if __name__ == "__main__":
+    mpd_main()
diff --git a/src/config/ConfigOption.hxx b/src/config/ConfigOption.hxx
index 5acd6fd..8d11a3f 100644
--- a/src/config/ConfigOption.hxx
+++ b/src/config/ConfigOption.hxx
@@ -90,6 +90,7 @@ enum class ConfigBlockOption {
 	AUDIO_FILTER,
 	DATABASE,
 	NEIGHBORS,
+    BACKEND,
 	MAX
 };
 
diff --git a/src/config/ConfigTemplates.cxx b/src/config/ConfigTemplates.cxx
index 6fbf025..d283e29 100644
--- a/src/config/ConfigTemplates.cxx
+++ b/src/config/ConfigTemplates.cxx
@@ -90,6 +90,7 @@ const ConfigTemplate config_block_templates[] = {
 	{ "filter", true },
 	{ "database", false },
 	{ "neighbors", true },
+    { "backend", "true" },
 };
 
 static constexpr unsigned n_config_block_templates =
diff --git a/src/lib/smbclient/Init.cxx b/src/lib/smbclient/Init.cxx
index 999e60f..991d02d 100644
--- a/src/lib/smbclient/Init.cxx
+++ b/src/lib/smbclient/Init.cxx
@@ -22,22 +22,146 @@
 #include "Mutex.hxx"
 #include "thread/Mutex.hxx"
 #include "util/Error.hxx"
+#include "config/ConfigGlobal.hxx"
 
 #include <libsmbclient.h>
 
 #include <string.h>
 
-static void
-mpd_smbc_get_auth_data(gcc_unused const char *srv,
-		       gcc_unused const char *shr,
-		       char *wg, gcc_unused int wglen,
-		       char *un, gcc_unused int unlen,
-		       char *pw, gcc_unused int pwlen)
+
+#ifdef ENABLE_LIBSECRET
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+const SecretSchema mpd_schema =
+    { "org.mpd.smbclient.password"
+    , SECRET_SCHEMA_NONE
+    , { { "server"
+        , SECRET_SCHEMA_ATTRIBUTE_STRING
+        }
+      , { "share"
+        , SECRET_SCHEMA_ATTRIBUTE_STRING
+        }
+      , { "workgroup"
+        , SECRET_SCHEMA_ATTRIBUTE_STRING
+        }
+      , { "username"
+        , SECRET_SCHEMA_ATTRIBUTE_STRING
+        }
+      , { "NULL"
+        , (SecretSchemaAttributeType)0
+        }
+      }
+    };
+#pragma GCC diagnostic pop
+#endif
+
+#ifdef ENABLE_LIBSECRET
+const char*
+mpd_smbc_get_auth_data_secret
+    ( SmbAuthData* smb_auth_data
+    )
 {
-	// TODO: implement
-	strcpy(wg, "WORKGROUP");
-	strcpy(un, "");
-	strcpy(pw, "");
+    GError *error = NULL;
+
+    // When to free?
+    const char* password = (const char*)secret_password_lookup_sync
+        ( &mpd_schema , NULL , &error
+        , "server", smb_auth_data->server
+        , "share", smb_auth_data->share
+        , "workgroup", smb_auth_data->workgroup
+        , "username", smb_auth_data->username
+        , NULL
+        );
+
+    if (error != NULL) {
+        g_error_free(error);
+        return "";
+    }
+
+    if (password == NULL) {
+        return "";
+    }
+
+    return password;
+}
+#endif
+
+const char*
+mpd_smbc_get_auth_data_password
+    ( SmbAuthData* smb_auth_data
+    , const ConfigBlock* block
+    )
+{   const char* password_backend = block->GetBlockValue("password_backend", "config");
+
+    if (strcmp(password_backend, "config") == 0) {
+        return block->GetBlockValue("password", "");
+    }
+#ifdef ENABLE_LIBSECRET
+    if (strcmp(password_backend, "libsecret") == 0)
+        return mpd_smbc_get_auth_data_secret(smb_auth_data);
+#endif
+    return "";
+}
+
+SmbAuthData
+mpd_smbc_get_auth_data_default()
+{   return { .server    = ""
+           , .share     = ""
+           , .workgroup = "WORKGROUP"
+           , .username  = ""
+           , .password  = ""
+           };
+}
+
+void
+mpd_smbc_get_auth_data_config
+    ( SmbAuthData* smb_auth_data
+    )
+{   const ConfigBlock* block = config_get_block(ConfigBlockOption::BACKEND);
+
+    if (block == nullptr)
+        return;
+
+    const char* backend_name = block->GetBlockValue("name", "");
+
+    if (strcmp(backend_name, "smbclient") != 0)
+        return;
+
+    smb_auth_data->workgroup = block->GetBlockValue("workgroup", "WORKGROUP");
+    smb_auth_data->username = block->GetBlockValue("username", "");
+    smb_auth_data->password = mpd_smbc_get_auth_data_password(smb_auth_data, block);
+}
+
+void
+mpd_smbc_set_auth_data
+    ( char* destination
+    , const char* source
+    , size_t num
+    )
+{   size_t source_len = strlen(source) + 1;
+    memcpy(destination, source, std::min(source_len, num));
+    if (source_len > num)
+        destination[num] = '\0';
+}
+
+void
+mpd_smbc_get_auth_data
+    ( const char* server
+    , const char* share
+    , char* workgroup,  int workgrouplen
+    , char* username,   int usernamelen
+    , char* password,   int passwordlen
+    )
+{   SmbAuthData smb_auth_data;
+
+    smb_auth_data = mpd_smbc_get_auth_data_default();
+    smb_auth_data.server = server;
+    smb_auth_data.share = share;
+    mpd_smbc_get_auth_data_config(&smb_auth_data);
+
+    mpd_smbc_set_auth_data(workgroup, smb_auth_data.workgroup, workgrouplen);
+    mpd_smbc_set_auth_data(username, smb_auth_data.username, usernamelen);
+    mpd_smbc_set_auth_data(password, smb_auth_data.password, passwordlen);
 }
 
 bool
diff --git a/src/lib/smbclient/Init.hxx b/src/lib/smbclient/Init.hxx
index 1ccaec0..7f1994a 100644
--- a/src/lib/smbclient/Init.hxx
+++ b/src/lib/smbclient/Init.hxx
@@ -22,12 +22,71 @@
 
 #include "check.h"
 
+#include "config/Block.hxx"
+
+#ifdef ENABLE_LIBSECRET
+#include <libsecret/secret.h>
+#endif
+
+
 class Error;
 
-/**
+#ifdef ENABLE_LIBSECRET
+extern const SecretSchema mpd_schema;
+#endif
+
+struct SmbAuthData
+    { const char* server;
+      const char* share;
+      const char* workgroup;
+      const char* username;
+      const char* password;
+    };
+
+#ifdef ENABLE_LIBSECRET
+const char*
+mpd_smbc_get_auth_data_secret
+    ( SmbAuthData*
+    );
+#endif
+
+const char*
+mpd_smbc_get_auth_data_password
+    ( SmbAuthData*
+    , const ConfigBlock*
+    );
+  
+SmbAuthData
+mpd_smbc_get_auth_data_default
+    ();
+
+void
+mpd_smbc_get_auth_data_config
+    ( SmbAuthData*
+    );
+
+void
+mpd_smbc_set_auth_data
+    ( char*
+    , const char*
+    , size_t
+    );
+
+void
+mpd_smbc_get_auth_data
+    ( const char*
+    , const char*
+    , char*, int
+    , char*, int
+    , char*, int
+    );
+
+/*
  * Initialize libsmbclient.
  */
 bool
-SmbclientInit(Error &error);
+SmbclientInit
+    (Error&
+    );
 
 #endif
-- 
2.1.4

_______________________________________________
mpd-devel mailing list
[email protected]
http://mailman.blarg.de/listinfo/mpd-devel

Reply via email to