Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:mia
mpd
mpd-ldap+ptsave.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File mpd-ldap+ptsave.patch of Package mpd
diff -ru mpd-0.23.10.orig/meson.build mpd-0.23.10/meson.build --- mpd-0.23.10.orig/meson.build 2022-10-14 23:51:41.000000000 +0200 +++ mpd-0.23.10/meson.build 2022-11-05 00:18:13.016745326 +0100 @@ -534,6 +534,11 @@ target_name = 'mpd' endif +ldap_deps = [ + c_compiler.find_library('ldap'), + c_compiler.find_library('lber'), +] + mpd = build_target( target_name, sources, @@ -565,6 +570,7 @@ more_deps, chromaprint_dep, fmt_dep, + ldap_deps, ], link_args: link_args, build_by_default: not get_option('fuzzer'), diff -ru mpd-0.23.10.orig/src/command/PartitionCommands.cxx mpd-0.23.10/src/command/PartitionCommands.cxx --- mpd-0.23.10.orig/src/command/PartitionCommands.cxx 2022-10-14 23:51:41.000000000 +0200 +++ mpd-0.23.10/src/command/PartitionCommands.cxx 2022-11-05 00:18:13.016745326 +0100 @@ -100,13 +100,14 @@ return CommandResult::ERROR; } - instance.partitions.emplace_back(instance, name, - // TODO: use real configuration - 16384, - 1024, - AudioFormat::Undefined(), - ReplayGainConfig()); - auto &partition = instance.partitions.back(); +// instance.partitions.emplace_back(instance, name, +// TODO: use real configuration +// 16384, +// 1024, +// AudioFormat::Undefined(), +// ReplayGainConfig()); +// auto &partition = instance.partitions.back(); + auto &partition = instance.NewPartition(name, true); partition.UpdateEffectiveReplayGainMode(); instance.EmitIdle(IDLE_PARTITION); diff -ru mpd-0.23.10.orig/src/config/Option.hxx mpd-0.23.10/src/config/Option.hxx --- mpd-0.23.10.orig/src/config/Option.hxx 2022-10-14 23:51:41.000000000 +0200 +++ mpd-0.23.10/src/config/Option.hxx 2022-11-05 00:18:13.017745347 +0100 @@ -80,6 +80,12 @@ DESPOTIFY_USER, DESPOTIFY_PASSWORD, DESPOTIFY_HIGH_BITRATE, + LDAP_BIND_URI, + LDAP_BIND_DN, + LDAP_BIND_PW, + LDAP_BIND_METH, + LDAP_Q_BASE, + LDAP_Q_SCOPE, MAX }; diff -ru mpd-0.23.10.orig/src/config/Templates.cxx mpd-0.23.10/src/config/Templates.cxx --- mpd-0.23.10.orig/src/config/Templates.cxx 2022-10-14 23:51:41.000000000 +0200 +++ mpd-0.23.10/src/config/Templates.cxx 2022-11-05 00:18:13.017745347 +0100 @@ -76,6 +76,12 @@ { "despotify_user", false, true }, { "despotify_password", false, true }, { "despotify_high_bitrate", false, true }, + { "ldap_bind_uri" }, + { "ldap_bind_dn" }, + { "ldap_bind_pw" }, + { "ldap_bind_meth" }, + { "ldap_q_base" }, + { "ldap_q_scope" }, }; static constexpr unsigned n_config_param_templates = diff -ru mpd-0.23.10.orig/src/Instance.cxx mpd-0.23.10/src/Instance.cxx --- mpd-0.23.10.orig/src/Instance.cxx 2022-10-14 23:51:41.000000000 +0200 +++ mpd-0.23.10/src/Instance.cxx 2022-11-05 00:18:13.017745347 +0100 @@ -77,8 +77,8 @@ void Instance::OnStateModified() noexcept { - if (state_file) - state_file->CheckModified(); + for (auto& f : state_files) + f->CheckModified(); } Partition * diff -ru mpd-0.23.10.orig/src/Instance.hxx mpd-0.23.10/src/Instance.hxx --- mpd-0.23.10.orig/src/Instance.hxx 2022-10-14 23:51:41.000000000 +0200 +++ mpd-0.23.10/src/Instance.hxx 2022-11-05 00:18:13.017745347 +0100 @@ -52,7 +52,7 @@ #include <list> class ClientList; -struct Partition; +#include "Partition.hxx" class StateFile; class RemoteTagCache; class StickerDatabase; @@ -137,7 +137,8 @@ std::list<Partition> partitions; - std::unique_ptr<StateFile> state_file; +// std::unique_ptr<StateFile> state_file; + std::list<StateFile*> state_files; #ifdef ENABLE_SQLITE std::unique_ptr<StickerDatabase> sticker_database; @@ -170,6 +171,8 @@ */ void OnStateModified() noexcept; + Partition::Factory NewPartition; + /** * Find a #Partition with the given name. Returns nullptr if * no such partition was found. diff -ru mpd-0.23.10.orig/src/Main.cxx mpd-0.23.10/src/Main.cxx --- mpd-0.23.10.orig/src/Main.cxx 2022-10-14 23:51:41.000000000 +0200 +++ mpd-0.23.10/src/Main.cxx 2022-11-05 00:18:13.017745347 +0100 @@ -273,10 +273,163 @@ } #endif +#include <fstream> +#include <type_traits> +namespace typelist { + template <size_t bits, bool sign> struct integral_c {}; + template <size_t bits, bool sign> using integral = typename integral_c<bits,sign>::ty; + + template<> struct integral_c<8, false> { using ty = uint8_t; }; + template<> struct integral_c<16, false> { using ty = uint16_t; }; + template<> struct integral_c<32, false> { using ty = uint32_t; }; + template<> struct integral_c<64, false> { using ty = uint64_t; }; + + template<size_t bits> struct integral_c<bits, true> { + using ty = std::make_signed_t<integral<bits,false> >; + }; +} +template <typename word> struct srz { srz() = delete; + using To = std::basic_ostream<word>; + using Ti = std::basic_istream<word>; + + template <size_t bits, bool sign> + using isz = typelist::integral<bits,sign>; + + /* core mechanism */ + template <size_t bits, bool sign, typename T> static + void out_i(To& o, const T val) { + using V = isz<bits, sign>; + static_assert(sizeof(T) >= sizeof(V), + "val is not big enough to hold a value of the specified bit length"); + static_assert(std::is_signed_v<T> == sign, + "val does not match the requested sign"); + + if constexpr (bits == sizeof(word)*8) { + o.put((word)val); + } else { + using H = isz<bits/2, sign>; + isz<bits,false> raw; raw = (decltype(raw)) val; + out_i<bits/2, sign, H>(o, raw & (( (V)1 << (bits/2)) - 1)); + out_i<bits/2, sign, H>(o, raw >> (bits/2)); + } + } + + template <size_t bits, bool sign, typename T> static + void in_i(Ti& i, T& val) { + using V = isz<bits, sign>; + static_assert(sizeof(T) >= sizeof(V), + "val is not big enough to hold a value of the specified bit length"); + static_assert(std::is_signed_v<T> == sign, + "val does not match the requested sign"); + + if constexpr (bits == sizeof(word)*8) { + word w; i.get(w); + val = (V)w; + } else { + using H = isz<bits/2, sign>; + H low, high; + in_i<bits/2,sign,H> (i, low); + in_i<bits/2,sign,H> (i, high); + V tmp = (V)low | ((V)high << (bits/2)); + val = tmp; + } + } + + /* strings */ + static void + out(To&o, const char* const str, size_t len = 0) { + if (len==0) len = strlen(str); + out(o, len); + for (size_t i = 0; i < len; ++i) { + out(o, (uint8_t)(str[i])); + } + } + + static void + out(To&o, const std::string& str) { + out(o, str.c_str(), str.size()); + } + + static std::string in_s(Ti&i) { + size_t len; in(i,len); + char buf[len]; + i.read(buf, len); + return std::string(buf, len); + } + + static void in(Ti&i, std::string& str) { str = in_s(i); } + + /* numerics */ + template<typename T, std::enable_if_t<std::is_integral_v<T>,bool> = true> static + void out(To&o, const T& v) { + out_i<sizeof(T)*8, std::is_signed_v<T> > (o, v); + } + template<typename T, std::enable_if_t<std::is_integral_v<T>,bool> = true> static + void in(Ti&i, T& v) { + in_i<sizeof(T)*8, std::is_signed_v<T> > (i, v); + } + + /* std::list */ + template<typename T> static + void out(To&o, const std::list<T>& l) { + out(o, l.size()); + for (const T& r : l) out(o, r); + } + + template<typename T> static + void in(Ti&i, std::list<T>& l) { + size_t len; in(i, len); + for (size_t j = 0; j < len; ++j) { + T n; in(i, n); + l.push_back(n); + } + + } + + /* tuples */ + template<typename T, size_t N, size_t ofs = 0> static + void out(To&o, T const (&r)[N]) { + out(o, r[ofs]); + if constexpr (ofs+1 < N) { + out<T,N,ofs + 1> (o,r); + } + } + + template<typename T, size_t N, size_t ofs = 0> static + void in(Ti&i, T (&r)[N]) { + in(i, r[ofs]); + if constexpr (ofs+1 < N) { + in<T,N,ofs + 1> (i,r); + } + } +}; +static void +glue_partitions_init(Instance& instance, const ConfigData &raw_config) { + auto plpath = raw_config.GetPath(ConfigOption::STATE_FILE); + std::ifstream statefile(plpath.c_str()); + + if (!statefile) { + return; /* default is already present */ + } else { + uint16_t nparts; + using S = srz<char>; + S::in(statefile, nparts); + for (size_t i = 0; i < nparts; ++ i) { + size_t chlen; + S::in(statefile, chlen); +// char pname [chlen+1]; + char* pname = (char*)alloca(chlen+1); + statefile.read(pname, chlen); + pname[chlen] = 0; + instance.NewPartition(pname); + } + } +} static void glue_state_file_init(Instance &instance, const ConfigData &raw_config) { +#if 0 StateFileConfig config(raw_config); if (!config.IsEnabled()) return; @@ -285,6 +438,20 @@ instance.partitions.front(), instance.event_loop); instance.state_file->Read(); +#endif + for (auto& p : instance.partitions) { + StateFileConfig config(raw_config); + if (!config.IsEnabled()) + return; + +// std::string path = config.path.Steal(); +// path = path + ".p/" + p.name; +// config.path = Path::FromFS(path.c_str()); + + instance.state_files.push_back(new StateFile( + std::move(config), p, instance.event_loop)); + instance.state_files.back()->Read(); + } } /** @@ -334,19 +501,30 @@ return ParseAudioFormat(s, true); }); - instance.partitions.emplace_back(instance, - "default", - max_length, - buffered_chunks, - configured_audio_format, - replay_gain_config); - auto &partition = instance.partitions.back(); - partition.replay_gain_mode = config.With(ConfigOption::REPLAYGAIN, [](const char *s){ + /* set up partition configurator */ + auto& np = instance.NewPartition; + np.instance = &instance; + np.max_length = max_length; + np.buffer_chunks = buffered_chunks; + np.configured_audio_format = configured_audio_format; + np.raw_config = &config; + np.replay_gain_config = &replay_gain_config; + np.replay_gain_mode = config.With(ConfigOption::REPLAYGAIN, [](const char *s){ return s != nullptr ? FromString(s) : ReplayGainMode::OFF; }); + +// instance.partitions.emplace_back(instance, +// "default", +// max_length, +// buffered_chunks, +// configured_audio_format, +// replay_gain_config); +// auto &partition = instance.partitions.back(); + /* auto &partition = */ instance.NewPartition("default"); + np.configured_audio_format = AudioFormat::Undefined(); } inline void @@ -461,12 +639,15 @@ command_init(); + glue_partitions_init(instance, raw_config); + for (auto &partition : instance.partitions) { partition.outputs.Configure(instance.io_thread.GetEventLoop(), instance.rtio_thread.GetEventLoop(), raw_config, config.replay_gain); partition.UpdateEffectiveReplayGainMode(); + /*HACK*/ break; } client_manager_init(raw_config); @@ -581,8 +762,22 @@ /* cleanup */ - if (instance.state_file) - instance.state_file->Write(); + auto plpath = raw_config.GetPath(ConfigOption::STATE_FILE); + {std::ofstream plist(plpath.c_str()); + if (!!plist) { + using S = srz<char>; +// plist << instance.partitions.size() - 1; + S::out(plist, (uint16_t)(instance.partitions.size() - 1)); + for (auto& p : instance.partitions) { + if (&p == &instance.partitions.front()) continue; + S::out(plist, p.name); + } + }} + + for (auto f : instance.state_files) { + f->Write(); + delete f; + } instance.BeginShutdownUpdate(); instance.BeginShutdownPartitions(); diff -ru mpd-0.23.10.orig/src/Partition.cxx mpd-0.23.10/src/Partition.cxx --- mpd-0.23.10.orig/src/Partition.cxx 2022-10-14 23:51:41.000000000 +0200 +++ mpd-0.23.10/src/Partition.cxx 2022-11-05 00:18:13.017745347 +0100 @@ -29,7 +29,29 @@ #include "input/cache/Manager.hxx" #include "util/Domain.hxx" +#include "StateFile.hxx" +#include "StateFileConfig.hxx" + static constexpr Domain cache_domain("cache"); +Partition& +Partition::Factory::operator() (const char* name, bool createStateFile) { + instance->partitions.emplace_back( + *instance, name, max_length, buffer_chunks, + configured_audio_format, *replay_gain_config + ); + auto& p = instance->partitions.back(); /* christ */ + p.replay_gain_mode = replay_gain_mode; + + if (createStateFile) { + StateFileConfig config(*raw_config); + if (!config.IsEnabled()) + return p; + + instance->state_files.push_back(new StateFile( + std::move(config), p, instance->event_loop)); + } + return p; +} Partition::Partition(Instance &_instance, const char *_name, Only in mpd-0.23.10/src: Partition.cxx.orig diff -ru mpd-0.23.10.orig/src/Partition.hxx mpd-0.23.10/src/Partition.hxx --- mpd-0.23.10.orig/src/Partition.hxx 2022-10-14 23:51:41.000000000 +0200 +++ mpd-0.23.10/src/Partition.hxx 2022-11-05 00:18:13.017745347 +0100 @@ -272,6 +272,18 @@ * if it was one-shot. */ void BorderPause() noexcept; + struct Factory { + /* default values -- loaded from config in main.cxx */ + Instance* instance; + unsigned max_length; + unsigned buffer_chunks; + AudioFormat configured_audio_format; + const ReplayGainConfig* replay_gain_config; + const ConfigData* raw_config; + ReplayGainMode replay_gain_mode; + + Partition& operator()(const char* name, bool createStateFile = false); + }; private: /* virtual methods from class QueueListener */ Only in mpd-0.23.10/src: Partition.hxx.orig diff -ru mpd-0.23.10.orig/src/Permission.cxx mpd-0.23.10/src/Permission.cxx --- mpd-0.23.10.orig/src/Permission.cxx 2022-10-14 23:51:41.000000000 +0200 +++ mpd-0.23.10/src/Permission.cxx 2022-11-05 00:18:13.017745347 +0100 @@ -50,6 +50,16 @@ }; static std::map<std::string, unsigned> permission_passwords; +static struct LDAPDirectory { + const char + * uri, + * dn, + * pw, + * authmeth, + * base, + * scope; +} directory; + static unsigned permission_default; @@ -141,6 +151,18 @@ }); } #endif + + auto getp = [&](ConfigOption c) -> const char* { + const ConfigParam* cp = config.GetParam(c); + if (cp == nullptr) return nullptr; + return cp->value.c_str(); + }; + directory.uri = getp(ConfigOption::LDAP_BIND_URI); + directory.dn = getp(ConfigOption::LDAP_BIND_DN); + directory.pw = getp(ConfigOption::LDAP_BIND_PW); + directory.authmeth= getp(ConfigOption::LDAP_BIND_METH); + directory.base = getp(ConfigOption::LDAP_Q_BASE); + directory.scope = getp(ConfigOption::LDAP_Q_SCOPE); } #ifdef HAVE_TCP @@ -157,12 +179,131 @@ #endif +namespace ldap { extern "C" { +# include <ldap.h> + char** ldap_get_values (LDAP*, LDAPMessage*, char*); + int ldap_count_values (char**); + void ldap_value_free (char**); + int ldap_unbind_s (LDAP*); + int ldap_simple_bind_s(LDAP*, const char*, const char*); +}} + +static ldap::LDAP* +openLDAPConnection() { + using namespace ldap; + LDAP* ctx; + ldap_initialize(&ctx, directory.uri); + {int v=3; ldap_set_option(ctx, LDAP_OPT_PROTOCOL_VERSION, &v);} + int res; + if (directory.authmeth == nullptr) { + res = ldap_simple_bind_s(ctx, directory.dn, directory.pw); + } else { + res = ldap_sasl_interactive_bind_s(ctx, directory.dn, directory.authmeth, nullptr, nullptr, LDAP_SASL_QUIET, nullptr, nullptr); + } + if (res != 0) { + ldap_unbind_s(ctx); + throw std::runtime_error(ldap_err2string(res)); + // return nullptr; + } + + return ctx; +} + +static int +getPermissionFromLDAPLookup(const char* password, unsigned* permission) { + using namespace ldap; + typedef char const* str; + + LDAP* l = openLDAPConnection(); + if (l == nullptr) return -1; + + str const filter = "(&(preSharedKey=*)(authorizedService=music*))"; + str const attrs[] = { + "authorizedService", + "preSharedKey", + // "cn", + // "aRecord", + // "aAAARecord", + // "associatedDomain", + nullptr, + }; + + LDAPMessage* m; + int e = ldap_search_ext_s(l, directory.base, LDAP_SCOPE_SUBTREE, filter, const_cast<char**>(attrs), + /* attrs only*/ 0, + /*server controls*/ nullptr, + /*client controls*/ nullptr, + /* timeout*/ nullptr, + /* sizelimit*/ 0, &m); + + bool found = false; + + if (e != LDAP_SUCCESS) { + throw std::runtime_error(ldap_err2string(e)); + //goto fail; + } + + int permset = 0; + for (LDAPMessage* ent = ldap_first_entry(l, m); ent != nullptr; + ent = ldap_next_entry(l, ent)) { + char* dn = ldap_get_dn(l, ent); + char** keys = ldap_get_values(l, ent, const_cast<char*>("preSharedKey")); + char** svcs = ldap_get_values(l, ent, const_cast<char*>("authorizedService")); + + size_t nkeys = ldap_count_values(keys); + size_t nsvcs = ldap_count_values(svcs); + + bool keyMatch = false; + for (size_t i = 0; i < nkeys; ++i) { + if (strcmp(password, keys[i]) == 0) { + keyMatch = true; + break; + } + } + + if (keyMatch) for (size_t i = 0; i < nsvcs; ++i) { + auto svc = svcs[i]; + if (strncmp(svc, "music", 5) == 0) { + if (svc[5] == 0) /* all privileges */ { + found = true; + permset |= (unsigned)-1; + } else if(svc[5] == '=') /* defined privs */ { + found = true; + char* priv = svc + 6, *s; + for (char* p = strtok_r(priv, ",", &s); p != nullptr; + p = strtok_r(nullptr, ",", &s)) { + permset |= ParsePermission(p); + } + } + } + } + + ldap_value_free(keys); + ldap_value_free(svcs); + + ldap_memfree(dn); + if (found) break; + } + + if(found) { + *permission = permset; + } + + /*fail:*/ ldap_msgfree(m); + ldap_unbind_s(l); + return found ? 0 : -1; +} + std::optional<unsigned> GetPermissionFromPassword(const char *password) noexcept { auto i = permission_passwords.find(password); - if (i == permission_passwords.end()) - return std::nullopt; + if (i == permission_passwords.end()) { + unsigned perm; + if (getPermissionFromLDAPLookup(password, &perm) != 0) + return std::nullopt; + return perm; + } return i->second; } diff -ru mpd-0.23.10.orig/src/StateFile.cxx mpd-0.23.10/src/StateFile.cxx --- mpd-0.23.10.orig/src/StateFile.cxx 2022-10-14 23:51:41.000000000 +0200 +++ mpd-0.23.10/src/StateFile.cxx 2022-11-05 00:18:13.017745347 +0100 @@ -96,7 +96,10 @@ "Saving state file {}", path_utf8); try { - FileOutputStream fos(config.path); + std::string cpath (path_utf8); + cpath += ".p/"; + cpath += partition.name; + FileOutputStream fos(Path::FromFS(cpath.c_str())); Write(fos); fos.Commit(); } catch (...) { @@ -113,7 +116,10 @@ FmtDebug(state_file_domain, "Loading state file {}", path_utf8); - TextFile file(config.path); + std::string cpath (path_utf8); + cpath += ".p/"; + cpath += partition.name; + TextFile file(Path::FromFS(cpath.c_str())); #ifdef ENABLE_DATABASE const SongLoader song_loader(partition.instance.GetDatabase(), Only in mpd-0.23.10/src: StateFile.cxx.orig
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor