From 93c8b49f617853cd96d0aaf083675e767a9f7a41 Mon Sep 17 00:00:00 2001 From: eelke Date: Mon, 24 Dec 2018 07:51:27 +0100 Subject: [PATCH] PgServerObject now contains a list of acl's for the object so all the different objects can use this implementation. --- pglab/ProcTableModel.cpp | 2 +- pglablib/SqlFormattingUtils.cpp | 21 --- pglablib/catalog/PgProc.h | 12 -- pglablib/catalog/PgProcContainer.cpp | 6 +- pglablib/catalog/PgServerObject.cpp | 209 +++++++++++++++++++++++++++ pglablib/catalog/PgServerObject.h | 70 +++++++++ 6 files changed, 284 insertions(+), 36 deletions(-) diff --git a/pglab/ProcTableModel.cpp b/pglab/ProcTableModel.cpp index ba8c5aa..377e55e 100644 --- a/pglab/ProcTableModel.cpp +++ b/pglab/ProcTableModel.cpp @@ -87,7 +87,7 @@ QVariant ProcTableModel::getData(const QModelIndex &index) const if (lan) return lan->objectName(); return t.lang; } - case AclCol: return t.acl; + case AclCol: return t.aclString(); } return QVariant(); } diff --git a/pglablib/SqlFormattingUtils.cpp b/pglablib/SqlFormattingUtils.cpp index 0429e13..5df940c 100644 --- a/pglablib/SqlFormattingUtils.cpp +++ b/pglablib/SqlFormattingUtils.cpp @@ -410,24 +410,3 @@ QString getConstraintDefinition(const PgDatabaseCatalog &catalog, const PgConstr return result; } - -//rolename=xxxx -- privileges granted to a role -// =xxxx -- privileges granted to PUBLIC - -// r -- SELECT ("read") -// w -- UPDATE ("write") -// a -- INSERT ("append") -// d -- DELETE -// D -- TRUNCATE -// x -- REFERENCES -// t -- TRIGGER -// X -- EXECUTE -// U -- USAGE -// C -- CREATE -// c -- CONNECT -// T -- TEMPORARY -// arwdDxt -- ALL PRIVILEGES (for tables, varies for other objects) -// * -- grant option for preceding privilege - -// /yyyy -- role that granted this privilege - diff --git a/pglablib/catalog/PgProc.h b/pglablib/catalog/PgProc.h index 88c24d5..040c0e7 100644 --- a/pglablib/catalog/PgProc.h +++ b/pglablib/catalog/PgProc.h @@ -56,17 +56,11 @@ class PgProc: public PgNamespaceObject, public PgOwnedObject { public: using PgNamespaceObject::PgNamespaceObject; -// Oid oid = InvalidOid; // oid -// QString name; // name -// Oid pronamespace = InvalidOid; // oid, namespace -// Oid owner = InvalidOid; // oid Oid lang = InvalidOid; // oid float cost = 0.f; // float4 float rows = 0.f; // float4 Oid variadic = InvalidOid; // oid QString transform; // regproc -// bool isagg = false; // bool < 11 -// bool iswindow = false; // bool << 11 ProcKind kind = ProcKind::Function; // >= 11 bool secdef = false; // bool bool leakproof = false; // bool @@ -81,7 +75,6 @@ public: QString src; // text QString bin; // text std::vector config; // text[] - QString acl; // aclitem[] /// Converts the collection of arrays about the arguments to a single list of arguments /// making it much easier to work with them correctly @@ -94,11 +87,6 @@ public: ); const std::vector& args() const; -// bool operator==(Oid _oid) const { return oid == _oid; } -// bool operator==(const QString &n) const { return name == n; } -// bool operator<(Oid _oid) const { return oid < _oid; } -// bool operator<(const PgProc &rhs) const { return oid < rhs.oid; } - const QString& createSql() const; QString argListWithNames(bool multiline = false) const; QString argSigList(const bool forScript = false) const; diff --git a/pglablib/catalog/PgProcContainer.cpp b/pglablib/catalog/PgProcContainer.cpp index b3ef874..e328774 100644 --- a/pglablib/catalog/PgProcContainer.cpp +++ b/pglablib/catalog/PgProcContainer.cpp @@ -49,8 +49,10 @@ PgProc PgProcContainer::loadElem(const Pgsql::Row &row) std::optional argdefaults; // pg_node_tree col.getAsVector(std::back_inserter(argtypes)); col >> allargtypes >> argmodes >> argnames >> argdefaults - >> v.src >> v.bin >> v.config >> v.acl; - + >> v.src >> v.bin >> v.config; // >> v.acl; + AclList acl_list; + col >> acl_list; + v.setAcls(std::move(acl_list)); v.setArgs(argtypes, allargtypes, argmodes, argnames, argdefaults); if (minimumVersion(90500)) { diff --git a/pglablib/catalog/PgServerObject.cpp b/pglablib/catalog/PgServerObject.cpp index b03bc4e..daa159c 100644 --- a/pglablib/catalog/PgServerObject.cpp +++ b/pglablib/catalog/PgServerObject.cpp @@ -1,2 +1,211 @@ #include "PgServerObject.h" +#include "ArrayParser.h" +#include + +namespace { + + QString privilegeLetterToKeyword(char c) + { + switch (c) { + case 'r': return "SELECT"; + case 'w': return "UPDATE"; + case 'a': return "INSERT"; + case 'd': return "DELETE"; + case 'D': return "TRUNCATE"; + case 'x': return "REFERENCES"; + case 't': return "TRIGGER"; + case 'X': return "EXECUTE"; + case 'U': return "USAGE"; + case 'C': return "CREATE"; + case 'c': return "CONNECT"; + case 'T': return "TEMPORARY"; + } + throw std::runtime_error("Unexpected value for c in privilegeLetterToKeyword"); + } + +} + +char privilegeToChar(Privilege p) +{ + switch (p) { + case Privilege::Select: return 'r'; + case Privilege::Update: return 'w'; + case Privilege::Insert: return 'a'; + case Privilege::Delete: return 'd'; + case Privilege::Truncate: return 'D'; + case Privilege::References: return 'x'; + case Privilege::Trigger: return 't'; + case Privilege::Execute: return 'X'; + case Privilege::Usage: return 'U'; + case Privilege::Create: return 'C'; + case Privilege::Connect: return 'c'; + case Privilege::Temporary: return 'T'; + } + throw std::runtime_error("Unexpected value for privilege in privilegeToChar"); +} + +PgAcl::PgAcl(const QString &acl) +{ + setFromString(acl); +} + +void PgAcl::setFromString(const QString &acl) +{ + m_grantee = acl.section('=', 0, 0); + auto t = acl.section('=', 1); + m_privileges = t.section('/', 0, 0); + m_grantor = t.section('/', 1); +} + +PrivValue PgAcl::privilege(Privilege priv) const +{ + char c = privilegeToChar(priv); + return privilege(c); +} + +PrivValue PgAcl::privilege(char c) const +{ + int pos = m_privileges.indexOf(c); + if (pos >= 0) { + if ( (pos+1) < m_privileges.length() && m_privileges[pos+1] == '*') + return PrivValue::YesWithGrant; + return PrivValue::Yes; + } + return PrivValue::No; +} + +QString PgAcl::singleString() const +{ + return m_grantee % "=" % m_privileges % "/" % m_grantor; +} + +//void operator<<(AclList &s, const Pgsql::Value &v) +void operator<<(PgAcl &acl, const Pgsql::Value &v) +{ + acl.setFromString(v); +// const char *c = v.c_str(); +// Pgsql::ArrayParser parser(c); + +// while (true) { +// auto elem = parser.GetNextElem(); +// if (!elem.ok) +// break; +// auto&& v = elem.value.value_or(""); +// s.emplace_back(QString(v.data())); +// } +} + +namespace Pgsql { + template <> + PgAcl StringToArrayElem(std::string_view sv) + { + return PgAcl(QString::fromUtf8(sv.data(), static_cast(sv.length()))); + } +} + + +void PgServerObject::setAcls(AclList acls) +{ + m_acls = std::move(acls); +} + +QString PgServerObject::aclString() const +{ + QString result; + for (auto&& acl : m_acls) { + if (result.isEmpty()) result += "{"; + else result += ","; + result += acl.singleString(); + } + if (!result.isEmpty()) + result += "}"; + return result; +} + +QString PgServerObject::grantSql(const QString &all_pattern, const QString &grantee, const QString &column) const +{ + QString grant; +// wxString grant, str, user, grantFor, tmpUser; + +// if (_grantFor.IsNull()) +// { +// grantFor = GetTypeName(); +// grantFor.MakeUpper(); +// grantFor += wxT(" ") + GetQuotedFullIdentifier(); +// } +// else +// grantFor = _grantFor; + +// if (!acl.IsNull()) +// { +// if (acl == wxT("{}")) +// { +// grant += GetPrivileges(allPattern, str, grantFor, wxT("public"), qtIdent(_column)); +// grant += GetPrivileges(allPattern, str, grantFor, qtIdent(owner), qtIdent(_column)); +// } +// else +// { +// // checks if certain privilege is granted to public +// bool grantedToPublic = false; +// // checks if certain privilege is granted to owner +// bool grantedToOwner = false; + +// queryTokenizer acls(acl.Mid(1, acl.Length() - 2), ','); +// while (acls.HasMoreTokens()) +// { +// str = acls.GetNextToken(); + +// if (str.Left(1) == '"') +// str = str.Mid(1, str.Length() - 2); +// user = str.BeforeFirst('='); +// str = str.AfterFirst('=').BeforeFirst('/'); +// if (user == wxT("")) +// { +// user = wxT("public"); +// grantedToPublic = true; +// } +// else +// { +// if (user.Left(6) == wxT("group ")) +// { +// tmpUser = user.Mid(6); +// if (user.Mid(6).StartsWith(wxT("\\\"")) && user.Mid(6).EndsWith(wxT("\\\""))) +// user = wxT("GROUP ") + qtIdent(user.Mid(8, user.Length() - 10)); +// else +// user = wxT("GROUP ") + qtIdent(user.Mid(6)); +// } +// else +// { +// tmpUser = user; +// if (user.StartsWith(wxT("\\\"")) && user.EndsWith(wxT("\\\""))) +// user = qtIdent(user.Mid(2, user.Length() - 4)); +// else +// user = qtIdent(user); +// } + +// if (tmpUser.Contains(owner)) +// grantedToOwner = true; +// } + +// grant += GetPrivileges(allPattern, str, grantFor, user, qtIdent(_column)); +// } + +// str = wxEmptyString; +// int metaType = GetMetaType(); + +// // We check here that whether the user has revoked prvileges granted to databases, functions +// // and languages. If so then this must be part of reverse engineered sql statement +// if (!grantedToPublic && (metaType == PGM_LANGUAGE || metaType == PGM_FUNCTION || metaType == PGM_DATABASE)) +// grant += GetPrivileges(allPattern, str, grantFor, wxT("public"), qtIdent(_column)); +// // We check here that whether the owner has revoked prvileges on himself to this postgres +// // object. If so then this must be part of reverse engineered sql statement +// if (!grantedToOwner) +// grant += GetPrivileges(allPattern, str, grantFor, qtIdent(owner), qtIdent(_column)); +// } +// } + return grant; +} + + + diff --git a/pglablib/catalog/PgServerObject.h b/pglablib/catalog/PgServerObject.h index 5c703b6..3bc23f8 100644 --- a/pglablib/catalog/PgServerObject.h +++ b/pglablib/catalog/PgServerObject.h @@ -3,13 +3,83 @@ #include #include "PgObject.h" +#include "Pgsql_Value.h" +#include +enum class Privilege { + Select, + Update, + Insert, + Delete, + Truncate, + References, + Trigger, + Execute, + Usage, + Create, + Connect, + Temporary +}; + +char privilegeToChar(Privilege p); + +enum class PrivValue { + No, Yes, YesWithGrant +}; + +class PgAcl { +public: + PgAcl() = default; + explicit PgAcl(const QString &acl); + void setFromString(const QString &acl); + + PrivValue privilege(Privilege priv) const; + PrivValue privilege(char c) const; + const QString& grantee() const { return m_grantee; } + const QString& grantor() const { return m_grantor; } + QString singleString() const; +private: + QString m_grantee; + QString m_grantor; + QString m_privileges; +}; + +using AclList = std::vector; + +void operator<<(PgAcl &acl, const Pgsql::Value &v); + +namespace Pgsql { + template <> + PgAcl StringToArrayElem(std::string_view sv); +} + /// Base object for objects that belong to a server class PgServerObject: public PgObject { public: using PgObject::PgObject; + + + /** + * @brief setAcls Takes the acl array as stored by postgres as a single string + * and decodes it directly into an AclList. + * @param acls + * + */ + void setAcls(AclList acls); + QString aclString() const; + /** + * @brief grantSql + * @param all_pattern Used to recognize when a GRANT ALL can be generated but also to not consider irrelevant letters. + * @param grantee + * @param column + * @return + */ + QString grantSql(const QString &all_pattern, const QString &grantee, const QString &column) const; + +private: + AclList m_acls; }; #endif // PGSERVEROBJECT_H