Add help text for attribute S/R.
[qpwmc.git] / pwmd.h
blob692bd73981d87b6b872be5441dd70531b58b4d48
1 /*
2 Copyright (C) 2010-2024 Ben Kibbey <bjk@luxsci.net>
4 This file is part of qpwmc.
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 USA
22 * This is a generic class that wraps around the most used libpwmd functions.
23 * It should serve its purpose for most applications and when it doesn't you
24 * can reimplement it or use the handle() to do what's needed.
26 #ifndef PWMD_H
27 #define PWMD_H
29 #include <QObject>
30 #include <QThread>
31 #include <QMutex>
32 #include <QProcess>
33 #include <QStringList>
34 #include <QMetaType>
35 #include <libpwmd.h>
36 #include "pwmdRemoteHost.h"
38 /* Internal command ID's are < 0 although they may still be passed to
39 * the commandResult() signal. */
40 #define PwmdCmdIdInvalid -255
41 #define PwmdCmdIdRunQueue -128 // Deprecated
42 #define PwmdCmdIdInternalCloseFile -8
43 #define PwmdCmdIdInternalConnectHost -7
44 #define PwmdCmdIdInternalGenKey -6
45 #define PwmdCmdIdInternalStatusError -5
46 #define PwmdCmdIdInternalConnect -4
47 #define PwmdCmdIdInternalOpen -3
48 #define PwmdCmdIdInternalSave -2
49 #define PwmdCmdIdInternalPassword -1
51 class Pwmd;
52 class PwmdInquireData;
54 /* Creates a new command to be passed to the command thread. */
55 class PwmdCommandQueueItem
57 public:
58 PwmdCommandQueueItem (int id, QString cmd = 0, pwmd_inquire_cb_t = 0,
59 PwmdInquireData * = 0);
60 ~PwmdCommandQueueItem ();
62 /* The command id which should be >= 0 since internal id's are < 0. */
63 int id();
65 /* Whether this command is flagged as queued. When this command is the first
66 * in the command queue no action is done. You must call Pwmd::runQueue(). */
67 void setQueuedOnly (bool);
68 bool queuedOnly ();
70 /* The command and callback function along with callback data. */
71 QString command();
72 pwmd_inquire_cb_t callback();
73 PwmdInquireData *data();
74 void setData (PwmdInquireData *);
76 /* A known error code that should not flush the command queue for this
77 * command. */
78 void addError (gpg_error_t);
79 void addError (gpg_err_source_t, gpg_err_code_t);
81 /* Check that the passed error code is in the known error code list. */
82 bool checkError (gpg_error_t);
84 // Return the error list.
85 QList <gpg_error_t> errorList ();
87 /* Clear all known error codes. */
88 void clearErrorList ();
91 * Call this after you are done with this command in each receiver of the
92 * Pwmd::commandResult() signal to let the garbage collector delete it.
94 void setSeen ();
97 * Set an error string and code from a callback function of a command to be
98 * shown in the UI thread.
100 void setErrorString (QString);
101 QString errorString ();
102 void setError (gpg_error_t);
103 gpg_error_t error ();
105 // Whether this command requires a server inquire.
106 void setNeedsInquire (bool = true);
107 bool needsInquire ();
109 // Whether this is the final item in the queue with a unique command ID.
110 bool isFinalItem ();
112 private:
113 friend class PwmdCommandThread;
114 friend class PwmdCommandCollectorThread;
115 friend class Pwmd;
116 int seen ();
117 /* Set host data for use with Pwmd::connectHost() and related signals. */
118 void setHostData (PwmdRemoteHost &);
119 PwmdRemoteHost &hostData ();
120 void setCommand (QString);
121 void setFinalItem (bool = true);
123 int _id;
124 QString _cmd;
125 pwmd_inquire_cb_t _cb;
126 PwmdInquireData *_data;
127 QList <gpg_error_t> _errorList;
128 int _seen;
129 gpg_error_t _error;
130 QString _errorString;
131 bool _queuedOnly;
132 PwmdRemoteHost _hostData;
133 bool _needsInquire;
134 bool _isFinal;
137 /* Runs a command queue in a separate thread to prevent blocking the UI. */
138 class PwmdCommandThread : public QThread
140 Q_OBJECT
141 public:
142 PwmdCommandThread (Pwmd *p);
143 ~PwmdCommandThread ();
144 void run();
145 void flushQueue (bool = false, gpg_error_t = 0);
146 unsigned queued ();
147 bool isQueued (int);
148 bool isQueued (PwmdCommandQueueItem *);
149 bool setCommand (PwmdCommandQueueItem *, bool queueOnly = false);
151 private:
152 friend class Pwmd;
154 bool hasFinalItem (PwmdCommandQueueItem *, QList <PwmdCommandQueueItem *>);
155 gpg_error_t connectSocket (PwmdCommandQueueItem *);
156 gpg_error_t openFile (PwmdCommandQueueItem *);
157 gpg_error_t saveFile (PwmdCommandQueueItem *);
158 gpg_error_t genKey (PwmdCommandQueueItem *);
159 gpg_error_t changePassword (PwmdCommandQueueItem *);
160 static gpg_error_t knownHostCallback (void *data, const char *host,
161 const char *key, size_t len);
163 Pwmd *pwm;
164 QList <PwmdCommandQueueItem *>queue;
165 QMutex *queueMutex;
168 class PwmdCommandCollectorThread : public QThread
170 Q_OBJECT
171 public:
172 PwmdCommandCollectorThread (Pwmd *p);
173 ~PwmdCommandCollectorThread ();
174 void run ();
175 void addItem (PwmdCommandQueueItem *);
176 bool isQueued (int);
177 bool isQueued (PwmdCommandQueueItem *);
179 private:
180 Pwmd *pwm;
181 QList <PwmdCommandQueueItem *> list;
182 QMutex *listMutex;
186 /* Processes status messages when not in a command. It is started once the
187 * connection is established. */
188 class PwmdStatusMessageThread : public QThread
190 Q_OBJECT
191 public:
192 PwmdStatusMessageThread (Pwmd *p);
193 void run ();
195 private:
196 Pwmd *pwm;
199 class Pwmd : public QObject
201 Q_OBJECT
202 public:
204 * 'sock' is the Url to connect to. 'filename' is the default filename
205 * to open which can be reset with setFilename(). 'clientName' is used
206 * with the pwmd log file.
208 Pwmd (const QString & filename = 0, const QString & clientName = 0,
209 const QString & sock = 0, QObject *parent = 0);
210 ~Pwmd ();
212 /* Sent as an argument to the stateChanged() signal. */
213 enum ConnectionState
215 Init, Connecting, Connected, Opened
218 /* The ERROR status message obtained via gpgme/gnupg/gpg-agent. */
219 gpg_error_t lastError;
221 /* The current pwmd connection state. */
222 ConnectionState state ();
224 /* The data pointer passed to the statusMessage signal. */
225 void setStatusMessageData (void *);
226 void *statusMessageData ();
228 /* Returns the currently set socket path. */
229 QString socket ();
231 /* Will not be considered until the next connect(). */
232 void setSocket (const QString & sock);
234 /* Returns the currently set data filename. */
235 QString filename ();
238 * To be called before open() and when a new data file is to be
239 * opened. The default the value passed to the constructor.
241 void setFilename (QString filename);
243 /* Set user data. May be useful when this class is passed to other
244 * classes.
246 void setData (QByteArray);
247 QByteArray data ();
249 /* If you use pwmd_command() from libpwmd on a handle obtained from
250 * Pwmd:handle(), these may be needed since the status message thread
251 * does socket IO but only after obtaining a mutex.
253 void lockMutex ();
254 void unlockMutex ();
257 * Sends a command to the pwmd server. When queueOnly is true, the command is
258 * only added to the command queue. When false and there are other commands
259 * in the queue, the queue is run as if runQueue() had been called. Commands
260 * are run in first-in first-out order (FIFO).
262 virtual bool command (PwmdCommandQueueItem *cmd, bool queueOnly = false);
264 /* Runs all queued commands. */
265 virtual void runQueue ();
267 /* Flush all queued commands. */
268 virtual void flushQueue ();
270 /* Returns the number of queued commands. */
271 virtual unsigned queued ();
273 /* Returns true when command 'id' or 'cmd' is in the command queue or waiting
274 * to be garbage collected. */
275 virtual bool isQueued (int id);
276 virtual bool isQueued (PwmdCommandQueueItem *cmd);
278 /* Cancel a connection in progress or running command. */
279 virtual gpg_error_t cancel ();
281 /* Set positional parameters to pwmd_connect(). The arguments are
282 * added to pwmd_connect() in the order the were added to the list. See the
283 * libpwmd(3) manual page for details about the parameters.
285 virtual void setConnectParameters (QStringList params);
287 /* Set the data parameter for the knownHost signal. */
288 virtual void setKnownHostData (void *data);
289 virtual void *knownHostData ();
292 * Connect the socket set with setSocket(). This function uses the
293 * PwmdCmdIdInternalConnect command ID.
295 virtual bool connect (pwmd_inquire_cb_t = 0, void *data = 0,
296 bool queueOnly = false, PwmdCommandQueueItem ** = 0);
298 /* Associates a handle with an existing connected socket. */
299 virtual bool connectFd (int fd, pwmd_inquire_cb_t = 0, void *data = 0,
300 bool queueOnly = false, PwmdCommandQueueItem ** = 0);
302 /* For use with connectFd() to keep track of the Connecting/Connected states.
303 * You must wait for the connectReady() signal before calling connectFd().
305 virtual bool connectHost (PwmdRemoteHost hostData, bool queueOnly = false,
306 PwmdCommandQueueItem ** = 0);
308 /* When set, a function to call when GPG_ERR_BAD_PASSPHRASE is
309 returned during pwmd_open(). The function should return 0 to try
310 again or an error code to cancel (normally
311 GPG_ERR_BAD_PASSPHRASE). The 'data' parameter is set with
312 setBadPassphraseData(). The 'final' parameter is set to true when
313 the callback has been called at least once and before
314 Pwmd::open() returns and in this case the return value of the
315 callback is ignored. This lets the app for example reset any pinentry
316 strings and only when needed.
318 virtual void setBadPassphraseCallback (gpg_error_t (*)(void *data, bool final));
319 void setBadPassphraseData (void *);
322 * Opens the filename specified with setFilename(). This function uses the
323 * PwmdCmdIdInternalOpen command ID.
325 virtual bool open (pwmd_inquire_cb_t cb = 0, PwmdInquireData * = 0,
326 bool queueOnly = false, PwmdCommandQueueItem ** = 0);
329 * Generates a new key. The parameter 'args' are any extra arguments to
330 * pass to the pwmd GENKEY protocol command. This function uses the
331 * PwmdCmdIdInternalGenKey command ID.
333 virtual bool genkey (const QString & args = QString (),
334 pwmd_inquire_cb_t cb = 0, PwmdInquireData * = 0,
335 bool queueOnly = false, PwmdCommandQueueItem ** = 0);
338 * Saves any changes do disk. The parameter 'args' are any extra arguments to
339 * pass to the pwmd SAVE protocol command. This function uses the
340 * PwmdCmdIdInternalSave command ID.
342 virtual bool save (const QString & args = QString (),
343 pwmd_inquire_cb_t cb = 0, PwmdInquireData * = 0,
344 bool queueOnly = false, PwmdCommandQueueItem ** = 0);
347 * Changes the passphrase for a data file or secret key. The parameter 'args'
348 * are any extra arguments to pass to the pwmd PASSWD protocol command. This
349 * function uses the PwmdCmdIdInternalPassword command ID.
351 virtual bool passwd (const QString & args = QString (),
352 pwmd_inquire_cb_t cb = 0, PwmdInquireData * = 0,
353 bool queueOnly = false, PwmdCommandQueueItem ** = 0);
356 * Closes any active handle and resets the connection state to Init.
358 virtual gpg_error_t reset (bool doEmit = true, bool disco = true);
361 * Keeps the connection open but closes the opened file. */
362 virtual gpg_error_t close (bool queueOnly = false,
363 PwmdCommandQueueItem ** = 0);
365 /* These should be set before opening a file. */
366 void setLockOnOpen (bool = true); // pwmd option LOCK_ON_OPEN
367 bool lockOnOpen ();
369 /* If you need call other libpwmd functions then you may need this. */
370 pwm_t *handle ();
373 * For convienence. Spawn a qpwmc process to select the socket, file and
374 * element path parameters. The 'external' parameter is whether this instance
375 * is from another process other than "qpwmc".
377 * Returns false on failure or true on success and sets result to the line
378 * containing the parameter values. Use extractToken() to parse the result.
380 bool spawnEditor (QString &result, QString sock = 0, QString file = 0,
381 QString path = 0, bool external = true);
384 * For convienence. Parse the string returned by spawnEditor() and return the
385 * token value. Token may be one of: <SOCKET>, <SOCKET-ARG>, <SSH-AGENT>,
386 * <TLS-VERIFY>, <CONNECT-TIMEOUT>, <SOCKET-TIMEOUT>, <FILE> or <PATH>. The
387 * offset parameter is set to the position of the found token in str.
389 static QString extractToken (const QString str, const QString token,
390 int &offset);
393 /* Shows a descriptive error string of the specified error code. */
394 static void showError (gpg_error_t, Pwmd * = 0, bool bulk = false);
395 static QString errorString(gpg_error_t, Pwmd * = 0);
397 /* Returns the number of receivers for a 'signal'. */
398 int receivers (const char *signal);
400 /* For convienence. Handles passphrases and key files. */
401 static gpg_error_t inquireCallback (void *user, const char *keyword,
402 gpg_error_t rc, char **data,
403 size_t * len);
406 * For convienence. Shows a message box prompting to accept or reject a new
407 * SSH hostname.
409 static gpg_error_t knownHostPrompt(void *data, const char *host,
410 const char *key, size_t len);
413 * Can be set before showError() to show an error string for a TLS error.
415 int tlsError;
417 signals:
418 /* Required for use with connectFd(). After calling connectHost(), wait for
419 * this signal to continue obtaining the file descriptor to pass to
420 * connectFd().
422 void connectReady (PwmdRemoteHost);
424 /* Emitted when the connection state changes. */
425 void stateChanged (Pwmd::ConnectionState);
428 * Emitted when a command completes from the command queue. The 'item' is the
429 * item passed to command (), or an internal item using an internal command
430 * ID. In either case the item must not be deleted by the user. Instead, call
431 * PwmdCommandQueueItem::setSeen() in each receiver of this signal when done
432 * with the item to let it be garbage collected.
434 * The 'queued' parameter is whether the item was queued but removed from the
435 * command queue do to a previous command failure. When 'queued' is true the
436 * same 'rc' as the command that failed is passed.
438 void commandResult (PwmdCommandQueueItem *item, QString result,
439 gpg_error_t rc, bool queued);
441 /* Emitted when a status message is received from the server. */
442 void statusMessage (QString msg, void *userData);
444 /* Emitted at the start and end of a command or connection. The cmdId is the
445 * command that trigged the signal. */
446 void busy (int cmdId, bool);
449 * Emitted when verification for a hostname is needed when connecting to a
450 * remote SSH pwmd server. The parent object should send the "knownHostRc
451 * (gpg_error_t)" signal and set the gpg_error_t to 0 for a successful
452 * verification of the remote host, or an error code to terminate the
453 * connection. This Pwmd object is already setup to receive the signal.
455 * The 'data' parameter should be set with Pwmd::setKnownHostData().
457 void knownHost (void *data, const char *host, const char *hash, size_t len);
459 #ifdef Q_OS_ANDROID
460 void passphrase (Pwmd *, QString keyword, QString desc, QString prompt,
461 QPrivateSignal);
462 void passphraseResult (QString passphrase, QPrivateSignal);
463 #endif
465 private slots:
466 void slotProcessError (QProcess::ProcessError e);
467 void slotKnownHostRc (gpg_error_t);
468 #ifdef Q_OS_ANDROID
469 void slotPassphrase (Pwmd *, QString, QString, QString);
470 void slotPassphraseResult (QString);
471 #endif
473 private:
474 void resetHandle ();
475 gpg_error_t doConnect (bool, pwmd_inquire_cb_t, void *);
476 static gpg_error_t statusCallback (void *, const char *);
477 static gpg_error_t sshPassphraseCallback (void *, const char *, const char *,
478 char **);
479 char *connectParameterValue (int);
480 static gpg_error_t passphraseCommon (Pwmd *, const QString &keyfile,
481 char **r_passphrase, size_t *r_size,
482 QString keyword, PwmdInquireData *inq);
484 friend class PwmdStatusMessageThread;
485 friend class PwmdCommandThread;
486 friend class PwmdCommandCollectorThread;
487 PwmdStatusMessageThread statusMsgThread;
488 PwmdCommandThread commandThread;
489 PwmdCommandCollectorThread collectorThread;
490 QRecursiveMutex *commandMutex;
491 pwm_t *pwm;
492 ConnectionState _state;
493 QString _socket;
494 QString _filename;
495 QString clientName;
496 bool _lockOnOpen;
497 QString _knownhosts;
498 QString _identity;
499 unsigned inquireMaxlen;
500 QStringList _connectParameters;
501 gpg_error_t (*badPassphraseCallback) (void *, bool);
502 void *badPassphraseData;
503 QByteArray _data;
504 bool _quit;
505 bool spawnError;
506 bool needKnownHostRc;
507 gpg_error_t knownHostRc;
508 #ifdef Q_OS_ANDROID
509 bool needPassphraseRc;
510 gpg_error_t passphraseRc;
511 QString thePassphraseResult;
512 QString pinentryHint;
513 QString pinentryInfo;
514 #endif
515 void *_knownHostData;
516 void *_statusMessageData;
519 /* This is used in to handle pinentry loopback mode over an SSH channel, for
520 * key files and for other inquire data when the inquire type is
521 * NoInquirePassphrase. It may also be used generically in your app by passing
522 * this class as the data parameter of an inquire callback such as the static
523 * Pwmd::inquireCallback().
525 * Note that the data of this class must be allocated with the
526 * libpwmd(3) allocators when set upon the ctor or setData(). When this
527 * class is deleted the data will be freed in the dtor.
529 class PwmdInquireData
531 public:
532 PwmdInquireData ();
533 PwmdInquireData (const QString &, pwm_t * = 0);
534 PwmdInquireData (pwm_t * handle, QString filename = 0, char *data = 0,
535 size_t size = 0);
536 ~PwmdInquireData ();
537 void setFilename (QString);
538 const QString & filename ();
539 void setKeyFile (QString);
540 const QString & keyFile ();
541 void setEncryptKeyFile (QString);
542 const QString & encryptKeyFile ();
543 void setSignKeyFile (QString);
544 const QString & signKeyFile ();
545 void setData (char *, size_t);
546 void setData (const QString &);
547 char *data ();
548 size_t size ();
549 void setHandle (pwm_t *);
550 pwm_t *handle ();
551 void setUser (QString);
552 const QString & user ();
553 void setUser2 (QString);
554 const QString & user2 ();
555 void setSent (size_t);
556 size_t sent ();
557 void setUserBool (bool);
558 bool userBool ();
559 void setUserPtr (void *);
560 void *userPtr ();
561 void setUserInt (int);
562 int userInt ();
563 void setSaving (bool extended = false);
564 bool isSaving (bool &extended);
566 /* For internal commands which may be used in a callback function. */
567 void setCommandItem (PwmdCommandQueueItem *);
568 PwmdCommandQueueItem *commandItem ();
570 private:
571 friend class Pwmd;
572 friend class PwmdCommandThread;
573 void setUserInternal (QString);
574 const QString & userInternal ();
576 QString _keyFile;
577 QString _encryptKeyFile;
578 QString _signKeyFile;
579 char *_data;
580 size_t _size;
581 pwm_t *_handle;
582 QString _filename;
583 QString _user;
584 QString _user2;
585 size_t _sent;
586 bool _userBool;
587 void *_userPtr;
588 int _userInt;
589 QString _userInternal;
590 PwmdCommandQueueItem *_item;
591 void *_internalData; // for keyfiles.
592 int _internalInt; // File descriptor for pwmd_connect_fd().
593 Pwmd *pwm;
594 bool _isBulk;
595 bool _extendedSave;
596 bool _isSaving;
599 Q_DECLARE_METATYPE (Pwmd::ConnectionState);
601 #endif