libsecret.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. #if defined(HAVE_LIBSECRET)
  2. #include <libsecret/secret.h>
  3. #endif
  4. #include "libsecret_p.h"
  5. #include <QLibrary>
  6. #if defined(HAVE_LIBSECRET)
  7. const SecretSchema* qtkeychainSchema(void) {
  8. static const SecretSchema schema = {
  9. "org.qt.keychain", SECRET_SCHEMA_DONT_MATCH_NAME,
  10. {
  11. { "user", SECRET_SCHEMA_ATTRIBUTE_STRING },
  12. { "server", SECRET_SCHEMA_ATTRIBUTE_STRING },
  13. { "type", SECRET_SCHEMA_ATTRIBUTE_STRING }
  14. }
  15. };
  16. return &schema;
  17. }
  18. typedef struct {
  19. QKeychain::JobPrivate *self;
  20. QString user;
  21. QString server;
  22. } callbackArg;
  23. typedef void (*secret_password_lookup_t) (const SecretSchema *schema,
  24. GCancellable *cancellable,
  25. GAsyncReadyCallback callback,
  26. gpointer user_data,
  27. ...) G_GNUC_NULL_TERMINATED;
  28. typedef gchar *(*secret_password_lookup_finish_t) (GAsyncResult *result,
  29. GError **error);
  30. typedef void (*secret_password_store_t) (const SecretSchema *schema,
  31. const gchar *collection,
  32. const gchar *label,
  33. const gchar *password,
  34. GCancellable *cancellable,
  35. GAsyncReadyCallback callback,
  36. gpointer user_data,
  37. ...) G_GNUC_NULL_TERMINATED;
  38. typedef gboolean (*secret_password_store_finish_t) (GAsyncResult *result,
  39. GError **error);
  40. typedef void (*secret_password_clear_t) (const SecretSchema *schema,
  41. GCancellable *cancellable,
  42. GAsyncReadyCallback callback,
  43. gpointer user_data,
  44. ...) G_GNUC_NULL_TERMINATED;
  45. typedef gboolean (*secret_password_clear_finish_t) (GAsyncResult *result,
  46. GError **error);
  47. typedef void (*secret_password_free_t) (gchar *password);
  48. typedef GQuark (*secret_error_get_quark_t) (void) G_GNUC_CONST;
  49. static secret_password_lookup_t secret_password_lookup_fn = nullptr;
  50. static secret_password_lookup_finish_t secret_password_lookup_finish_fn = nullptr;
  51. static secret_password_store_t secret_password_store_fn = nullptr;
  52. static secret_password_store_finish_t secret_password_store_finish_fn = nullptr;
  53. static secret_password_clear_t secret_password_clear_fn = nullptr;
  54. static secret_password_clear_finish_t secret_password_clear_finish_fn = nullptr;
  55. static secret_password_free_t secret_password_free_fn = nullptr;
  56. static secret_error_get_quark_t secret_error_get_quark_fn = nullptr;
  57. static QKeychain::Error gerrorToCode(const GError *error) {
  58. if (error->domain != secret_error_get_quark_fn()) {
  59. return QKeychain::OtherError;
  60. }
  61. switch(error->code) {
  62. case SECRET_ERROR_NO_SUCH_OBJECT:
  63. return QKeychain::EntryNotFound;
  64. case SECRET_ERROR_IS_LOCKED:
  65. return QKeychain::AccessDenied;
  66. default:
  67. return QKeychain::OtherError;
  68. }
  69. }
  70. static void
  71. on_password_lookup (GObject *source,
  72. GAsyncResult *result,
  73. gpointer inst)
  74. {
  75. GError *error = nullptr;
  76. callbackArg *arg = (callbackArg*)inst;
  77. gchar *password = secret_password_lookup_finish_fn (result, &error);
  78. Q_UNUSED(source);
  79. if (arg) {
  80. if (error) {
  81. QKeychain::Error code = gerrorToCode(error);
  82. arg->self->q->emitFinishedWithError( code, QString::fromUtf8(error->message) );
  83. } else {
  84. if (password) {
  85. QByteArray raw = QByteArray(password);
  86. switch(arg->self->mode) {
  87. case QKeychain::JobPrivate::Binary:
  88. arg->self->data = QByteArray::fromBase64(raw);
  89. break;
  90. case QKeychain::JobPrivate::Text:
  91. default:
  92. arg->self->data = raw;
  93. }
  94. arg->self->q->emitFinished();
  95. } else if (arg->self->mode == QKeychain::JobPrivate::Text) {
  96. arg->self->mode = QKeychain::JobPrivate::Binary;
  97. secret_password_lookup_fn (qtkeychainSchema(), nullptr,
  98. on_password_lookup, arg,
  99. "user", arg->user.toUtf8().constData(),
  100. "server", arg->server.toUtf8().constData(),
  101. "type", "base64",
  102. nullptr);
  103. return;
  104. } else {
  105. arg->self->q->emitFinishedWithError( QKeychain::EntryNotFound, QObject::tr("Entry not found") );
  106. }
  107. }
  108. }
  109. if (error) {
  110. g_error_free (error);
  111. }
  112. if (password) {
  113. secret_password_free_fn (password);
  114. }
  115. if (arg) {
  116. delete arg;
  117. }
  118. }
  119. static void
  120. on_password_stored (GObject *source,
  121. GAsyncResult *result,
  122. gpointer inst)
  123. {
  124. GError *error = nullptr;
  125. QKeychain::JobPrivate *self = (QKeychain::JobPrivate*)inst;
  126. Q_UNUSED(source);
  127. secret_password_store_finish_fn (result, &error);
  128. if (self) {
  129. if (error) {
  130. self->q->emitFinishedWithError( gerrorToCode(error),
  131. QString::fromUtf8(error->message) );
  132. } else {
  133. self->q->emitFinished();
  134. }
  135. }
  136. if (error) {
  137. g_error_free (error);
  138. }
  139. }
  140. static void
  141. on_password_cleared (GObject *source,
  142. GAsyncResult *result,
  143. gpointer inst)
  144. {
  145. GError *error = nullptr;
  146. QKeychain::JobPrivate *self = (QKeychain::JobPrivate*)inst;
  147. gboolean removed = secret_password_clear_finish_fn (result, &error);
  148. Q_UNUSED(source);
  149. if (self) {
  150. if ( error ) {
  151. self->q->emitFinishedWithError( gerrorToCode(error),
  152. QString::fromUtf8(error->message) );
  153. } else {
  154. Q_UNUSED(removed);
  155. self->q->emitFinished();
  156. }
  157. }
  158. if (error) {
  159. g_error_free (error);
  160. }
  161. }
  162. static QString modeToString(QKeychain::JobPrivate::Mode mode) {
  163. switch(mode) {
  164. case QKeychain::JobPrivate::Binary:
  165. return "base64";
  166. default:
  167. return "plaintext";
  168. }
  169. }
  170. #endif
  171. bool LibSecretKeyring::isAvailable() {
  172. #if defined(HAVE_LIBSECRET)
  173. const LibSecretKeyring& keyring = instance();
  174. if (!keyring.isLoaded())
  175. return false;
  176. if (secret_password_lookup_fn == nullptr)
  177. return false;
  178. if (secret_password_lookup_finish_fn == nullptr)
  179. return false;
  180. if (secret_password_store_fn == nullptr)
  181. return false;
  182. if (secret_password_store_finish_fn == nullptr)
  183. return false;
  184. if (secret_password_clear_fn == nullptr)
  185. return false;
  186. if (secret_password_clear_finish_fn == nullptr)
  187. return false;
  188. if (secret_password_free_fn == nullptr)
  189. return false;
  190. if (secret_error_get_quark_fn == nullptr)
  191. return false;
  192. return true;
  193. #else
  194. return false;
  195. #endif
  196. }
  197. bool LibSecretKeyring::findPassword(const QString &user, const QString &server,
  198. QKeychain::JobPrivate *self)
  199. {
  200. #if defined(HAVE_LIBSECRET)
  201. if (!isAvailable()) {
  202. return false;
  203. }
  204. self->mode = QKeychain::JobPrivate::Text;
  205. self->data = QByteArray();
  206. callbackArg *arg = new callbackArg;
  207. arg->self = self;
  208. arg->user = user;
  209. arg->server = server;
  210. secret_password_lookup_fn (qtkeychainSchema(), nullptr, on_password_lookup, arg,
  211. "user", user.toUtf8().constData(),
  212. "server", server.toUtf8().constData(),
  213. "type", "plaintext",
  214. nullptr);
  215. return true;
  216. #else
  217. Q_UNUSED(user)
  218. Q_UNUSED(server)
  219. Q_UNUSED(self)
  220. return false;
  221. #endif
  222. }
  223. bool LibSecretKeyring::writePassword(const QString &display_name,
  224. const QString &user,
  225. const QString &server,
  226. const QKeychain::JobPrivate::Mode mode,
  227. const QByteArray &password,
  228. QKeychain::JobPrivate *self)
  229. {
  230. #if defined(HAVE_LIBSECRET)
  231. if (!isAvailable()) {
  232. return false;
  233. }
  234. QString type = modeToString(mode);
  235. QByteArray pwd;
  236. switch(mode) {
  237. case QKeychain::JobPrivate::Binary:
  238. pwd = password.toBase64();
  239. break;
  240. default:
  241. pwd = password;
  242. break;
  243. }
  244. secret_password_store_fn (qtkeychainSchema(), SECRET_COLLECTION_DEFAULT,
  245. display_name.toUtf8().constData(),
  246. pwd.constData(), nullptr, on_password_stored, self,
  247. "user", user.toUtf8().constData(),
  248. "server", server.toUtf8().constData(),
  249. "type", type.toUtf8().constData(),
  250. nullptr);
  251. return true;
  252. #else
  253. Q_UNUSED(display_name)
  254. Q_UNUSED(user)
  255. Q_UNUSED(server)
  256. Q_UNUSED(mode)
  257. Q_UNUSED(password)
  258. Q_UNUSED(self)
  259. return false;
  260. #endif
  261. }
  262. bool LibSecretKeyring::deletePassword(const QString &key, const QString &service,
  263. QKeychain::JobPrivate* self)
  264. {
  265. #if defined(HAVE_LIBSECRET)
  266. if (!isAvailable()) {
  267. return false;
  268. }
  269. secret_password_clear_fn (qtkeychainSchema(), nullptr, on_password_cleared, self,
  270. "user", key.toUtf8().constData(),
  271. "server", service.toUtf8().constData(),
  272. nullptr);
  273. #else
  274. Q_UNUSED(key)
  275. Q_UNUSED(service)
  276. Q_UNUSED(self)
  277. return false;
  278. #endif
  279. }
  280. LibSecretKeyring::LibSecretKeyring()
  281. : QLibrary(QLatin1String("secret-1"), 0)
  282. {
  283. #ifdef HAVE_LIBSECRET
  284. if (load()) {
  285. secret_password_lookup_fn =
  286. (secret_password_lookup_t)resolve("secret_password_lookup");
  287. secret_password_lookup_finish_fn =
  288. (secret_password_lookup_finish_t)resolve("secret_password_lookup_finish");
  289. secret_password_store_fn =
  290. (secret_password_store_t)resolve("secret_password_store");
  291. secret_password_store_finish_fn =
  292. (secret_password_store_finish_t)resolve("secret_password_store_finish");
  293. secret_password_clear_fn =
  294. (secret_password_clear_t)resolve("secret_password_clear");
  295. secret_password_clear_finish_fn =
  296. (secret_password_clear_finish_t)resolve("secret_password_clear_finish");
  297. secret_password_free_fn =
  298. (secret_password_free_t)resolve("secret_password_free");
  299. secret_error_get_quark_fn =
  300. (secret_error_get_quark_t)resolve("secret_error_get_quark");
  301. }
  302. #endif
  303. }
  304. LibSecretKeyring &LibSecretKeyring::instance() {
  305. static LibSecretKeyring instance;
  306. return instance;
  307. }