Commit acaa1f1f authored by Lisa's avatar Lisa
Browse files

Third revision: key editing, general polishing

parent 1f2a2ab6
This diff is collapsed.
# - Try to find the QGpgME library
# Once done this will define
#
# QGPGME_FOUND
# QGPGME_LIBRARIES
# QGPGME_INCLUDE_DIR
# What we do here is a bit simplictic, but it's no worse than what
# people were using in kdepim up to now...
find_package(Gpgme)
if(GPGME_FOUND)
if ( WIN32 )
find_library(_QGPGME_EXTRA_LIBRARY gpgme++
HINTS ${GPGME_LIBRARY_DIR})
else ( WIN32 )
find_library(_QGPGME_EXTRA_LIBRARY gpgme++-pthread
HINTS ${GPGME_LIBRARY_DIR})
endif ( WIN32 )
find_library(QGPGME_LIBRARY qgpgme
HINTS ${GPGME_LIBRARY_DIR})
if (QGPGME_LIBRARY)
# get the libdirectory and then go one up
get_filename_component(_QGPGME_PREFIX "${QGPGME_LIBRARY}" PATH)
get_filename_component(_QGPGME_PREFIX "${_QGPGME_PREFIX}" PATH)
find_path(QGPGME_INCLUDE_DIR qgpgme/qgpgme_export.h
HINTS "${_QGPGME_PREFIX}/include" )
endif (QGPGME_LIBRARY)
if ( WIN32 )
set(QGPGME_LIBRARIES ${QGPGME_LIBRARY} ${_QGPGME_EXTRA_LIBRARY} ${GPGME_VANILLA_LIBRARIES} ${GPGME_QT_LIBRARIES})
else ( WIN32 )
set(QGPGME_LIBRARIES ${QGPGME_LIBRARY} ${_QGPGME_EXTRA_LIBRARY} ${GPGME_PTHREAD_LIBRARIES})
endif ( WIN32 )
endif(GPGME_FOUND)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(QGpgme DEFAULT_MSG QGPGME_LIBRARY QGPGME_INCLUDE_DIR _QGPGME_EXTRA_LIBRARY)
mark_as_advanced(QGPGME_LIBRARY _QGPGME_EXTRA_LIBRARY QGPGME_INCLUDE_DIR)
......@@ -19,19 +19,31 @@
#include <gpgme.h>
#include <iostream>
#define IS_HELP(x) ((x) == "help" || (x) == "--help" || (x) == "-h")
/* Utility macro for translating C-like boolean values into strings */
#define YESNO(x) ((x) == 1 ? "yes" : "no")
/**
* TODO
* - comments
* - import from keyserver
* - trusting when importing
* - good error handling
* - remove useless cmake modules from directory
* - fix paths
using namespace std;
/*
* TODO: check that the trust level is set correctly
* make the import from server work
* fix paths for the keyring
* translations?
*/
using namespace std;
/*
* Compares the number of arguments passed from the command line with the minimum required by
* a specified operation.
*/
void countArgs(gpgme_ctx_t ctx, const QStringList& args, int minimum)
{
if (args.size() < minimum) {
QTextStream err(stderr);
err << "Error: wrong number of arguments. See \"" << args.at(0) << " help\" for details." << endl;
gpgme_release(ctx);
exit(-1);
}
}
void printHelp()
{
......@@ -63,6 +75,10 @@ void printVersion()
out << QObject::tr(":: akabei-key v2.0 is part of the Akabei suite.") << endl;
}
/*
* Initializes a keyring "akabei" with all the necessary files; the configuration file stores the
* keyserver URL, used for getting new keys.
*/
void initRing(QDir& keyring)
{
const QString AkabeiKeyringPub( "pubring.gpg" );
......@@ -111,8 +127,11 @@ void initRing(QDir& keyring)
conf.write("keyserver hkp://keys.gnupg.net");
conf.close();
cout << ":: Keyring initialized successfully." << endl;
}
/* Prints all public keys in the keyring */
void listKeys(gpgme_ctx_t ctx)
{
gpgme_key_t key;
......@@ -139,92 +158,180 @@ void listKeys(gpgme_ctx_t ctx)
}
}
/*
* This callback is being invoked at each step of the key editing process started by the editKey() function.
* Parameters are:
* - f: a customizable argument. Here it records whether the editing has finished, and is initially set to false;
* - status: a code identifying the reason this function was called;
* - args: a string identifiying the current step
* - fd: where the user's answer must be written.
*/
gpgme_error_t editCallback(void* f, gpgme_status_code_t status, const char* args, int fd)
{
QTextStream out(stdout);
QString result;
QString processDesc(args);
bool* finished = (bool *)f;
out << "[-- Code: " << status << ", " << args << " --]" << endl;
if (fd >= 0) { /* this is a message requesting for some input */
if (processDesc == "keyedit.prompt") {
result = "trust";
} else if (processDesc == "edit_ownertrust.value") {
result = "5";
} else if (processDesc == "edit_ownertrust.set_ultimate.okay") {
result = "y";
(*finished) = true;
}
} else if ((*finished)) { /* this is just a status message, namely a confirmation for the previous action */
return GPG_ERR_USER_1; /* I found no other way of stopping the editing, so I use a customizable error code */
}
/* Write the result, if there is one */
if (!result.isEmpty()) {
gpgme_io_write(fd, result.toUtf8().data(), result.size());
gpgme_io_write(fd, "\n", 1);
}
return GPG_ERR_NO_ERROR;
}
void editKey(gpgme_ctx_t ctx, gpgme_key_t key)
{
bool finished = false;
gpgme_data_t output;
gpgme_error_t err;
gpgme_data_new(&output);
err = gpgme_op_edit(ctx, key, editCallback, ( void* )&finished, output);
if (err != GPG_ERR_NO_ERROR && err != GPG_ERR_USER_1) {
cerr << "Editing the key failed: " << gpgme_strerror(err) << endl;
gpgme_data_release(output);
return;
}
cout << ":: Key edited successfully." << endl;
gpgme_data_release(output);
}
/* Imports a key from the filename and sets its trust level to 5 via editing */
void importKey(gpgme_ctx_t ctx, const QString& filename)
{
gpgme_data_t data;
gpgme_error_t err;
gpgme_key_t key;
gpgme_data_new(&data);
err = gpgme_data_new_from_file(&data, filename.toUtf8().data(), 1);
if (err) {
qDebug() << "Cannot import data" << gpgme_strerror(err);
cerr << "Couldn't import key data from file: " << gpgme_strerror(err) << endl;
gpgme_data_release(data);
return;
}
err = gpgme_op_import(ctx, data);
if (err) {
qDebug() << "Cannot import" << gpgme_strerror(err);
cerr << "Couldn't import key into keyring: " << gpgme_strerror(err) << endl;
gpgme_data_release(data);
return;
}
gpgme_import_result_t res = gpgme_op_import_result(ctx);
qDebug() << res->considered << res->not_imported;
qDebug() << res->imported << res->imported_rsa;
cout << ":: Key imported successfully." << endl;
cout << ":: Editing key..." << endl;
gpgme_import_result_t result = gpgme_op_import_result(ctx);
gpgme_get_key(ctx, result->imports->fpr, &key, 0);
editKey(ctx, key);
gpgme_key_release(key);
gpgme_data_release(data);
}
/* Prints more detailed information about a single key identified by id */
void printKeyById(gpgme_ctx_t ctx, const QString& id)
{
gpgme_key_t key;
gpgme_error_t err = gpgme_get_key(ctx, id.toUtf8().data(), &key, 0);
if (err) {
qDebug() << "Cannot print key" << gpgme_strerror(err);
cerr << "Couldn't print key: " << gpgme_strerror(err) << endl;
return;
}
qDebug() << key->can_encrypt << key->can_sign << key->expired << key->invalid;
qDebug() << key->subkeys->keyid << key->uids->name << key->uids->email;
QTextStream out(stdout);
out << "-- Key " << key->subkeys->keyid << endl;
out << "Name: " << key->uids->name << endl;
out << "Email: " << key->uids->email << endl;
out << "Expired: " << YESNO(key->expired) << endl;
out << "Revoked: " << YESNO(key->revoked) << endl;
out << "Disabled: " << YESNO(key->disabled) << endl;
out << "Invalid: " << YESNO(key->invalid) << endl;
out << "Can encrypt: " << YESNO(key->invalid) << endl;
out << "Can sign: " << YESNO(key->can_sign) << endl;
out << "Can authenticate: " << YESNO(key->can_authenticate) << endl;
gpgme_key_release(key);
}
/* Deletes a key from the keyring */
void removeKey(gpgme_ctx_t ctx, const QString& id)
{
gpgme_key_t key;
gpgme_error_t err = gpgme_get_key(ctx, id.toUtf8().data(), &key, 0);
if (err) {
qDebug() << "Cannot get key" << gpgme_strerror(err);
cerr << "Couldn't find key: " << gpgme_strerror(err) << endl;
return;
}
err = gpgme_op_delete(ctx, key, 1);
if (err) {
qDebug() << "Cannot delete key" << gpgme_strerror(err);
cerr << "Couldn't delete key: " << gpgme_strerror(err) << endl;
gpgme_key_release(key);
return;
}
cout << ":: Key deleted successfully." << endl;
gpgme_key_release(key);
}
/* Imports a key from a keyserver */
void getFromServer(gpgme_ctx_t ctx, QString id)
{
gpgme_error_t err;
gpgme_key_t key;
/* Lookup works only when the key starts with this prefix */
if (!id.startsWith("0x")) {
id.prepend("0x");
}
/* Tells GPG to import the key from the keyserver written in the gpg.conf of this keyring */
gpgme_keylist_mode_t mode = gpgme_get_keylist_mode(ctx);
mode &= ~GPGME_KEYLIST_MODE_LOCAL;
mode |= GPGME_KEYLIST_MODE_EXTERN;
err = gpgme_set_keylist_mode(ctx, mode);
if (err) {
qDebug() << "Cannot set new mode";
cerr << "Couldn't set new mode for importing: " << gpgme_strerror(err) << endl;
return;
}
/* Gets the key from the remote keyserver */
err = gpgme_get_key(ctx, id.toUtf8().data(), &key, 0);
if (err) {
qDebug() << "Cannot get key" << id << gpgme_strerror(err);
cerr << "Couldn't get the requested key: " << gpgme_strerror(err) << endl;
return;
}
/* The key is now imported in the keyring: unfortunately only arrays can be specified */
gpgme_key_t* keys = (gpgme_key_t *)malloc( 2 * sizeof(gpgme_key_t) );
keys[0] = key;
keys[1] = NULL;
......@@ -232,11 +339,15 @@ void getFromServer(gpgme_ctx_t ctx, QString id)
free(keys);
if (err) {
qDebug() << gpgme_strerror(err);
cerr << "Couldn't import the key: " << gpgme_strerror(err) << endl;
gpgme_key_release(key);
return;
}
editKey(ctx, key);
qDebug() << "Imported" << key->uids->name << key->uids->email << key->subkeys->keyid;
cout << ":: The following key has been imported: " << key->uids->name << " " << key->uids->email << " " << key->subkeys->keyid << endl;
gpgme_key_release(key);
}
int main(int argc, char **argv)
......@@ -251,9 +362,10 @@ int main(int argc, char **argv)
out << ":: akabei-key v2.0 (akabei)" << endl;
out << ":: It looks like you don't have an Akabei keyring yet." << endl;
out << ":: This application will initialize the ring before continuing normally." << endl;
out << ":: This application will initialize the ring and then exit. Run again your command to get the actual result." << endl;
out << ":: Starting initialization..." << endl;
initRing(keyring);
exit(0);
}
QStringList args = QCoreApplication::arguments();
......@@ -265,7 +377,7 @@ int main(int argc, char **argv)
QString op = args.at(1);
if ( IS_HELP(op) ) {
if (op == "help" || op == "--help" || op == "-h") {
printHelp();
exit(0);
}
......@@ -277,48 +389,40 @@ int main(int argc, char **argv)
gpgme_ctx_t ctx;
/* Sets the keyring directory */
gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP, NULL, AkabeiKeyringDir.toUtf8().data());
gpgme_check_version(NULL);
gpgme_error_t err = gpgme_new(&ctx);
if (err) {
qDebug() << "init error";
cerr << "Error initializing GPG: " << gpgme_strerror(err);
exit(-1);
}
if (op == "list") {
listKeys(ctx);
} else if (op == "import") {
if (args.size() < 3) {
qDebug() << "missing arg";
exit(-1);
}
countArgs(ctx, args, 3);
importKey(ctx, args.at(2));
} else if (op == "print") {
if (args.size() < 3) {
qDebug() << "missing arg";
exit(-1);
}
} else if (op == "print") {
countArgs(ctx, args, 3);
printKeyById(ctx, args.at(2));
} else if (op == "remove") {
if (args.size() < 3) {
qDebug() << "missing arg";
exit(-1);
}
} else if (op == "remove") {
countArgs(ctx, args, 3);
removeKey(ctx, args.at(2));
} else if (op == "get") {
if (args.size() < 3) {
qDebug() << "missing arg";
exit(-1);
}
} else if (op == "get") {
countArgs(ctx, args, 3);
getFromServer(ctx, args.at(2));
}
gpgme_release(ctx);
return 0;
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment