diff options
author | saturneric <[email protected]> | 2023-12-03 07:28:41 +0000 |
---|---|---|
committer | saturneric <[email protected]> | 2023-12-03 07:28:41 +0000 |
commit | e0bc882bd46c40c86d9497fa043bbfe3e469888f (patch) | |
tree | 962b673899e4209ddd3504e975dcbac6758c496e | |
parent | feat: add buddled qt pinentry and make it works (diff) | |
download | GpgFrontend-e0bc882bd46c40c86d9497fa043bbfe3e469888f.tar.gz GpgFrontend-e0bc882bd46c40c86d9497fa043bbfe3e469888f.zip |
feat: introduce mimalloc to replace secmem
Diffstat (limited to '')
35 files changed, 545 insertions, 3478 deletions
diff --git a/.gitmodules b/.gitmodules index 397da182..3463984f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,4 +6,7 @@ url = https://github.com/bricke/Qt-AES.git [submodule "third_party/spdlog"] path = third_party/spdlog - url = https://github.com/gabime/spdlog.git
\ No newline at end of file + url = https://github.com/gabime/spdlog.git +[submodule "third_party/mimalloc"] + path = third_party/mimalloc + url = https://github.com/microsoft/mimalloc.git diff --git a/CMakeLists.txt b/CMakeLists.txt index d164dc9d..5fd05f30 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -346,7 +346,7 @@ if (LINUX) endif() if(USING_COMPILER_CLANG) - add_compile_options(-stdlib=libstdc++) + add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-stdlib=libstdc++>) endif() if(SYSTEM_NAME STREQUAL "FreeBSD") diff --git a/gpgfrontend.qrc b/gpgfrontend.qrc index 59859444..eb85ee76 100644 --- a/gpgfrontend.qrc +++ b/gpgfrontend.qrc @@ -75,5 +75,10 @@ <file alias="button_next.png">resource/lfs/icons/button_next.png</file> <file alias="refresh.png">resource/lfs/icons/refresh.png</file> <file alias="up.png">resource/lfs/icons/up.png</file> + <file alias="data-error.svg">resource/lfs/icons/data-error.svg</file> + <file alias="document-encrypt.png">resource/lfs/icons/document-encrypt.png</file> + <file alias="hint.svg">resource/lfs/icons/hint.svg</file> + <file alias="password-generate.svg">resource/lfs/icons/password-generate.svg</file> + <file alias="visibility.svg">resource/lfs/icons/visibility.svg</file> </qresource> </RCC> diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 137acc7b..ebc08df5 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -27,6 +27,7 @@ aux_source_directory(./function/result_analyse CORE_SOURCE) aux_source_directory(./function/basic CORE_SOURCE) aux_source_directory(./function/gpg CORE_SOURCE) +aux_source_directory(./function/secure_memory CORE_SOURCE) aux_source_directory(./function CORE_SOURCE) aux_source_directory(./thread CORE_SOURCE) aux_source_directory(./model CORE_SOURCE) @@ -43,8 +44,7 @@ add_library(gpgfrontend_core SHARED ${CORE_SOURCE}) set(_export_file "${CMAKE_CURRENT_SOURCE_DIR}/GpgFrontendCoreExport.h") generate_export_header(gpgfrontend_core EXPORT_FILE_NAME "${_export_file}") -# link buddled pinentry -target_link_libraries(gpgfrontend_core PRIVATE gpgfrontend_pinentry) +target_link_libraries(gpgfrontend_core PUBLIC mimalloc) # link third-party libraries target_link_libraries(gpgfrontend_core PUBLIC config++) @@ -83,7 +83,7 @@ if (MINGW) endif () # spdlog -target_link_libraries(gpgfrontend_core PRIVATE spdlog) +target_link_libraries(gpgfrontend_core PUBLIC spdlog) # link libarchive if(APPLE) diff --git a/src/core/GpgFrontendCore.cpp b/src/core/GpgFrontendCore.cpp new file mode 100644 index 00000000..5021b37d --- /dev/null +++ b/src/core/GpgFrontendCore.cpp @@ -0,0 +1,32 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "core/GpgFrontendCore.h" + +// mimalloc +#include <mimalloc-new-delete.h>
\ No newline at end of file diff --git a/src/core/GpgFrontendCore.h b/src/core/GpgFrontendCore.h index fcf890fa..89f2dee6 100644 --- a/src/core/GpgFrontendCore.h +++ b/src/core/GpgFrontendCore.h @@ -32,6 +32,7 @@ #include <QtCore> // std +#include <cstdint> #include <filesystem> #include <memory> #include <string> diff --git a/src/core/function/gpg/GpgContext.cpp b/src/core/function/gpg/GpgContext.cpp index 9ee81bad..a6040231 100644 --- a/src/core/function/gpg/GpgContext.cpp +++ b/src/core/function/gpg/GpgContext.cpp @@ -30,18 +30,6 @@ #include <gpg-error.h> #include <gpgme.h> -#include <qapplication.h> -#include <qcoreapplication.h> -#include <qeasingcurve.h> -#include <qeventloop.h> -#include <qlabel.h> -#include <qobject.h> -#include <qtmetamacros.h> -#include <qwindowdefs.h> -#include <sys/types.h> -#include <unistd.h> - -#include <cstring> #include "core/function/CoreSignalStation.h" #include "core/function/basic/GpgFunctionObject.h" @@ -54,7 +42,6 @@ #include "core/utils/CommonUtils.h" #include "core/utils/GpgUtils.h" #include "function/CacheManager.h" -#include "spdlog/spdlog.h" #ifdef _WIN32 #include <windows.h> diff --git a/src/core/function/gpg/GpgKeyOpera.cpp b/src/core/function/gpg/GpgKeyOpera.cpp index 64f33373..751d4f51 100644 --- a/src/core/function/gpg/GpgKeyOpera.cpp +++ b/src/core/function/gpg/GpgKeyOpera.cpp @@ -49,7 +49,6 @@ #include "core/utils/CommonUtils.h" #include "core/utils/GpgUtils.h" #include "model/DataObject.h" -#include "spdlog/spdlog.h" namespace GpgFrontend { @@ -290,7 +289,7 @@ void GpgKeyOpera::ModifyPassword(const GpgKey& key, return; } - auto *task = new Thread::Task( + auto* task = new Thread::Task( [&](const DataObjectPtr& data_object) -> int { auto err = gpgme_op_passwd(ctx_, static_cast<gpgme_key_t>(key), 0); data_object->Swap({err}); diff --git a/src/core/function/secure_memory/SecureMemoryAllocator.cpp b/src/core/function/secure_memory/SecureMemoryAllocator.cpp new file mode 100644 index 00000000..09390305 --- /dev/null +++ b/src/core/function/secure_memory/SecureMemoryAllocator.cpp @@ -0,0 +1,44 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "SecureMemoryAllocator.h" + +#include <mimalloc.h> + +namespace GpgFrontend { + +auto SecurityMemoryAllocator::Allocate(std::size_t size) -> void* { + return mi_malloc(size); +} + +auto SecurityMemoryAllocator::Reallocate(void* ptr, std::size_t size) -> void* { + return mi_realloc(ptr, size); +} + +void SecurityMemoryAllocator::Deallocate(void* p) { mi_free(p); } +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/function/secure_memory/SecureMemoryAllocator.h b/src/core/function/secure_memory/SecureMemoryAllocator.h new file mode 100644 index 00000000..724da226 --- /dev/null +++ b/src/core/function/secure_memory/SecureMemoryAllocator.h @@ -0,0 +1,44 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <cstdint> + +namespace GpgFrontend { + +class GPGFRONTEND_CORE_EXPORT SecurityMemoryAllocator { + public: + static auto Allocate(std::size_t) -> void*; + + static auto Reallocate(void*, std::size_t) -> void*; + + static void Deallocate(void*); +}; + +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/MemoryUtils.cpp b/src/core/utils/MemoryUtils.cpp new file mode 100644 index 00000000..eae9fa10 --- /dev/null +++ b/src/core/utils/MemoryUtils.cpp @@ -0,0 +1,42 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "MemoryUtils.h" + +namespace GpgFrontend { + +auto SecureMalloc(std::size_t size) -> void * { + return SecurityMemoryAllocator::Allocate(size); +} + +auto SecureRealloc(void *ptr, std::size_t size) -> void * { + return SecurityMemoryAllocator::Reallocate(ptr, size); +} + +void SecureFree(void *ptr) { SecurityMemoryAllocator::Deallocate(ptr); } +} // namespace GpgFrontend
\ No newline at end of file diff --git a/src/core/utils/MemoryUtils.h b/src/core/utils/MemoryUtils.h new file mode 100644 index 00000000..507f693f --- /dev/null +++ b/src/core/utils/MemoryUtils.h @@ -0,0 +1,172 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include "core/GpgFrontendCoreExport.h" +#include "core/function/secure_memory/SecureMemoryAllocator.h" + +/* To avoid that a compiler optimizes certain memset calls away, these + macros may be used instead. */ +#define wipememory2(_ptr, _set, _len) \ + do { \ + volatile char *_vptr = (volatile char *)(_ptr); \ + size_t _vlen = (_len); \ + while (_vlen) { \ + *_vptr = (_set); \ + _vptr++; \ + _vlen--; \ + } \ + } while (0) +#define wipememory(_ptr, _len) wipememory2(_ptr, 0, _len) +#define wipe(_ptr, _len) wipememory2(_ptr, 0, _len) + +#define xtoi_1(p) \ + (*(p) <= '9' ? (*(p) - '0') \ + : *(p) <= 'F' ? (*(p) - 'A' + 10) \ + : (*(p) - 'a' + 10)) +#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p) + 1)) + +namespace GpgFrontend { + +template <typename T> +class PointerConverter { + public: + explicit PointerConverter(void *ptr) : ptr_(ptr) {} + + auto AsType() const -> T * { return static_cast<T *>(ptr_); } + + private: + void *ptr_; +}; + +/** + * @brief + * + * @return void* + */ +auto GPGFRONTEND_CORE_EXPORT SecureMalloc(std::size_t) -> void *; + +/** + * @brief + * + * @return void* + */ +auto GPGFRONTEND_CORE_EXPORT SecureRealloc(void *, std::size_t) -> void *; + +/** + * @brief + * + * @tparam T + * @return T* + */ +template <typename T> +auto SecureMallocAsType(std::size_t size) -> T * { + return PointerConverter<T>(SecurityMemoryAllocator::Allocate(size)).AsType(); +} + +/** + * @brief + * + * @return void* + */ +template <typename T> +auto SecureReallocAsType(T *ptr, std::size_t size) -> T * { + return PointerConverter<T>(SecurityMemoryAllocator::Reallocate(ptr, size)) + .AsType(); +} + +/** + * @brief + * + */ +void GPGFRONTEND_CORE_EXPORT SecureFree(void *); + +template <typename T> +struct SecureObjectDeleter { + void operator()(T *ptr) { + if (ptr) { + ptr->~T(); + SecurityMemoryAllocator::Deallocate(ptr); + } + } +}; + +template <typename T, typename... Args> +static auto SecureCreateObject(Args &&...args) -> T * { + void *mem = SecurityMemoryAllocator::Allocate(sizeof(T)); + if (!mem) return nullptr; + + try { + return new (mem) T(std::forward<Args>(args)...); + } catch (...) { + SecurityMemoryAllocator::Deallocate(mem); + throw; + } +} + +template <typename T> +static void SecureDestroyObject(T *obj) { + if (!obj) return; + obj->~T(); + SecurityMemoryAllocator::Deallocate(obj); +} + +template <typename T, typename... Args> +static auto SecureCreateUniqueObject(Args &&...args) + -> std::unique_ptr<T, SecureObjectDeleter<T>> { + void *mem = SecurityMemoryAllocator::Allocate(sizeof(T)); + if (!mem) throw std::bad_alloc(); + + try { + return std::unique_ptr<T, SecureObjectDeleter<T>>( + new (mem) T(std::forward<Args>(args)...)); + } catch (...) { + SecurityMemoryAllocator::Deallocate(mem); + throw; + } +} + +template <typename T, typename... Args> +auto SecureCreateSharedObject(Args &&...args) -> std::shared_ptr<T> { + void *mem = SecurityMemoryAllocator::Allocate(sizeof(T)); + if (!mem) throw std::bad_alloc(); + + try { + T *obj = new (mem) T(std::forward<Args>(args)...); + return std::shared_ptr<T>(obj, [](T *ptr) { + ptr->~T(); + SecurityMemoryAllocator::Deallocate(ptr); + }); + } catch (...) { + SecurityMemoryAllocator::Deallocate(mem); + throw; + } +} + +}; // namespace GpgFrontend
\ No newline at end of file diff --git a/src/pinentry/CMakeLists.txt b/src/pinentry/CMakeLists.txt index e6d53feb..b5283d11 100644 --- a/src/pinentry/CMakeLists.txt +++ b/src/pinentry/CMakeLists.txt @@ -33,14 +33,15 @@ else() list(APPEND PINENTRY_SOURCE "capslock/capslock_unix.cpp") endif() -message(STATUS "PINENTRY_SOURCE: ${PINENTRY_SOURCE}") add_library(gpgfrontend_pinentry SHARED ${PINENTRY_SOURCE}) +target_link_libraries(gpgfrontend_pinentry PUBLIC gpgfrontend_core) + # link Qt core if(Qt6_DIR) - target_link_libraries(gpgfrontend_pinentry PUBLIC Qt6::Core Qt6::Widgets) + target_link_libraries(gpgfrontend_pinentry PUBLIC Qt6::Widgets) else() - target_link_libraries(gpgfrontend_pinentry PUBLIC Qt5::Core Qt5::Widgets) + target_link_libraries(gpgfrontend_pinentry PUBLIC Qt5::Widgets) endif() # using std c++ 17 diff --git a/src/pinentry/argparse.cpp b/src/pinentry/argparse.cpp deleted file mode 100644 index d3568c64..00000000 --- a/src/pinentry/argparse.cpp +++ /dev/null @@ -1,1360 +0,0 @@ -/* [argparse.c wk 17.06.97] Argument Parser for option handling - * Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc. - * Copyright (C) 1997-2001, 2006-2008, 2013-2015 Werner Koch - * - * This file is part of JNLIB, which is a subsystem of GnuPG. - * - * JNLIB is free software; you can redistribute it and/or modify it - * under the terms of either - * - * - the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at - * your option) any later version. - * - * or - * - * - the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * or both in parallel, as here. - * - * JNLIB is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copies of the GNU General Public License - * and the GNU Lesser General Public License along with this program; - * if not, see <https://www.gnu.org/licenses/>. - * SPDX-License-Identifier: (GPL-2.0+ OR LGPL-3.0+) - */ - -/* This file may be used as part of GnuPG or standalone. A GnuPG - build is detected by the presence of the macro GNUPG_MAJOR_VERSION. - Some feature are only availalbe in the GnuPG build mode. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <ctype.h> -#include <errno.h> -#include <limits.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#ifdef GNUPG_MAJOR_VERSION -#include "libjnlib-config.h" -#include "logging.h" -#include "mischelp.h" -#include "stringhelp.h" -#ifdef JNLIB_NEED_UTF8CONV -#include "utf8conv.h" -#endif -#endif /*GNUPG_MAJOR_VERSION*/ - -#include "argparse.h" - -/* GnuPG uses GPLv3+ but a standalone version of this defaults to - GPLv2+ because that is the license of this file. Change this if - you include it in a program which uses GPLv3. If you don't want to - set a a copyright string for your usage() you may also hardcode it - here. */ -#ifndef GNUPG_MAJOR_VERSION - -#define ARGPARSE_GPL_VERSION 2 -#define ARGPARSE_CRIGHT_STR "Copyright (C) YEAR NAME" - -#else /* Used by GnuPG */ - -#define ARGPARSE_GPL_VERSION 3 -#define ARGPARSE_CRIGHT_STR "Copyright (C) 2015 Free Software Foundation, Inc." - -#endif /*GNUPG_MAJOR_VERSION*/ - -/* Replacements for standalone builds. */ -#ifndef GNUPG_MAJOR_VERSION -#ifndef _ -#define _(a) (a) -#endif -#ifndef DIM -#define DIM(v) (sizeof(v) / sizeof((v)[0])) -#endif -#define jnlib_malloc(a) malloc((a)) -#define jnlib_realloc(a, b) realloc((a), (b)) -#define jnlib_strdup(a) strdup((a)) -#define jnlib_free(a) free((a)) -#define jnlib_log_error my_log_error -#define jnlib_log_bug my_log_bug -#define trim_spaces(a) my_trim_spaces((a)) -#define map_static_macro_string(a) (a) -#endif /*!GNUPG_MAJOR_VERSION*/ - -#define ARGPARSE_STR(v) #v -#define ARGPARSE_STR2(v) ARGPARSE_STR(v) - -/* Replacements for standalone builds. */ -#ifndef GNUPG_MAJOR_VERSION -static void my_log_error(const char *fmt, ...) { - va_list arg_ptr; - - va_start(arg_ptr, fmt); - fprintf(stderr, "%s: ", strusage(11)); - vfprintf(stderr, fmt, arg_ptr); - va_end(arg_ptr); -} - -static void my_log_bug(const char *fmt, ...) { - va_list arg_ptr; - - va_start(arg_ptr, fmt); - fprintf(stderr, "%s: Ohhhh jeeee: ", strusage(11)); - vfprintf(stderr, fmt, arg_ptr); - va_end(arg_ptr); - abort(); -} - -static char *my_trim_spaces(char *str) { - char *string, *p, *mark; - - string = str; - /* Find first non space character. */ - for (p = string; *p && isspace(*(unsigned char *)p); p++) - ; - /* Move characters. */ - for ((mark = NULL); (*string = *p); string++, p++) - if (isspace(*(unsigned char *)p)) { - if (!mark) mark = string; - } else - mark = NULL; - if (mark) *mark = '\0'; /* Remove trailing spaces. */ - - return str; -} - -#endif /*!GNUPG_MAJOR_VERSION*/ - -/********************************* - * @Summary arg_parse - * #include "argparse.h" - * - * typedef struct { - * char *argc; pointer to argc (value subject to change) - * char ***argv; pointer to argv (value subject to change) - * unsigned flags; Global flags (DO NOT CHANGE) - * int err; print error about last option - * 1 = warning, 2 = abort - * int r_opt; return option - * int r_type; type of return value (0 = no argument found) - * union { - * int ret_int; - * long ret_long - * ulong ret_ulong; - * char *ret_str; - * } r; Return values - * struct { - * int idx; - * const char *last; - * void *aliases; - * } internal; DO NOT CHANGE - * } ARGPARSE_ARGS; - * - * typedef struct { - * int short_opt; - * const char *long_opt; - * unsigned flags; - * } ARGPARSE_OPTS; - * - * int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts ); - * - * @Description - * This is my replacement for getopt(). See the example for a typical usage. - * Global flags are: - * Bit 0 : Do not remove options form argv - * Bit 1 : Do not stop at last option but return other args - * with r_opt set to -1. - * Bit 2 : Assume options and real args are mixed. - * Bit 3 : Do not use -- to stop option processing. - * Bit 4 : Do not skip the first arg. - * Bit 5 : allow usage of long option with only one dash - * Bit 6 : ignore --version - * all other bits must be set to zero, this value is modified by the - * function, so assume this is write only. - * Local flags (for each option): - * Bit 2-0 : 0 = does not take an argument - * 1 = takes int argument - * 2 = takes string argument - * 3 = takes long argument - * 4 = takes ulong argument - * Bit 3 : argument is optional (r_type will the be set to 0) - * Bit 4 : allow 0x etc. prefixed values. - * Bit 6 : Ignore this option - * Bit 7 : This is a command and not an option - * You stop the option processing by setting opts to NULL, the function will - * then return 0. - * @Return Value - * Returns the args.r_opt or 0 if ready - * r_opt may be -2/-7 to indicate an unknown option/command. - * @See Also - * ArgExpand - * @Notes - * You do not need to process the options 'h', '--help' or '--version' - * because this function includes standard help processing; but if you - * specify '-h', '--help' or '--version' you have to do it yourself. - * The option '--' stops argument processing; if bit 1 is set the function - * continues to return normal arguments. - * To process float args or unsigned args you must use a string args and do - * the conversion yourself. - * @Example - * - * ARGPARSE_OPTS opts[] = { - * { 'v', "verbose", 0 }, - * { 'd', "debug", 0 }, - * { 'o', "output", 2 }, - * { 'c', "cross-ref", 2|8 }, - * { 'm', "my-option", 1|8 }, - * { 300, "ignored-long-option, ARGPARSE_OP_IGNORE}, - * { 500, "have-no-short-option-for-this-long-option", 0 }, - * {0} }; - * ARGPARSE_ARGS pargs = { &argc, &argv, 0 } - * - * while( ArgParse( &pargs, &opts) ) { - * switch( pargs.r_opt ) { - * case 'v': opt.verbose++; break; - * case 'd': opt.debug++; break; - * case 'o': opt.outfile = pargs.r.ret_str; break; - * case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break; - * case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break; - * case 500: opt.a_long_one++; break - * default : pargs.err = 1; break; -- force warning output -- - * } - * } - * if( argc > 1 ) - * log_fatal( "Too many args"); - * - */ - -typedef struct alias_def_s *ALIAS_DEF; -struct alias_def_s { - ALIAS_DEF next; - char *name; /* malloced buffer with name, \0, value */ - const char *value; /* ptr into name */ -}; - -/* Object to store the names for the --ignore-invalid-option option. - This is a simple linked list. */ -typedef struct iio_item_def_s *IIO_ITEM_DEF; -struct iio_item_def_s { - IIO_ITEM_DEF next; - char name[1]; /* String with the long option name. */ -}; - -static const char *(*strusage_handler)(int) = NULL; -static int (*custom_outfnc)(int, const char *); - -static int set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s); -static void show_help(ARGPARSE_OPTS *opts, unsigned flags); -static void show_version(void); -static int writestrings(int is_error, const char *string, ...) -#if __GNUC__ >= 4 - __attribute__((sentinel(0))) -#endif - ; - -void argparse_register_outfnc(int (*fnc)(int, const char *)) { - custom_outfnc = fnc; -} - -/* Write STRING and all following const char * arguments either to - stdout or, if IS_ERROR is set, to stderr. The list of strings must - be terminated by a NULL. */ -static int writestrings(int is_error, const char *string, ...) { - va_list arg_ptr; - const char *s; - int count = 0; - - if (string) { - s = string; - va_start(arg_ptr, string); - do { - if (custom_outfnc) - custom_outfnc(is_error ? 2 : 1, s); - else - fputs(s, is_error ? stderr : stdout); - count += strlen(s); - } while ((s = va_arg(arg_ptr, const char *))); - va_end(arg_ptr); - } - return count; -} - -static void flushstrings(int is_error) { - if (custom_outfnc) - custom_outfnc(is_error ? 2 : 1, NULL); - else - fflush(is_error ? stderr : stdout); -} - -static void initialize(ARGPARSE_ARGS *arg, const char *filename, - unsigned *lineno) { - if (!(arg->flags & (1 << 15))) { - /* Initialize this instance. */ - arg->internal.idx = 0; - arg->internal.last = NULL; - arg->internal.inarg = 0; - arg->internal.stopped = 0; - arg->internal.aliases = NULL; - arg->internal.cur_alias = NULL; - arg->internal.iio_list = NULL; - arg->err = 0; - arg->flags |= 1 << 15; /* Mark as initialized. */ - if (*arg->argc < 0) jnlib_log_bug("invalid argument for arg_parse\n"); - } - - if (arg->err) { - /* Last option was erroneous. */ - const char *s; - - if (filename) { - if (arg->r_opt == ARGPARSE_UNEXPECTED_ARG) - s = _("argument not expected"); - else if (arg->r_opt == ARGPARSE_READ_ERROR) - s = _("read error"); - else if (arg->r_opt == ARGPARSE_KEYWORD_TOO_LONG) - s = _("keyword too long"); - else if (arg->r_opt == ARGPARSE_MISSING_ARG) - s = _("missing argument"); - else if (arg->r_opt == ARGPARSE_INVALID_ARG) - s = _("invalid argument"); - else if (arg->r_opt == ARGPARSE_INVALID_COMMAND) - s = _("invalid command"); - else if (arg->r_opt == ARGPARSE_INVALID_ALIAS) - s = _("invalid alias definition"); - else if (arg->r_opt == ARGPARSE_OUT_OF_CORE) - s = _("out of core"); - else - s = _("invalid option"); - jnlib_log_error("%s:%u: %s\n", filename, *lineno, s); - } else { - s = arg->internal.last ? arg->internal.last : "[??]"; - - if (arg->r_opt == ARGPARSE_MISSING_ARG) - jnlib_log_error(_("missing argument for option \"%.50s\"\n"), s); - else if (arg->r_opt == ARGPARSE_INVALID_ARG) - jnlib_log_error(_("invalid argument for option \"%.50s\"\n"), s); - else if (arg->r_opt == ARGPARSE_UNEXPECTED_ARG) - jnlib_log_error(_("option \"%.50s\" does not expect an " - "argument\n"), - s); - else if (arg->r_opt == ARGPARSE_INVALID_COMMAND) - jnlib_log_error(_("invalid command \"%.50s\"\n"), s); - else if (arg->r_opt == ARGPARSE_AMBIGUOUS_OPTION) - jnlib_log_error(_("option \"%.50s\" is ambiguous\n"), s); - else if (arg->r_opt == ARGPARSE_AMBIGUOUS_COMMAND) - jnlib_log_error(_("command \"%.50s\" is ambiguous\n"), s); - else if (arg->r_opt == ARGPARSE_OUT_OF_CORE) - jnlib_log_error("%s\n", _("out of core\n")); - else - jnlib_log_error(_("invalid option \"%.50s\"\n"), s); - } - if (arg->err != ARGPARSE_PRINT_WARNING) exit(2); - arg->err = 0; - } - - /* Zero out the return value union. */ - arg->r.ret_str = NULL; - arg->r.ret_long = 0; -} - -static void store_alias(ARGPARSE_ARGS *arg, char *name, char *value) { - /* TODO: replace this dummy function with a rea one - * and fix the probelms IRIX has with (ALIAS_DEV)arg.. - * used as lvalue - */ - (void)arg; - (void)name; - (void)value; -#if 0 - ALIAS_DEF a = jnlib_xmalloc( sizeof *a ); - a->name = name; - a->value = value; - a->next = (ALIAS_DEF)arg->internal.aliases; - (ALIAS_DEF)arg->internal.aliases = a; -#endif -} - -/* Return true if KEYWORD is in the ignore-invalid-option list. */ -static int ignore_invalid_option_p(ARGPARSE_ARGS *arg, const char *keyword) { - IIO_ITEM_DEF item = (IIO_ITEM_DEF)arg->internal.iio_list; - - for (; item; item = item->next) - if (!strcmp(item->name, keyword)) return 1; - return 0; -} - -/* Add the keywords up to the next LF to the list of to be ignored - options. After returning FP will either be at EOF or the next - character read wll be the first of a new line. The function - returns 0 on success or true on malloc failure. */ -static int ignore_invalid_option_add(ARGPARSE_ARGS *arg, FILE *fp) { - IIO_ITEM_DEF item; - int c; - char name[100]; - int namelen = 0; - int ready = 0; - enum { skipWS, collectNAME, skipNAME, addNAME } state = skipWS; - - while (!ready) { - c = getc(fp); - if (c == '\n') - ready = 1; - else if (c == EOF) { - c = '\n'; - ready = 1; - } - again: - switch (state) { - case skipWS: - if (!isascii(c) || !isspace(c)) { - namelen = 0; - state = collectNAME; - goto again; - } - break; - - case collectNAME: - if (isspace(c)) { - state = addNAME; - goto again; - } else if (namelen < DIM(name) - 1) - name[namelen++] = c; - else /* Too long. */ - state = skipNAME; - break; - - case skipNAME: - if (isspace(c)) { - state = skipWS; - goto again; - } - break; - - case addNAME: - name[namelen] = 0; - if (!ignore_invalid_option_p(arg, name)) { - item = (IIO_ITEM_DEF)jnlib_malloc(sizeof *item + namelen); - if (!item) return 1; - strcpy(item->name, name); - item->next = (IIO_ITEM_DEF)arg->internal.iio_list; - arg->internal.iio_list = item; - } - state = skipWS; - goto again; - } - } - return 0; -} - -/* Clear the entire ignore-invalid-option list. */ -static void ignore_invalid_option_clear(ARGPARSE_ARGS *arg) { - IIO_ITEM_DEF item, tmpitem; - - for (item = (IIO_ITEM_DEF)arg->internal.iio_list; item; item = tmpitem) { - tmpitem = item->next; - jnlib_free(item); - } - arg->internal.iio_list = NULL; -} - -/**************** - * Get options from a file. - * Lines starting with '#' are comment lines. - * Syntax is simply a keyword and the argument. - * Valid keywords are all keywords from the long_opt list without - * the leading dashes. The special keywords "help", "warranty" and "version" - * are not valid here. - * The special keyword "alias" may be used to store alias definitions, - * which are later expanded like long options. - * The option - * ignore-invalid-option OPTIONNAMEs - * is recognized and updates a list of option which should be ignored if they - * are not defined. - * Caller must free returned strings. - * If called with FP set to NULL command line args are parse instead. - * - * Q: Should we allow the syntax - * keyword = value - * and accept for boolean options a value of 1/0, yes/no or true/false? - * Note: Abbreviation of options is here not allowed. - */ -int optfile_parse(FILE *fp, const char *filename, unsigned *lineno, - ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts) { - int state, i, c; - int idx = 0; - char keyword[100]; - char *buffer = NULL; - size_t buflen = 0; - int in_alias = 0; - - if (!fp) /* Divert to to arg_parse() in this case. */ - return arg_parse(arg, opts); - - initialize(arg, filename, lineno); - - /* Find the next keyword. */ - state = i = 0; - for (;;) { - c = getc(fp); - if (c == '\n' || c == EOF) { - if (c != EOF) ++*lineno; - if (state == -1) - break; - else if (state == 2) { - keyword[i] = 0; - for (i = 0; opts[i].short_opt; i++) { - if (opts[i].long_opt && !strcmp(opts[i].long_opt, keyword)) break; - } - idx = i; - arg->r_opt = opts[idx].short_opt; - if ((opts[idx].flags & ARGPARSE_OPT_IGNORE)) { - state = i = 0; - continue; - } else if (!opts[idx].short_opt) { - if (!strcmp(keyword, "ignore-invalid-option")) { - /* No argument - ignore this meta option. */ - state = i = 0; - continue; - } else if (ignore_invalid_option_p(arg, keyword)) { - /* This invalid option is in the iio list. */ - state = i = 0; - continue; - } - arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND) - ? ARGPARSE_INVALID_COMMAND - : ARGPARSE_INVALID_OPTION); - } else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK)) - arg->r_type = 0; /* Does not take an arg. */ - else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL)) - arg->r_type = 0; /* Arg is optional. */ - else - arg->r_opt = ARGPARSE_MISSING_ARG; - - break; - } else if (state == 3) { - /* No argument found. */ - if (in_alias) - arg->r_opt = ARGPARSE_MISSING_ARG; - else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK)) - arg->r_type = 0; /* Does not take an arg. */ - else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL)) - arg->r_type = 0; /* No optional argument. */ - else - arg->r_opt = ARGPARSE_MISSING_ARG; - - break; - } else if (state == 4) { - /* Has an argument. */ - if (in_alias) { - if (!buffer) - arg->r_opt = ARGPARSE_UNEXPECTED_ARG; - else { - char *p; - - buffer[i] = 0; - p = strpbrk(buffer, " \t"); - if (p) { - *p++ = 0; - trim_spaces(p); - } - if (!p || !*p) { - jnlib_free(buffer); - arg->r_opt = ARGPARSE_INVALID_ALIAS; - } else { - store_alias(arg, buffer, p); - } - } - } else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK)) - arg->r_opt = ARGPARSE_UNEXPECTED_ARG; - else { - char *p; - - if (!buffer) { - keyword[i] = 0; - buffer = jnlib_strdup(keyword); - if (!buffer) arg->r_opt = ARGPARSE_OUT_OF_CORE; - } else - buffer[i] = 0; - - if (buffer) { - trim_spaces(buffer); - p = buffer; - if (*p == '"') { - /* Remove quotes. */ - p++; - if (*p && p[strlen(p) - 1] == '\"') p[strlen(p) - 1] = 0; - } - if (!set_opt_arg(arg, opts[idx].flags, p)) jnlib_free(buffer); - } - } - break; - } else if (c == EOF) { - ignore_invalid_option_clear(arg); - if (ferror(fp)) - arg->r_opt = ARGPARSE_READ_ERROR; - else - arg->r_opt = 0; /* EOF. */ - break; - } - state = 0; - i = 0; - } else if (state == -1) - ; /* Skip. */ - else if (state == 0 && isascii(c) && isspace(c)) - ; /* Skip leading white space. */ - else if (state == 0 && c == '#') - state = 1; /* Start of a comment. */ - else if (state == 1) - ; /* Skip comments. */ - else if (state == 2 && isascii(c) && isspace(c)) { - /* Check keyword. */ - keyword[i] = 0; - for (i = 0; opts[i].short_opt; i++) - if (opts[i].long_opt && !strcmp(opts[i].long_opt, keyword)) break; - idx = i; - arg->r_opt = opts[idx].short_opt; - if ((opts[idx].flags & ARGPARSE_OPT_IGNORE)) { - state = 1; /* Process like a comment. */ - } else if (!opts[idx].short_opt) { - if (!strcmp(keyword, "alias")) { - in_alias = 1; - state = 3; - } else if (!strcmp(keyword, "ignore-invalid-option")) { - if (ignore_invalid_option_add(arg, fp)) { - arg->r_opt = ARGPARSE_OUT_OF_CORE; - break; - } - state = i = 0; - ++*lineno; - } else if (ignore_invalid_option_p(arg, keyword)) - state = 1; /* Process like a comment. */ - else { - arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND) - ? ARGPARSE_INVALID_COMMAND - : ARGPARSE_INVALID_OPTION); - state = -1; /* Skip rest of line and leave. */ - } - } else - state = 3; - } else if (state == 3) { - /* Skip leading spaces of the argument. */ - if (!isascii(c) || !isspace(c)) { - i = 0; - keyword[i++] = c; - state = 4; - } - } else if (state == 4) { - /* Collect the argument. */ - if (buffer) { - if (i < buflen - 1) - buffer[i++] = c; - else { - char *tmp; - size_t tmplen = buflen + 50; - - tmp = (char *)jnlib_realloc(buffer, tmplen); - if (tmp) { - buflen = tmplen; - buffer = tmp; - buffer[i++] = c; - } else { - jnlib_free(buffer); - arg->r_opt = ARGPARSE_OUT_OF_CORE; - break; - } - } - } else if (i < DIM(keyword) - 1) - keyword[i++] = c; - else { - size_t tmplen = DIM(keyword) + 50; - buffer = (char *)jnlib_malloc(tmplen); - if (buffer) { - buflen = tmplen; - memcpy(buffer, keyword, i); - buffer[i++] = c; - } else { - arg->r_opt = ARGPARSE_OUT_OF_CORE; - break; - } - } - } else if (i >= DIM(keyword) - 1) { - arg->r_opt = ARGPARSE_KEYWORD_TOO_LONG; - state = -1; /* Skip rest of line and leave. */ - } else { - keyword[i++] = c; - state = 2; - } - } - - return arg->r_opt; -} - -static int find_long_option(ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts, - const char *keyword) { - int i; - size_t n; - - (void)arg; - - /* Would be better if we can do a binary search, but it is not - possible to reorder our option table because we would mess - up our help strings - What we can do is: Build a nice option - lookup table when this function is first invoked */ - if (!*keyword) return -1; - for (i = 0; opts[i].short_opt; i++) - if (opts[i].long_opt && !strcmp(opts[i].long_opt, keyword)) return i; -#if 0 - { - ALIAS_DEF a; - /* see whether it is an alias */ - for( a = args->internal.aliases; a; a = a->next ) { - if( !strcmp( a->name, keyword) ) { - /* todo: must parse the alias here */ - args->internal.cur_alias = a; - return -3; /* alias available */ - } - } - } -#endif - /* not found, see whether it is an abbreviation */ - /* aliases may not be abbreviated */ - n = strlen(keyword); - for (i = 0; opts[i].short_opt; i++) { - if (opts[i].long_opt && !strncmp(opts[i].long_opt, keyword, n)) { - int j; - for (j = i + 1; opts[j].short_opt; j++) { - if (opts[j].long_opt && !strncmp(opts[j].long_opt, keyword, n)) - return -2; /* abbreviation is ambiguous */ - } - return i; - } - } - return -1; /* Not found. */ -} - -int arg_parse(ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts) { - int idx; - int argc; - char **argv; - char *s, *s2; - int i; - - initialize(arg, NULL, NULL); - argc = *arg->argc; - argv = *arg->argv; - idx = arg->internal.idx; - - if (!idx && argc && !(arg->flags & ARGPARSE_FLAG_ARG0)) { - /* Skip the first argument. */ - argc--; - argv++; - idx++; - } - -next_one: - if (!argc) { - /* No more args. */ - arg->r_opt = 0; - goto leave; /* Ready. */ - } - - s = *argv; - arg->internal.last = s; - - if (arg->internal.stopped && (arg->flags & ARGPARSE_FLAG_ALL)) { - arg->r_opt = ARGPARSE_IS_ARG; /* Not an option but an argument. */ - arg->r_type = 2; - arg->r.ret_str = s; - argc--; - argv++; - idx++; /* set to next one */ - } else if (arg->internal.stopped) { - arg->r_opt = 0; - goto leave; /* Ready. */ - } else if (*s == '-' && s[1] == '-') { - /* Long option. */ - char *argpos; - - arg->internal.inarg = 0; - if (!s[2] && !(arg->flags & ARGPARSE_FLAG_NOSTOP)) { - /* Stop option processing. */ - arg->internal.stopped = 1; - arg->flags |= ARGPARSE_FLAG_STOP_SEEN; - argc--; - argv++; - idx++; - goto next_one; - } - - argpos = strchr(s + 2, '='); - if (argpos) *argpos = 0; - i = find_long_option(arg, opts, s + 2); - if (argpos) *argpos = '='; - - if (i < 0 && !strcmp("help", s + 2)) - show_help(opts, arg->flags); - else if (i < 0 && !strcmp("version", s + 2)) { - if (!(arg->flags & ARGPARSE_FLAG_NOVERSION)) { - show_version(); - exit(0); - } - } else if (i < 0 && !strcmp("warranty", s + 2)) { - writestrings(0, strusage(16), "\n", NULL); - exit(0); - } else if (i < 0 && !strcmp("dump-options", s + 2)) { - for (i = 0; opts[i].short_opt; i++) { - if (opts[i].long_opt && !(opts[i].flags & ARGPARSE_OPT_IGNORE)) - writestrings(0, "--", opts[i].long_opt, "\n", NULL); - } - writestrings(0, "--dump-options\n--help\n--version\n--warranty\n", NULL); - exit(0); - } - - if (i == -2) - arg->r_opt = ARGPARSE_AMBIGUOUS_OPTION; - else if (i == -1) { - arg->r_opt = ARGPARSE_INVALID_OPTION; - arg->r.ret_str = s + 2; - } else - arg->r_opt = opts[i].short_opt; - if (i < 0) - ; - else if ((opts[i].flags & ARGPARSE_TYPE_MASK)) { - if (argpos) { - s2 = argpos + 1; - if (!*s2) s2 = NULL; - } else - s2 = argv[1]; - if (!s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL)) { - arg->r_type = ARGPARSE_TYPE_NONE; /* Argument is optional. */ - } else if (!s2) { - arg->r_opt = ARGPARSE_MISSING_ARG; - } else if (!argpos && *s2 == '-' && - (opts[i].flags & ARGPARSE_OPT_OPTIONAL)) { - /* The argument is optional and the next seems to be an - option. We do not check this possible option but - assume no argument */ - arg->r_type = ARGPARSE_TYPE_NONE; - } else { - set_opt_arg(arg, opts[i].flags, s2); - if (!argpos) { - argc--; - argv++; - idx++; /* Skip one. */ - } - } - } else { - /* Does not take an argument. */ - if (argpos) - arg->r_type = ARGPARSE_UNEXPECTED_ARG; - else - arg->r_type = 0; - } - argc--; - argv++; - idx++; /* Set to next one. */ - } else if ((*s == '-' && s[1]) || arg->internal.inarg) { - /* Short option. */ - int dash_kludge = 0; - - i = 0; - if (!arg->internal.inarg) { - arg->internal.inarg++; - if ((arg->flags & ARGPARSE_FLAG_ONEDASH)) { - for (i = 0; opts[i].short_opt; i++) - if (opts[i].long_opt && !strcmp(opts[i].long_opt, s + 1)) { - dash_kludge = 1; - break; - } - } - } - s += arg->internal.inarg; - - if (!dash_kludge) { - for (i = 0; opts[i].short_opt; i++) - if (opts[i].short_opt == *s) break; - } - - if (!opts[i].short_opt && (*s == 'h' || *s == '?')) - show_help(opts, arg->flags); - - arg->r_opt = opts[i].short_opt; - if (!opts[i].short_opt) { - arg->r_opt = (opts[i].flags & ARGPARSE_OPT_COMMAND) - ? ARGPARSE_INVALID_COMMAND - : ARGPARSE_INVALID_OPTION; - arg->internal.inarg++; /* Point to the next arg. */ - arg->r.ret_str = s; - } else if ((opts[i].flags & ARGPARSE_TYPE_MASK)) { - if (s[1] && !dash_kludge) { - s2 = s + 1; - set_opt_arg(arg, opts[i].flags, s2); - } else { - s2 = argv[1]; - if (!s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL)) { - arg->r_type = ARGPARSE_TYPE_NONE; - } else if (!s2) { - arg->r_opt = ARGPARSE_MISSING_ARG; - } else if (*s2 == '-' && s2[1] && - (opts[i].flags & ARGPARSE_OPT_OPTIONAL)) { - /* The argument is optional and the next seems to - be an option. We do not check this possible - option but assume no argument. */ - arg->r_type = ARGPARSE_TYPE_NONE; - } else { - set_opt_arg(arg, opts[i].flags, s2); - argc--; - argv++; - idx++; /* Skip one. */ - } - } - s = "x"; /* This is so that !s[1] yields false. */ - } else { - /* Does not take an argument. */ - arg->r_type = ARGPARSE_TYPE_NONE; - arg->internal.inarg++; /* Point to the next arg. */ - } - if (!s[1] || dash_kludge) { - /* No more concatenated short options. */ - arg->internal.inarg = 0; - argc--; - argv++; - idx++; - } - } else if (arg->flags & ARGPARSE_FLAG_MIXED) { - arg->r_opt = ARGPARSE_IS_ARG; - arg->r_type = 2; - arg->r.ret_str = s; - argc--; - argv++; - idx++; /* Set to next one. */ - } else { - arg->internal.stopped = 1; /* Stop option processing. */ - goto next_one; - } - -leave: - *arg->argc = argc; - *arg->argv = argv; - arg->internal.idx = idx; - return arg->r_opt; -} - -/* Returns: -1 on error, 0 for an integer type and 1 for a non integer - type argument. */ -static int set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s) { - int base = (flags & ARGPARSE_OPT_PREFIX) ? 0 : 10; - long l; - - switch ((arg->r_type = (flags & ARGPARSE_TYPE_MASK))) { - case ARGPARSE_TYPE_LONG: - case ARGPARSE_TYPE_INT: - errno = 0; - l = strtol(s, NULL, base); - if ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) { - arg->r_opt = ARGPARSE_INVALID_ARG; - return -1; - } - if (arg->r_type == ARGPARSE_TYPE_LONG) - arg->r.ret_long = l; - else if ((l < 0 && l < INT_MIN) || l > INT_MAX) { - arg->r_opt = ARGPARSE_INVALID_ARG; - return -1; - } else - arg->r.ret_int = (int)l; - return 0; - - case ARGPARSE_TYPE_ULONG: - while (isascii(*s) && isspace(*s)) s++; - if (*s == '-') { - arg->r.ret_ulong = 0; - arg->r_opt = ARGPARSE_INVALID_ARG; - return -1; - } - errno = 0; - arg->r.ret_ulong = strtoul(s, NULL, base); - if (arg->r.ret_ulong == ULONG_MAX && errno == ERANGE) { - arg->r_opt = ARGPARSE_INVALID_ARG; - return -1; - } - return 0; - - case ARGPARSE_TYPE_STRING: - default: - arg->r.ret_str = s; - return 1; - } -} - -static size_t long_opt_strlen(ARGPARSE_OPTS *o) { - size_t n = strlen(o->long_opt); - - if (o->description && *o->description == '|') { - const char *s; -#ifdef JNLIB_NEED_UTF8CONV - int is_utf8 = is_native_utf8(); -#endif - - s = o->description + 1; - if (*s != '=') n++; - /* For a (mostly) correct length calculation we exclude - continuation bytes (10xxxxxx) if we are on a native utf8 - terminal. */ - for (; *s && *s != '|'; s++) -#ifdef JNLIB_NEED_UTF8CONV - if (is_utf8 && (*s & 0xc0) != 0x80) -#endif - n++; - } - return n; -} - -/**************** - * Print formatted help. The description string has some special - * meanings: - * - A description string which is "@" suppresses help output for - * this option - * - a description,ine which starts with a '@' and is followed by - * any other characters is printed as is; this may be used for examples - * ans such. - * - A description which starts with a '|' outputs the string between this - * bar and the next one as arguments of the long option. - */ -static void show_help(ARGPARSE_OPTS *opts, unsigned int flags) { - const char *s; - char tmp[2]; - - show_version(); - writestrings(0, "\n", NULL); - s = strusage(42); - if (s && *s == '1') { - s = strusage(40); - writestrings(1, s, NULL); - if (*s && s[strlen(s)] != '\n') writestrings(1, "\n", NULL); - } - s = strusage(41); - writestrings(0, s, "\n", NULL); - if (opts[0].description) { - /* Auto format the option description. */ - int i, j, indent; - - /* Get max. length of long options. */ - for (i = indent = 0; opts[i].short_opt; i++) { - if (opts[i].long_opt) - if (!opts[i].description || *opts[i].description != '@') - if ((j = long_opt_strlen(opts + i)) > indent && j < 35) indent = j; - } - - /* Example: " -v, --verbose Viele Sachen ausgeben" */ - indent += 10; - if (*opts[0].description != '@') writestrings(0, "Options:", "\n", NULL); - for (i = 0; opts[i].short_opt; i++) { - s = map_static_macro_string(_(opts[i].description)); - if (s && *s == '@' && !s[1]) /* Hide this line. */ - continue; - if (s && *s == '@') /* Unindented comment only line. */ - { - for (s++; *s; s++) { - if (*s == '\n') { - if (s[1]) writestrings(0, "\n", NULL); - } else { - tmp[0] = *s; - tmp[1] = 0; - writestrings(0, tmp, NULL); - } - } - writestrings(0, "\n", NULL); - continue; - } - - j = 3; - if (opts[i].short_opt < 256) { - tmp[0] = opts[i].short_opt; - tmp[1] = 0; - writestrings(0, " -", tmp, NULL); - if (!opts[i].long_opt) { - if (s && *s == '|') { - writestrings(0, " ", NULL); - j++; - for (s++; *s && *s != '|'; s++, j++) { - tmp[0] = *s; - tmp[1] = 0; - writestrings(0, tmp, NULL); - } - if (*s) s++; - } - } - } else - writestrings(0, " ", NULL); - if (opts[i].long_opt) { - tmp[0] = opts[i].short_opt < 256 ? ',' : ' '; - tmp[1] = 0; - j += writestrings(0, tmp, " --", opts[i].long_opt, NULL); - if (s && *s == '|') { - if (*++s != '=') { - writestrings(0, " ", NULL); - j++; - } - for (; *s && *s != '|'; s++, j++) { - tmp[0] = *s; - tmp[1] = 0; - writestrings(0, tmp, NULL); - } - if (*s) s++; - } - writestrings(0, " ", NULL); - j += 3; - } - for (; j < indent; j++) writestrings(0, " ", NULL); - if (s) { - if (*s && j > indent) { - writestrings(0, "\n", NULL); - for (j = 0; j < indent; j++) writestrings(0, " ", NULL); - } - for (; *s; s++) { - if (*s == '\n') { - if (s[1]) { - writestrings(0, "\n", NULL); - for (j = 0; j < indent; j++) writestrings(0, " ", NULL); - } - } else { - tmp[0] = *s; - tmp[1] = 0; - writestrings(0, tmp, NULL); - } - } - } - writestrings(0, "\n", NULL); - } - if ((flags & ARGPARSE_FLAG_ONEDASH)) - writestrings(0, - "\n(A single dash may be used " - "instead of the double ones)\n", - NULL); - } - if ((s = strusage(19))) { - writestrings(0, "\n", NULL); - writestrings(0, s, NULL); - } - flushstrings(0); - exit(0); -} - -static void show_version(void) { - const char *s; - int i; - - /* Version line. */ - writestrings(0, strusage(11), NULL); - if ((s = strusage(12))) writestrings(0, " (", s, ")", NULL); - writestrings(0, " ", strusage(13), "\n", NULL); - /* Additional version lines. */ - for (i = 20; i < 30; i++) - if ((s = strusage(i))) writestrings(0, s, "\n", NULL); - /* Copyright string. */ - if ((s = strusage(14))) writestrings(0, s, "\n", NULL); - /* Licence string. */ - if ((s = strusage(10))) writestrings(0, s, "\n", NULL); - /* Copying conditions. */ - if ((s = strusage(15))) writestrings(0, s, NULL); - /* Thanks. */ - if ((s = strusage(18))) writestrings(0, s, NULL); - /* Additional program info. */ - for (i = 30; i < 40; i++) - if ((s = strusage(i))) writestrings(0, s, NULL); - flushstrings(0); -} - -void usage(int level) { - const char *p; - - if (!level) { - writestrings(1, strusage(11), " ", strusage(13), "; ", strusage(14), "\n", - NULL); - flushstrings(1); - } else if (level == 1) { - p = strusage(40); - writestrings(1, p, NULL); - if (*p && p[strlen(p)] != '\n') writestrings(1, "\n", NULL); - exit(2); - } else if (level == 2) { - p = strusage(42); - if (p && *p == '1') { - p = strusage(40); - writestrings(1, p, NULL); - if (*p && p[strlen(p)] != '\n') writestrings(1, "\n", NULL); - } - writestrings(0, strusage(41), "\n", NULL); - exit(0); - } -} - -/* Level - * 0: Print copyright string to stderr - * 1: Print a short usage hint to stderr and terminate - * 2: Print a long usage hint to stdout and terminate - * 10: Return license info string - * 11: Return the name of the program - * 12: Return optional name of package which includes this program. - * 13: version string - * 14: copyright string - * 15: Short copying conditions (with LFs) - * 16: Long copying conditions (with LFs) - * 17: Optional printable OS name - * 18: Optional thanks list (with LFs) - * 19: Bug report info - *20..29: Additional lib version strings. - *30..39: Additional program info (with LFs) - * 40: short usage note (with LF) - * 41: long usage note (with LF) - * 42: Flag string: - * First char is '1': - * The short usage notes needs to be printed - * before the long usage note. - */ -const char *strusage(int level) { - const char *p = strusage_handler ? strusage_handler(level) : NULL; - - if (p) return map_static_macro_string(p); - - switch (level) { - case 10: -#if ARGPARSE_GPL_VERSION == 3 - p = - ("License GPLv3+: GNU GPL version 3 or later " - "<https://www.gnu.org/licenses/gpl.html>"); -#else - p = - ("License GPLv2+: GNU GPL version 2 or later " - "<https://www.gnu.org/licenses/>"); -#endif - break; - case 11: - p = "foo"; - break; - case 13: - p = "0.0"; - break; - case 14: - p = ARGPARSE_CRIGHT_STR; - break; - case 15: - p = "This is free software: you are free to change and redistribute it.\n" - "There is NO WARRANTY, to the extent permitted by law.\n"; - break; - case 16: - p = -"This is free software; you can redistribute it and/or modify\n" -"it under the terms of the GNU General Public License as published by\n" -"the Free Software Foundation; either version " -ARGPARSE_STR2(ARGPARSE_GPL_VERSION) -" of the License, or\n" -"(at your option) any later version.\n\n" -"It is distributed in the hope that it will be useful,\n" -"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" -"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" -"GNU General Public License for more details.\n\n" -"You should have received a copy of the GNU General Public License\n" -"along with this software. If not, see <https://www.gnu.org/licenses/>.\n"; - break; - case 40: /* short and long usage */ - case 41: - p = ""; - break; - } - - return p; -} - -/* Set the usage handler. This function is basically a constructor. */ -void set_strusage(const char *(*f)(int)) { strusage_handler = f; } - -#ifdef TEST -static struct { - int verbose; - int debug; - char *outfile; - char *crf; - int myopt; - int echo; - int a_long_one; -} opt; - -int main(int argc, char **argv) { - ARGPARSE_OPTS opts[] = { - ARGPARSE_x('v', "verbose", NONE, 0, "Laut sein"), - ARGPARSE_s_n('e', "echo", - ("Zeile ausgeben, damit wir sehen, " - "was wir eingegeben haben")), - ARGPARSE_s_n('d', "debug", "Debug\nfalls mal etwas\nschief geht"), - ARGPARSE_s_s('o', "output", 0), - ARGPARSE_o_s('c', "cross-ref", "cross-reference erzeugen\n"), - /* Note that on a non-utf8 terminal the ß might garble the output. */ - ARGPARSE_s_n('s', "street", - "|Straße|set the name of the street to Straße"), - ARGPARSE_o_i('m', "my-option", 0), ARGPARSE_s_n(500, "a-long-option", 0), - ARGPARSE_end()}; - ARGPARSE_ARGS pargs = { - &argc, &argv, - (ARGPARSE_FLAG_ALL | ARGPARSE_FLAG_MIXED | ARGPARSE_FLAG_ONEDASH)}; - int i; - - while (arg_parse(&pargs, opts)) { - switch (pargs.r_opt) { - case ARGPARSE_IS_ARG: - printf("arg='%s'\n", pargs.r.ret_str); - break; - case 'v': - opt.verbose++; - break; - case 'e': - opt.echo++; - break; - case 'd': - opt.debug++; - break; - case 'o': - opt.outfile = pargs.r.ret_str; - break; - case 'c': - opt.crf = pargs.r_type ? pargs.r.ret_str : "a.crf"; - break; - case 'm': - opt.myopt = pargs.r_type ? pargs.r.ret_int : 1; - break; - case 500: - opt.a_long_one++; - break; - default: - pargs.err = ARGPARSE_PRINT_WARNING; - break; - } - } - for (i = 0; i < argc; i++) printf("%3d -> (%s)\n", i, argv[i]); - puts("Options:"); - if (opt.verbose) printf(" verbose=%d\n", opt.verbose); - if (opt.debug) printf(" debug=%d\n", opt.debug); - if (opt.outfile) printf(" outfile='%s'\n", opt.outfile); - if (opt.crf) printf(" crffile='%s'\n", opt.crf); - if (opt.myopt) printf(" myopt=%d\n", opt.myopt); - if (opt.a_long_one) printf(" a-long-one=%d\n", opt.a_long_one); - if (opt.echo) printf(" echo=%d\n", opt.echo); - - return 0; -} -#endif /*TEST*/ - -/**** bottom of file ****/ diff --git a/src/pinentry/argparse.h b/src/pinentry/argparse.h deleted file mode 100644 index 5b652eba..00000000 --- a/src/pinentry/argparse.h +++ /dev/null @@ -1,204 +0,0 @@ -/* argparse.h - Argument parser for option handling. - * Copyright (C) 1998,1999,2000,2001,2006 Free Software Foundation, Inc. - * - * This file is part of JNLIB, which is a subsystem of GnuPG. - * - * JNLIB is free software; you can redistribute it and/or modify it - * under the terms of either - * - * - the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at - * your option) any later version. - * - * or - * - * - the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * or both in parallel, as here. - * - * JNLIB is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copies of the GNU General Public License - * and the GNU Lesser General Public License along with this program; - * if not, see <https://www.gnu.org/licenses/>. - * SPDX-License-Identifier: (GPL-2.0+ OR LGPL-3.0+) - */ - -#ifndef LIBJNLIB_ARGPARSE_H -#define LIBJNLIB_ARGPARSE_H - -#include <stdio.h> - -typedef struct -{ - int *argc; /* Pointer to ARGC (value subject to change). */ - char ***argv; /* Pointer to ARGV (value subject to change). */ - unsigned int flags; /* Global flags. May be set prior to calling the - parser. The parser may change the value. */ - int err; /* Print error description for last option. - Either 0, ARGPARSE_PRINT_WARNING or - ARGPARSE_PRINT_ERROR. */ - - int r_opt; /* Returns option code. */ - int r_type; /* Returns type of option value. */ - union { - int ret_int; - long ret_long; - unsigned long ret_ulong; - char *ret_str; - } r; /* Return values */ - - struct { - int idx; - int inarg; - int stopped; - const char *last; - void *aliases; - const void *cur_alias; - void *iio_list; - } internal; /* Private - do not change. */ -} ARGPARSE_ARGS; - -typedef struct -{ - int short_opt; - const char *long_opt; - unsigned int flags; - const char *description; /* Optional option description. */ -} ARGPARSE_OPTS; - - -/* Global flags (ARGPARSE_ARGS). */ -#define ARGPARSE_FLAG_KEEP 1 /* Do not remove options form argv. */ -#define ARGPARSE_FLAG_ALL 2 /* Do not stop at last option but return - remaining args with R_OPT set to -1. */ -#define ARGPARSE_FLAG_MIXED 4 /* Assume options and args are mixed. */ -#define ARGPARSE_FLAG_NOSTOP 8 /* Do not stop processing at "--". */ -#define ARGPARSE_FLAG_ARG0 16 /* Do not skip the first arg. */ -#define ARGPARSE_FLAG_ONEDASH 32 /* Allow long options with one dash. */ -#define ARGPARSE_FLAG_NOVERSION 64 /* No output for "--version". */ - -#define ARGPARSE_FLAG_STOP_SEEN 256 /* Set to true if a "--" has been seen. */ - -/* Flags for each option (ARGPARSE_OPTS). The type code may be - ORed with the OPT flags. */ -#define ARGPARSE_TYPE_NONE 0 /* Does not take an argument. */ -#define ARGPARSE_TYPE_INT 1 /* Takes an int argument. */ -#define ARGPARSE_TYPE_STRING 2 /* Takes a string argument. */ -#define ARGPARSE_TYPE_LONG 3 /* Takes a long argument. */ -#define ARGPARSE_TYPE_ULONG 4 /* Takes an unsigned long argument. */ -#define ARGPARSE_OPT_OPTIONAL (1<<3) /* Argument is optional. */ -#define ARGPARSE_OPT_PREFIX (1<<4) /* Allow 0x etc. prefixed values. */ -#define ARGPARSE_OPT_IGNORE (1<<6) /* Ignore command or option. */ -#define ARGPARSE_OPT_COMMAND (1<<7) /* The argument is a command. */ - -#define ARGPARSE_TYPE_MASK 7 /* Mask for the type values (internal). */ - -/* A set of macros to make option definitions easier to read. */ -#define ARGPARSE_x(s,l,t,f,d) \ - { (s), (l), ARGPARSE_TYPE_ ## t | (f), (d) } - -#define ARGPARSE_s(s,l,t,d) \ - { (s), (l), ARGPARSE_TYPE_ ## t, (d) } -#define ARGPARSE_s_n(s,l,d) \ - { (s), (l), ARGPARSE_TYPE_NONE, (d) } -#define ARGPARSE_s_i(s,l,d) \ - { (s), (l), ARGPARSE_TYPE_INT, (d) } -#define ARGPARSE_s_s(s,l,d) \ - { (s), (l), ARGPARSE_TYPE_STRING, (d) } -#define ARGPARSE_s_l(s,l,d) \ - { (s), (l), ARGPARSE_TYPE_LONG, (d) } -#define ARGPARSE_s_u(s,l,d) \ - { (s), (l), ARGPARSE_TYPE_ULONG, (d) } - -#define ARGPARSE_o(s,l,t,d) \ - { (s), (l), (ARGPARSE_TYPE_ ## t | ARGPARSE_OPT_OPTIONAL), (d) } -#define ARGPARSE_o_n(s,l,d) \ - { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_OPTIONAL), (d) } -#define ARGPARSE_o_i(s,l,d) \ - { (s), (l), (ARGPARSE_TYPE_INT | ARGPARSE_OPT_OPTIONAL), (d) } -#define ARGPARSE_o_s(s,l,d) \ - { (s), (l), (ARGPARSE_TYPE_STRING | ARGPARSE_OPT_OPTIONAL), (d) } -#define ARGPARSE_o_l(s,l,d) \ - { (s), (l), (ARGPARSE_TYPE_LONG | ARGPARSE_OPT_OPTIONAL), (d) } -#define ARGPARSE_o_u(s,l,d) \ - { (s), (l), (ARGPARSE_TYPE_ULONG | ARGPARSE_OPT_OPTIONAL), (d) } - -#define ARGPARSE_p(s,l,t,d) \ - { (s), (l), (ARGPARSE_TYPE_ ## t | ARGPARSE_OPT_PREFIX), (d) } -#define ARGPARSE_p_n(s,l,d) \ - { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_PREFIX), (d) } -#define ARGPARSE_p_i(s,l,d) \ - { (s), (l), (ARGPARSE_TYPE_INT | ARGPARSE_OPT_PREFIX), (d) } -#define ARGPARSE_p_s(s,l,d) \ - { (s), (l), (ARGPARSE_TYPE_STRING | ARGPARSE_OPT_PREFIX), (d) } -#define ARGPARSE_p_l(s,l,d) \ - { (s), (l), (ARGPARSE_TYPE_LONG | ARGPARSE_OPT_PREFIX), (d) } -#define ARGPARSE_p_u(s,l,d) \ - { (s), (l), (ARGPARSE_TYPE_ULONG | ARGPARSE_OPT_PREFIX), (d) } - -#define ARGPARSE_op(s,l,t,d) \ - { (s), (l), (ARGPARSE_TYPE_ ## t \ - | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } -#define ARGPARSE_op_n(s,l,d) \ - { (s), (l), (ARGPARSE_TYPE_NONE \ - | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } -#define ARGPARSE_op_i(s,l,d) \ - { (s), (l), (ARGPARSE_TYPE_INT \ - | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } -#define ARGPARSE_op_s(s,l,d) \ - { (s), (l), (ARGPARSE_TYPE_STRING \ - | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } -#define ARGPARSE_op_l(s,l,d) \ - { (s), (l), (ARGPARSE_TYPE_LONG \ - | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } -#define ARGPARSE_op_u(s,l,d) \ - { (s), (l), (ARGPARSE_TYPE_ULONG \ - | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) } - -#define ARGPARSE_c(s,l,d) \ - { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_COMMAND), (d) } - -#define ARGPARSE_ignore(s,l) \ - { (s), (l), (ARGPARSE_OPT_IGNORE), "@" } - -#define ARGPARSE_group(s,d) \ - { (s), NULL, 0, (d) } - -#define ARGPARSE_end() { 0, NULL, 0, NULL } - - -/* Other constants. */ -#define ARGPARSE_PRINT_WARNING 1 -#define ARGPARSE_PRINT_ERROR 2 - - -/* Error values. */ -#define ARGPARSE_IS_ARG (-1) -#define ARGPARSE_INVALID_OPTION (-2) -#define ARGPARSE_MISSING_ARG (-3) -#define ARGPARSE_KEYWORD_TOO_LONG (-4) -#define ARGPARSE_READ_ERROR (-5) -#define ARGPARSE_UNEXPECTED_ARG (-6) -#define ARGPARSE_INVALID_COMMAND (-7) -#define ARGPARSE_AMBIGUOUS_OPTION (-8) -#define ARGPARSE_AMBIGUOUS_COMMAND (-9) -#define ARGPARSE_INVALID_ALIAS (-10) -#define ARGPARSE_OUT_OF_CORE (-11) -#define ARGPARSE_INVALID_ARG (-12) - - -int arg_parse (ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts); -int optfile_parse (FILE *fp, const char *filename, unsigned *lineno, - ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts); -void usage (int level); -const char *strusage (int level); -void set_strusage (const char *(*f)( int )); -void argparse_register_outfnc (int (*fnc)(int, const char *)); - -#endif /*LIBJNLIB_ARGPARSE_H*/ diff --git a/src/pinentry/capslock/capslock.cpp b/src/pinentry/capslock/capslock.cpp index 3ff0b779..a730c220 100644 --- a/src/pinentry/capslock/capslock.cpp +++ b/src/pinentry/capslock/capslock.cpp @@ -18,10 +18,6 @@ * SPDX-License-Identifier: GPL-2.0+ */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #include <QDebug> #include <QGuiApplication> diff --git a/src/pinentry/password_cache.cpp b/src/pinentry/password_cache.cpp deleted file mode 100644 index b52602d7..00000000 --- a/src/pinentry/password_cache.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/* password-cache.c - Password cache support. - Copyright (C) 2015 g10 Code GmbH - - This file is part of PINENTRY. - - PINENTRY is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - PINENTRY is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see <https://www.gnu.org/licenses/>. - SPDX-License-Identifier: GPL-2.0+ - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#ifdef HAVE_LIBSECRET -#include <libsecret/secret.h> -#endif - -#include "password_cache.h" -#include "secmem.h" - -#ifdef HAVE_LIBSECRET -static const SecretSchema *gpg_schema(void) { - static const SecretSchema the_schema = { - "org.gnupg.Passphrase", - SECRET_SCHEMA_NONE, - { - {"stored-by", SECRET_SCHEMA_ATTRIBUTE_STRING}, - {"keygrip", SECRET_SCHEMA_ATTRIBUTE_STRING}, - {"NULL", 0}, - }}; - return &the_schema; -} - -static char *keygrip_to_label(const char *keygrip) { - char const prefix[] = "GnuPG: "; - char *label; - - label = malloc(sizeof(prefix) + strlen(keygrip)); - if (label) { - memcpy(label, prefix, sizeof(prefix) - 1); - strcpy(&label[sizeof(prefix) - 1], keygrip); - } - return label; -} -#endif - -void password_cache_save(const char *keygrip, const char *password) { -#ifdef HAVE_LIBSECRET - char *label; - GError *error = NULL; - - if (!*keygrip) return; - - label = keygrip_to_label(keygrip); - if (!label) return; - - if (!secret_password_store_sync(gpg_schema(), SECRET_COLLECTION_DEFAULT, - label, password, NULL, &error, "stored-by", - "GnuPG Pinentry", "keygrip", keygrip, NULL)) { - fprintf(stderr, - "Failed to cache password for key %s with secret service: %s\n", - keygrip, error->message); - - g_error_free(error); - } - - free(label); -#else - (void)keygrip; - (void)password; - return; -#endif -} - -char *password_cache_lookup(const char *keygrip, int *fatal_error) { -#ifdef HAVE_LIBSECRET - GError *error = NULL; - char *password; - char *password2; - - if (!*keygrip) return NULL; - - password = secret_password_lookup_nonpageable_sync(gpg_schema(), NULL, &error, - "keygrip", keygrip, NULL); - - if (error != NULL) { - if (fatal_error) *fatal_error = 1; - - fprintf(stderr, - "Failed to lookup password for key %s with secret service: %s\n", - keygrip, error->message); - g_error_free(error); - return NULL; - } - if (!password) - /* The password for this key is not cached. Just return NULL. */ - return NULL; - - /* The password needs to be returned in secmem allocated memory. */ - password2 = secmem_malloc(strlen(password) + 1); - if (password2) - strcpy(password2, password); - else - fprintf(stderr, "secmem_malloc failed: can't copy password!\n"); - - secret_password_free(password); - - return password2; -#else - (void)keygrip; - (void)fatal_error; - return NULL; -#endif -} - -/* Try and remove the cached password for key grip. Returns -1 on - error, 0 if the key is not found and 1 if the password was - removed. */ -int password_cache_clear(const char *keygrip) { -#ifdef HAVE_LIBSECRET - GError *error = NULL; - int removed = secret_password_clear_sync(gpg_schema(), NULL, &error, - "keygrip", keygrip, NULL); - if (error != NULL) { - fprintf(stderr, - "Failed to clear password for key %s with secret service: %s\n", - keygrip, error->message); - g_debug("%s", error->message); - g_error_free(error); - return -1; - } - if (removed) return 1; - return 0; -#else - (void)keygrip; - return -1; -#endif -} diff --git a/src/pinentry/password_cache.h b/src/pinentry/password_cache.h deleted file mode 100644 index cdba356d..00000000 --- a/src/pinentry/password_cache.h +++ /dev/null @@ -1,30 +0,0 @@ -/* password_cache.h - Password cache support interfaces. - Copyright (C) 2015 g10 Code GmbH - - This file is part of PINENTRY. - - PINENTRY is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - PINENTRY is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see <https://www.gnu.org/licenses/>. - SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef PASSWORD_CACHE_H -#define PASSWORD_CACHE_H - -void password_cache_save(const char *key_grip, const char *password); - -char *password_cache_lookup(const char *key_grip, int *fatal_error); - -int password_cache_clear(const char *keygrip); - -#endif diff --git a/src/pinentry/pinentry.cpp b/src/pinentry/pinentry.cpp index 918944b9..79b2450b 100644 --- a/src/pinentry/pinentry.cpp +++ b/src/pinentry/pinentry.cpp @@ -44,10 +44,8 @@ #include <assuan.h> -#include "argparse.h" -#include "password_cache.h" +#include "core/utils/MemoryUtils.h" #include "pinentry.h" -#include "secmem_util.h" #ifdef WINDOWS #define getpid() GetCurrentProcessId() @@ -145,7 +143,7 @@ static void pinentry_reset(int use_defaults) { free(pinentry.ok); free(pinentry.notok); free(pinentry.cancel); - secmem_free(pinentry.pin); + GpgFrontend::SecureFree(pinentry.pin); free(pinentry.repeat_passphrase); free(pinentry.repeat_error_string); free(pinentry.quality_bar); @@ -415,12 +413,13 @@ int pinentry_inq_quality(pinentry_t pin, const char *passphrase, length = 300; /* Limit so that it definitely fits into an Assuan line. */ - command = (char *)secmem_malloc(strlen(prefix) + 3 * length + 1); + command = + GpgFrontend::SecureMallocAsType<char>(strlen(prefix) + 3 * length + 1); if (!command) return 0; strcpy(command, prefix); copy_and_escape(command + strlen(command), passphrase, length); rc = assuan_write_line(ctx, command); - secmem_free(command); + GpgFrontend::SecureFree(command); if (rc) { fprintf(stderr, "ASSUAN WRITE LINE failed: rc=%d\n", rc); return 0; @@ -473,12 +472,13 @@ char *pinentry_inq_checkpin(pinentry_t pin, const char *passphrase, length = 300; /* Limit so that it definitely fits into an Assuan line. */ - command = (char *)secmem_malloc(strlen(prefix) + 3 * length + 1); + command = + GpgFrontend::SecureMallocAsType<char>(strlen(prefix) + 3 * length + 1); if (!command) return 0; strcpy(command, prefix); copy_and_escape(command + strlen(command), passphrase, length); rc = assuan_write_line(ctx, command); - secmem_free(command); + GpgFrontend::SecureFree(command); if (rc) { fprintf(stderr, "ASSUAN WRITE LINE failed: rc=%d\n", rc); return 0; @@ -568,12 +568,12 @@ char *pinentry_setbufferlen(pinentry_t pin, int len) { if (len <= pin->pin_len) return pin->pin; - newp = (char *)secmem_realloc(pin->pin, len); + newp = GpgFrontend::SecureReallocAsType<char>(pin->pin, len); if (newp) { pin->pin = newp; pin->pin_len = len; } else { - secmem_free(pin->pin); + GpgFrontend::SecureFree(pin->pin); pin->pin = 0; pin->pin_len = 0; } @@ -588,7 +588,7 @@ static void pinentry_setbuffer_clear(pinentry_t pin) { assert(pin->pin_len > 0); - secmem_free(pin->pin); + GpgFrontend::SecureFree(pin->pin); pin->pin = NULL; pin->pin_len = 0; } @@ -609,14 +609,15 @@ void pinentry_setbuffer_use(pinentry_t pin, char *passphrase, int len) { if (passphrase && len == 0) len = strlen(passphrase) + 1; - if (pin->pin) secmem_free(pin->pin); + if (pin->pin) GpgFrontend::SecureFree(pin->pin); pin->pin = passphrase; pin->pin_len = len; } static struct assuan_malloc_hooks assuan_malloc_hooks = { - secmem_malloc, secmem_realloc, secmem_free}; + GpgFrontend::SecureMalloc, GpgFrontend::SecureRealloc, + GpgFrontend::SecureFree}; /* Initialize the secure memory subsystem, drop privileges and return. Must be called early. */ @@ -627,16 +628,6 @@ void pinentry_init(const char *pgmname) { gpgrt_check_version(NULL); - /* Initialize secure memory. 1 is too small, so the default size - will be used. */ - secmem_init(1); - secmem_set_flags(SECMEM_WARN); - drop_privs(); - - if (atexit(secmem_term)) { - /* FIXME: Could not register at-exit function, bail out. */ - } - assuan_set_malloc_hooks(&assuan_malloc_hooks); } @@ -772,131 +763,6 @@ char *parse_color(char *arg, pinentry_color_t *color_p, int *bright_p) { return new_arg; } -/* Parse the command line options. May exit the program if only help - or version output is requested. */ -void pinentry_parse_opts(int argc, char *argv[]) { - static ARGPARSE_OPTS opts[] = { - ARGPARSE_s_n('d', "debug", "Turn on debugging output"), - ARGPARSE_s_s('D', "display", "|DISPLAY|Set the X display"), - ARGPARSE_s_s('T', "ttyname", "|FILE|Set the tty terminal node name"), - ARGPARSE_s_s('N', "ttytype", "|NAME|Set the tty terminal type"), - ARGPARSE_s_s('C', "lc-ctype", "|STRING|Set the tty LC_CTYPE value"), - ARGPARSE_s_s('M', "lc-messages", "|STRING|Set the tty LC_MESSAGES value"), - ARGPARSE_s_i('o', "timeout", - "|SECS|Timeout waiting for input after this many seconds"), - ARGPARSE_s_n('g', "no-global-grab", - "Grab keyboard only while window is focused"), - ARGPARSE_s_u('W', "parent-wid", "Parent window ID (for positioning)"), - ARGPARSE_s_s('c', "colors", "|STRING|Set custom colors for ncurses"), - ARGPARSE_s_s('a', "ttyalert", - "|STRING|Set the alert mode (none, beep or flash)"), - ARGPARSE_end()}; - ARGPARSE_ARGS pargs = {&argc, &argv, 0}; - - set_strusage(my_strusage); - - pinentry_reset(1); - - while (arg_parse(&pargs, opts)) { - switch (pargs.r_opt) { - case 'd': - pinentry.debug = 1; - break; - case 'g': - pinentry.grab = 0; - break; - - case 'D': - /* Note, this is currently not used because the GUI engine - has already been initialized when parsing these options. */ - pinentry.display = strdup(pargs.r.ret_str); - if (!pinentry.display) { -#ifndef WINDOWS - fprintf(stderr, "%s: %s\n", this_pgmname, strerror(errno)); -#endif - exit(EXIT_FAILURE); - } - break; - case 'T': - pinentry.ttyname = strdup(pargs.r.ret_str); - if (!pinentry.ttyname) { -#ifndef WINDOWS - fprintf(stderr, "%s: %s\n", this_pgmname, strerror(errno)); -#endif - exit(EXIT_FAILURE); - } - break; - case 'N': - pinentry.ttytype_l = strdup(pargs.r.ret_str); - if (!pinentry.ttytype_l) { -#ifndef WINDOWS - fprintf(stderr, "%s: %s\n", this_pgmname, strerror(errno)); -#endif - exit(EXIT_FAILURE); - } - break; - case 'C': - pinentry.lc_ctype = strdup(pargs.r.ret_str); - if (!pinentry.lc_ctype) { -#ifndef WINDOWS - fprintf(stderr, "%s: %s\n", this_pgmname, strerror(errno)); -#endif - exit(EXIT_FAILURE); - } - break; - case 'M': - pinentry.lc_messages = strdup(pargs.r.ret_str); - if (!pinentry.lc_messages) { -#ifndef WINDOWS - fprintf(stderr, "%s: %s\n", this_pgmname, strerror(errno)); -#endif - exit(EXIT_FAILURE); - } - break; - case 'W': - pinentry.parent_wid = pargs.r.ret_ulong; - break; - - case 'c': { - char *tmpstr = pargs.r.ret_str; - - tmpstr = - parse_color(tmpstr, &pinentry.color_fg, &pinentry.color_fg_bright); - tmpstr = parse_color(tmpstr, &pinentry.color_bg, NULL); - tmpstr = - parse_color(tmpstr, &pinentry.color_so, &pinentry.color_so_bright); - tmpstr = - parse_color(tmpstr, &pinentry.color_ok, &pinentry.color_ok_bright); - tmpstr = parse_color(tmpstr, &pinentry.color_qualitybar, - &pinentry.color_qualitybar_bright); - } break; - - case 'o': - pinentry.timeout = pargs.r.ret_int; - break; - - case 'a': - pinentry.ttyalert = strdup(pargs.r.ret_str); - if (!pinentry.ttyalert) { -#ifndef WINDOWS - fprintf(stderr, "%s: %s\n", this_pgmname, strerror(errno)); -#endif - exit(EXIT_FAILURE); - } - break; - - default: - pargs.err = ARGPARSE_PRINT_WARNING; - break; - } - } - - if (!pinentry.display && remember_display) { - pinentry.display = remember_display; - remember_display = NULL; - } -} - /* Set the optional flag used with getinfo. */ void pinentry_set_flavor_flag(const char *string) { flavor_flag = string; } @@ -1073,425 +939,6 @@ static void write_status_error(assuan_context_t ctx, pinentry_t pe) { assuan_write_status(ctx, "ERROR", buf); } -static gpg_error_t cmd_setdesc(assuan_context_t ctx, char *line) { - char *newd; - - (void)ctx; - - newd = (char *)malloc(strlen(line) + 1); - if (!newd) return gpg_error_from_syserror(); - - strcpy_escaped(newd, line); - if (pinentry.description) free(pinentry.description); - pinentry.description = newd; - return 0; -} - -static gpg_error_t cmd_setprompt(assuan_context_t ctx, char *line) { - char *newp; - - (void)ctx; - - newp = (char *)malloc(strlen(line) + 1); - if (!newp) return gpg_error_from_syserror(); - - strcpy_escaped(newp, line); - if (pinentry.prompt) free(pinentry.prompt); - pinentry.prompt = newp; - return 0; -} - -/* The data provided at LINE may be used by pinentry implementations - to identify a key for caching strategies of its own. The empty - string and --clear mean that the key does not have a stable - identifier. */ -static gpg_error_t cmd_setkeyinfo(assuan_context_t ctx, char *line) { - (void)ctx; - - if (pinentry.keyinfo) free(pinentry.keyinfo); - - if (*line && strcmp(line, "--clear") != 0) - pinentry.keyinfo = strdup(line); - else - pinentry.keyinfo = NULL; - - return 0; -} - -static gpg_error_t cmd_setrepeat(assuan_context_t ctx, char *line) { - char *p; - - (void)ctx; - - p = (char *)malloc(strlen(line) + 1); - if (!p) return gpg_error_from_syserror(); - - strcpy_escaped(p, line); - free(pinentry.repeat_passphrase); - pinentry.repeat_passphrase = p; - return 0; -} - -static gpg_error_t cmd_setrepeatok(assuan_context_t ctx, char *line) { - char *p; - - (void)ctx; - - p = (char *)malloc(strlen(line) + 1); - if (!p) return gpg_error_from_syserror(); - - strcpy_escaped(p, line); - free(pinentry.repeat_ok_string); - pinentry.repeat_ok_string = p; - return 0; -} - -static gpg_error_t cmd_setrepeaterror(assuan_context_t ctx, char *line) { - char *p; - - (void)ctx; - - p = (char *)malloc(strlen(line) + 1); - if (!p) return gpg_error_from_syserror(); - - strcpy_escaped(p, line); - free(pinentry.repeat_error_string); - pinentry.repeat_error_string = p; - return 0; -} - -static gpg_error_t cmd_seterror(assuan_context_t ctx, char *line) { - char *newe; - - (void)ctx; - - newe = (char *)malloc(strlen(line) + 1); - if (!newe) return gpg_error_from_syserror(); - - strcpy_escaped(newe, line); - if (pinentry.error) free(pinentry.error); - pinentry.error = newe; - return 0; -} - -static gpg_error_t cmd_setok(assuan_context_t ctx, char *line) { - char *newo; - - (void)ctx; - - newo = (char *)malloc(strlen(line) + 1); - if (!newo) return gpg_error_from_syserror(); - - strcpy_escaped(newo, line); - if (pinentry.ok) free(pinentry.ok); - pinentry.ok = newo; - return 0; -} - -static gpg_error_t cmd_setnotok(assuan_context_t ctx, char *line) { - char *newo; - - (void)ctx; - - newo = (char *)malloc(strlen(line) + 1); - if (!newo) return gpg_error_from_syserror(); - - strcpy_escaped(newo, line); - if (pinentry.notok) free(pinentry.notok); - pinentry.notok = newo; - return 0; -} - -static gpg_error_t cmd_setcancel(assuan_context_t ctx, char *line) { - char *newc; - - (void)ctx; - - newc = (char *)malloc(strlen(line) + 1); - if (!newc) return gpg_error_from_syserror(); - - strcpy_escaped(newc, line); - if (pinentry.cancel) free(pinentry.cancel); - pinentry.cancel = newc; - return 0; -} - -static gpg_error_t cmd_settimeout(assuan_context_t ctx, char *line) { - (void)ctx; - - if (line && *line) pinentry.timeout = atoi(line); - - return 0; -} - -static gpg_error_t cmd_settitle(assuan_context_t ctx, char *line) { - char *newt; - - (void)ctx; - - newt = (char *)malloc(strlen(line) + 1); - if (!newt) return gpg_error_from_syserror(); - - strcpy_escaped(newt, line); - if (pinentry.title) free(pinentry.title); - pinentry.title = newt; - return 0; -} - -static gpg_error_t cmd_setqualitybar(assuan_context_t ctx, char *line) { - char *newval; - - (void)ctx; - - if (!*line) line = "Quality:"; - - newval = (char *)malloc(strlen(line) + 1); - if (!newval) return gpg_error_from_syserror(); - - strcpy_escaped(newval, line); - if (pinentry.quality_bar) free(pinentry.quality_bar); - pinentry.quality_bar = newval; - return 0; -} - -/* Set the tooltip to be used for a quality bar. */ -static gpg_error_t cmd_setqualitybar_tt(assuan_context_t ctx, char *line) { - char *newval; - - (void)ctx; - - if (*line) { - newval = (char *)malloc(strlen(line) + 1); - if (!newval) return gpg_error_from_syserror(); - - strcpy_escaped(newval, line); - } else - newval = NULL; - if (pinentry.quality_bar_tt) free(pinentry.quality_bar_tt); - pinentry.quality_bar_tt = newval; - return 0; -} - -/* Set the tooltip to be used for a generate action. */ -static gpg_error_t cmd_setgenpin_tt(assuan_context_t ctx, char *line) { - char *newval; - - (void)ctx; - - if (*line) { - newval = (char *)malloc(strlen(line) + 1); - if (!newval) return gpg_error_from_syserror(); - - strcpy_escaped(newval, line); - } else - newval = NULL; - if (pinentry.genpin_tt) free(pinentry.genpin_tt); - pinentry.genpin_tt = newval; - return 0; -} - -/* Set the label to be used for a generate action. */ -static gpg_error_t cmd_setgenpin_label(assuan_context_t ctx, char *line) { - char *newval; - - (void)ctx; - - if (*line) { - newval = (char *)malloc(strlen(line) + 1); - if (!newval) return gpg_error_from_syserror(); - - strcpy_escaped(newval, line); - } else - newval = NULL; - if (pinentry.genpin_label) free(pinentry.genpin_label); - pinentry.genpin_label = newval; - return 0; -} - -static gpg_error_t cmd_getpin(assuan_context_t ctx, char *line) { - int result; - int set_prompt = 0; - int just_read_password_from_cache = 0; - - (void)line; - - pinentry_setbuffer_init(&pinentry); - if (!pinentry.pin) return gpg_error(GPG_ERR_ENOMEM); - - pinentry.confirm = 0; - - /* Try reading from the password cache. */ - if (/* If repeat passphrase is set, then we don't want to read from - the cache. */ - !pinentry.repeat_passphrase - /* Are we allowed to read from the cache? */ - && pinentry.allow_external_password_cache && - pinentry.keyinfo - /* Only read from the cache if we haven't already tried it. */ - && !pinentry.tried_password_cache - /* If the last read resulted in an error, then don't read from - the cache. */ - && !pinentry.error) { - char *password; - int give_up_on_password_store = 0; - - pinentry.tried_password_cache = 1; - - password = - password_cache_lookup(pinentry.keyinfo, &give_up_on_password_store); - if (give_up_on_password_store) pinentry.allow_external_password_cache = 0; - - if (password) - /* There is a cached password. Try it. */ - { - int len = strlen(password) + 1; - if (len > pinentry.pin_len) len = pinentry.pin_len; - - memcpy(pinentry.pin, password, len); - pinentry.pin[len] = '\0'; - - secmem_free(password); - - pinentry.pin_from_cache = 1; - - assuan_write_status(ctx, "PASSWORD_FROM_CACHE", ""); - - /* Result is the length of the password not including the - NUL terminator. */ - result = len - 1; - - just_read_password_from_cache = 1; - - goto out; - } - } - - /* The password was not cached (or we are not allowed to / cannot - use the cache). Prompt the user. */ - pinentry.pin_from_cache = 0; - - if (!pinentry.prompt) { - pinentry.prompt = const_cast<char *>( - pinentry.default_prompt ? pinentry.default_prompt : "PIN:"); - set_prompt = 1; - } - pinentry.locale_err = 0; - pinentry.specific_err = 0; - pinentry.specific_err_loc = NULL; - free(pinentry.specific_err_info); - pinentry.specific_err_info = NULL; - pinentry.close_button = 0; - pinentry.repeat_okay = 0; - pinentry.one_button = 0; - pinentry.ctx_assuan = ctx; - result = (*pinentry_cmd_handler)(&pinentry); - pinentry.ctx_assuan = NULL; - if (pinentry.error) { - free(pinentry.error); - pinentry.error = NULL; - } - if (pinentry.repeat_passphrase) { - free(pinentry.repeat_passphrase); - pinentry.repeat_passphrase = NULL; - } - if (set_prompt) pinentry.prompt = NULL; - - pinentry.quality_bar = 0; /* Reset it after the command. */ - - if (pinentry.close_button) assuan_write_status(ctx, "BUTTON_INFO", "close"); - - if (result < 0) { - pinentry_setbuffer_clear(&pinentry); - if (pinentry.specific_err) { - write_status_error(ctx, &pinentry); - - if (gpg_err_code(pinentry.specific_err) == GPG_ERR_FULLY_CANCELED) - assuan_set_flag(ctx, ASSUAN_FORCE_CLOSE, 1); - - return pinentry.specific_err; - } - return (pinentry.locale_err ? gpg_error(GPG_ERR_LOCALE_PROBLEM) - : gpg_error(GPG_ERR_CANCELED)); - } - -out: - if (result) { - if (pinentry.repeat_okay) assuan_write_status(ctx, "PIN_REPEATED", ""); - assuan_begin_confidential(ctx); - result = assuan_send_data(ctx, pinentry.pin, strlen(pinentry.pin)); - if (!result) result = assuan_send_data(ctx, NULL, 0); - assuan_end_confidential(ctx); - - if (/* GPG Agent says it's okay. */ - pinentry.allow_external_password_cache && - pinentry.keyinfo - /* We didn't just read it from the cache. */ - && !just_read_password_from_cache - /* And the user said it's okay. */ - && pinentry.may_cache_password) - /* Cache the password. */ - password_cache_save(pinentry.keyinfo, pinentry.pin); - } - - pinentry_setbuffer_clear(&pinentry); - - return result; -} - -/* Note that the option --one-button is a hack to allow the use of old - pinentries while the caller is ignoring the result. Given that - options have never been used or flagged as an error the new option - is an easy way to enable the messsage mode while not requiring to - update pinentry or to have the caller test for the message - command. New applications which are free to require an updated - pinentry should use MESSAGE instead. */ -static gpg_error_t cmd_confirm(assuan_context_t ctx, char *line) { - int result; - - pinentry.one_button = !!strstr(line, "--one-button"); - pinentry.quality_bar = 0; - pinentry.close_button = 0; - pinentry.locale_err = 0; - pinentry.specific_err = 0; - pinentry.specific_err_loc = NULL; - free(pinentry.specific_err_info); - pinentry.specific_err_info = NULL; - pinentry.canceled = 0; - pinentry.confirm = 1; - pinentry_setbuffer_clear(&pinentry); - result = (*pinentry_cmd_handler)(&pinentry); - if (pinentry.error) { - free(pinentry.error); - pinentry.error = NULL; - } - - if (pinentry.close_button) assuan_write_status(ctx, "BUTTON_INFO", "close"); - - if (result > 0) return 0; /* OK */ - - if (pinentry.specific_err) { - write_status_error(ctx, &pinentry); - - if (gpg_err_code(pinentry.specific_err) == GPG_ERR_FULLY_CANCELED) - assuan_set_flag(ctx, ASSUAN_FORCE_CLOSE, 1); - - return pinentry.specific_err; - } - - if (pinentry.locale_err) return gpg_error(GPG_ERR_LOCALE_PROBLEM); - - if (pinentry.one_button) return 0; /* OK */ - - if (pinentry.canceled) return gpg_error(GPG_ERR_CANCELED); - return gpg_error(GPG_ERR_NOT_CONFIRMED); -} - -static gpg_error_t cmd_message(assuan_context_t ctx, char *line) { - (void)line; - - return cmd_confirm(ctx, "--one-button"); -} - /* Return a staically allocated string with information on the mode, * uid, and gid of DEVICE. On error "?" is returned if DEVICE is * NULL, "-" is returned. */ @@ -1565,132 +1012,4 @@ static gpg_error_t cmd_getinfo(assuan_context_t ctx, char *line) { } else rc = gpg_error(GPG_ERR_ASS_PARAMETER); return rc; -} - -/* CLEARPASSPHRASE <cacheid> - - Clear the cache passphrase associated with the key identified by - cacheid. - */ -static gpg_error_t cmd_clear_passphrase(assuan_context_t ctx, char *line) { - (void)ctx; - - if (!line) return gpg_error(GPG_ERR_ASS_INV_VALUE); - - /* Remove leading and trailing white space. */ - while (*line == ' ') line++; - while (line[strlen(line) - 1] == ' ') line[strlen(line) - 1] = 0; - - switch (password_cache_clear(line)) { - case 1: - return 0; - case 0: - return gpg_error(GPG_ERR_ASS_INV_VALUE); - default: - return gpg_error(GPG_ERR_ASS_GENERAL); - } -} - -/* Tell the assuan library about our commands. */ -static gpg_error_t register_commands(assuan_context_t ctx) { - static struct { - const char *name; - gpg_error_t (*handler)(assuan_context_t, char *line); - } table[] = {{"SETDESC", cmd_setdesc}, - {"SETPROMPT", cmd_setprompt}, - {"SETKEYINFO", cmd_setkeyinfo}, - {"SETREPEAT", cmd_setrepeat}, - {"SETREPEATERROR", cmd_setrepeaterror}, - {"SETREPEATOK", cmd_setrepeatok}, - {"SETERROR", cmd_seterror}, - {"SETOK", cmd_setok}, - {"SETNOTOK", cmd_setnotok}, - {"SETCANCEL", cmd_setcancel}, - {"GETPIN", cmd_getpin}, - {"CONFIRM", cmd_confirm}, - {"MESSAGE", cmd_message}, - {"SETQUALITYBAR", cmd_setqualitybar}, - {"SETQUALITYBAR_TT", cmd_setqualitybar_tt}, - {"SETGENPIN", cmd_setgenpin_label}, - {"SETGENPIN_TT", cmd_setgenpin_tt}, - {"GETINFO", cmd_getinfo}, - {"SETTITLE", cmd_settitle}, - {"SETTIMEOUT", cmd_settimeout}, - {"CLEARPASSPHRASE", cmd_clear_passphrase}, - {NULL}}; - int i, j; - gpg_error_t rc; - - for (i = j = 0; table[i].name; i++) { - rc = assuan_register_command(ctx, table[i].name, table[i].handler, NULL); - if (rc) return rc; - } - return 0; -} - -int pinentry_loop2(int infd, int outfd) { - gpg_error_t rc; - assuan_fd_t filedes[2]; - assuan_context_t ctx; - - /* Extra check to make sure we have dropped privs. */ -#ifndef HAVE_DOSISH_SYSTEM - if (getuid() != geteuid()) abort(); -#endif - - rc = assuan_new(&ctx); - if (rc) { - fprintf(stderr, "server context creation failed: %s\n", gpg_strerror(rc)); - return -1; - } - - /* For now we use a simple pipe based server so that we can work - from scripts. We will later add options to run as a daemon and - wait for requests on a Unix domain socket. */ - filedes[0] = assuan_fdopen(infd); - filedes[1] = assuan_fdopen(outfd); - rc = assuan_init_pipe_server(ctx, filedes); - if (rc) { - fprintf(stderr, "%s: failed to initialize the server: %s\n", this_pgmname, - gpg_strerror(rc)); - return -1; - } - rc = register_commands(ctx); - if (rc) { - fprintf(stderr, "%s: failed to the register commands with Assuan: %s\n", - this_pgmname, gpg_strerror(rc)); - return -1; - } - - assuan_register_option_handler(ctx, option_handler); -#if 0 - assuan_set_log_stream (ctx, stderr); -#endif - assuan_register_reset_notify(ctx, pinentry_assuan_reset_handler); - - for (;;) { - rc = assuan_accept(ctx); - if (rc == -1) - break; - else if (rc) { - fprintf(stderr, "%s: Assuan accept problem: %s\n", this_pgmname, - gpg_strerror(rc)); - break; - } - - rc = assuan_process(ctx); - if (rc) { - fprintf(stderr, "%s: Assuan processing failed: %s\n", this_pgmname, - gpg_strerror(rc)); - continue; - } - } - - assuan_release(ctx); - return 0; -} - -/* Start the pinentry event loop. The program will start to process - Assuan commands until it is finished or an error occurs. If an - error occurs, -1 is returned. Otherwise, 0 is returned. */ -int pinentry_loop(void) { return pinentry_loop2(STDIN_FILENO, STDOUT_FILENO); } +}
\ No newline at end of file diff --git a/src/pinentry/pinentry.h b/src/pinentry/pinentry.h index aec01946..0c91a24e 100644 --- a/src/pinentry/pinentry.h +++ b/src/pinentry/pinentry.h @@ -21,7 +21,7 @@ #ifndef PINENTRY_H #define PINENTRY_H -#include "secmem.h" +#include <cstdint> #ifdef __cplusplus extern "C" { @@ -298,30 +298,19 @@ typedef struct pinentry *pinentry_t; and 1 otherwise. */ typedef int (*pinentry_cmd_handler_t)(pinentry_t pin); -/* Start the pinentry event loop. The program will start to process - Assuan commands until it is finished or an error occurs. If an - error occurs, -1 is returned and errno indicates the type of an - error. Otherwise, 0 is returned. */ -int pinentry_loop(void); - -/* The same as above but allows to specify the i/o descriptors. - * infd and outfd will be duplicated in this function so the caller - * still has to close them if necessary. - */ -int pinentry_loop2(int infd, int outfd); - const char *pinentry_get_pgmname(void); char *pinentry_get_title(pinentry_t pe); /* Run a quality inquiry for PASSPHRASE of LENGTH. */ -int pinentry_inq_quality(pinentry_t pin, const char *passphrase, size_t length); +int pinentry_inq_quality(pinentry_t pin, const char *passphrase, + std::size_t length); /* Run a checkpin inquiry for PASSPHRASE of LENGTH. Returns NULL, if the passphrase satisfies the constraints. Otherwise, returns a malloced error string. */ char *pinentry_inq_checkpin(pinentry_t pin, const char *passphrase, - size_t length); + std::size_t length); /* Run a genpin iquriry. Returns a malloced string or NULL */ char *pinentry_inq_genpin(pinentry_t pin); @@ -351,9 +340,6 @@ void pinentry_parse_opts(int argc, char *argv[]); /* Set the optional flag used with getinfo. */ void pinentry_set_flavor_flag(const char *string); -/* The caller must define this variable to process assuan commands. */ -extern pinentry_cmd_handler_t pinentry_cmd_handler; - #ifdef WINDOWS /* Windows declares sleep as obsolete, but provides a definition for _sleep but non for the still existing sleep. */ diff --git a/src/pinentry/pinentry_main.cpp b/src/pinentry/pinentry_main.cpp deleted file mode 100644 index fcea7c31..00000000 --- a/src/pinentry/pinentry_main.cpp +++ /dev/null @@ -1,413 +0,0 @@ -/* main.cpp - A Qt dialog for PIN entry. - * Copyright (C) 2002, 2008 Klarälvdalens Datakonsult AB (KDAB) - * Copyright (C) 2003, 2021 g10 Code GmbH - * Copyright 2007 Ingo Klöcker - * - * Written by Steffen Hansen <[email protected]>. - * Modified by Marcus Brinkmann <[email protected]>. - * Modified by Marc Mutz <[email protected]> - * Software engineering by Ingo Klöcker <[email protected]> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <https://www.gnu.org/licenses/>. - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <QApplication> -#include <QDebug> -#include <QIcon> -#include <QMessageBox> -#include <QPushButton> -#include <QString> -#include <QWidget> - -#include "accessibility.h" -#include "keyboardfocusindication.h" -#include "pinentry.h" -#include "pinentryconfirm.h" -#include "pinentrydialog.h" -#include "util.h" -#if QT_VERSION >= 0x050000 -#include <QWindow> -#endif - -#include <errno.h> -#include <gpg-error.h> -#include <stdio.h> - -#include <stdexcept> - -#ifdef FALLBACK_CURSES -#include <pinentry-curses.h> -#endif - -#if QT_VERSION >= 0x050000 && defined(QT_STATIC) -#include <QtPlugin> -#ifdef Q_OS_WIN -#include <shlobj.h> -#include <windows.h> -Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin) -#elif defined(Q_OS_MAC) -Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin) -#else -Q_IMPORT_PLUGIN(QXcbIntegrationPlugin) -#endif -#endif - -#ifdef Q_OS_WIN -#include <windows.h> -#endif - -#include "pinentry_debug.h" - -static QString escape_accel(const QString &s) { - QString result; - result.reserve(s.size()); - - bool afterUnderscore = false; - - for (unsigned int i = 0, end = s.size(); i != end; ++i) { - const QChar ch = s[i]; - if (ch == QLatin1Char('_')) { - if (afterUnderscore) { // escaped _ - result += QLatin1Char('_'); - afterUnderscore = false; - } else { // accel - afterUnderscore = true; - } - } else { - if (afterUnderscore || // accel - ch == QLatin1Char('&')) { // escape & from being interpreted by Qt - result += QLatin1Char('&'); - } - result += ch; - afterUnderscore = false; - } - } - - if (afterUnderscore) - // trailing single underscore: shouldn't happen, but deal with it robustly: - { - result += QLatin1Char('_'); - } - - return result; -} - -namespace { -class InvalidUtf8 : public std::invalid_argument { - public: - InvalidUtf8() : std::invalid_argument("invalid utf8") {} - ~InvalidUtf8() throw() {} -}; -} // namespace - -static const bool GPG_AGENT_IS_PORTED_TO_ONLY_SEND_UTF8 = false; - -static QString from_utf8(const char *s) { - const QString result = QString::fromUtf8(s); - if (result.contains(QChar::ReplacementCharacter)) { - if (GPG_AGENT_IS_PORTED_TO_ONLY_SEND_UTF8) { - throw InvalidUtf8(); - } else { - return QString::fromLocal8Bit(s); - } - } - - return result; -} - -static void setup_foreground_window(QWidget *widget, WId parentWid) { -#if QT_VERSION >= 0x050000 - /* For windows set the desktop window as the transient parent */ - QWindow *parentWindow = nullptr; - if (parentWid) { - parentWindow = QWindow::fromWinId(parentWid); - } -#ifdef Q_OS_WIN - if (!parentWindow) { - HWND desktop = GetDesktopWindow(); - if (desktop) { - parentWindow = QWindow::fromWinId((WId)desktop); - } - } -#endif - if (parentWindow) { - // Ensure that we have a native wid - widget->winId(); - QWindow *wndHandle = widget->windowHandle(); - - if (wndHandle) { - wndHandle->setTransientParent(parentWindow); - } - } -#endif - widget->setWindowFlags(Qt::Window | Qt::CustomizeWindowHint | - Qt::WindowTitleHint | Qt::WindowCloseButtonHint | - Qt::WindowStaysOnTopHint | - Qt::WindowMinimizeButtonHint); -} - -static int qt_cmd_handler(pinentry_t pe) { - int want_pass = !!pe->pin; - - const QString ok = pe->ok ? escape_accel(from_utf8(pe->ok)) - : pe->default_ok ? escape_accel(from_utf8(pe->default_ok)) - : - /* else */ QLatin1String("&OK"); - const QString cancel = pe->cancel ? escape_accel(from_utf8(pe->cancel)) - : pe->default_cancel - ? escape_accel(from_utf8(pe->default_cancel)) - : - /* else */ QLatin1String("&Cancel"); - - unique_malloced_ptr<char> str{pinentry_get_title(pe)}; - const QString title = str ? from_utf8(str.get()) : - /* else */ QLatin1String("pinentry-qt"); - - const QString repeatError = pe->repeat_error_string - ? from_utf8(pe->repeat_error_string) - : QLatin1String("Passphrases do not match"); - const QString repeatString = - pe->repeat_passphrase ? from_utf8(pe->repeat_passphrase) : QString(); - const QString visibilityTT = pe->default_tt_visi - ? from_utf8(pe->default_tt_visi) - : QLatin1String("Show passphrase"); - const QString hideTT = pe->default_tt_hide ? from_utf8(pe->default_tt_hide) - : QLatin1String("Hide passphrase"); - - const QString capsLockHint = pe->default_capshint - ? from_utf8(pe->default_capshint) - : QLatin1String("Caps Lock is on"); - - const QString generateLbl = - pe->genpin_label ? from_utf8(pe->genpin_label) : QString(); - const QString generateTT = - pe->genpin_tt ? from_utf8(pe->genpin_tt) : QString(); - - if (want_pass) { - PinEntryDialog pinentry(nullptr, 0, pe->timeout, true, !!pe->quality_bar, - repeatString, visibilityTT, hideTT); - setup_foreground_window(&pinentry, pe->parent_wid); - pinentry.setPinentryInfo(pe); - pinentry.setPrompt(escape_accel(from_utf8(pe->prompt))); - pinentry.setDescription(from_utf8(pe->description)); - pinentry.setRepeatErrorText(repeatError); - pinentry.setGenpinLabel(generateLbl); - pinentry.setGenpinTT(generateTT); - pinentry.setCapsLockHint(capsLockHint); - pinentry.setFormattedPassphrase({bool(pe->formatted_passphrase), - from_utf8(pe->formatted_passphrase_hint)}); - pinentry.setConstraintsOptions({bool(pe->constraints_enforce), - from_utf8(pe->constraints_hint_short), - from_utf8(pe->constraints_hint_long), - from_utf8(pe->constraints_error_title)}); - - if (!title.isEmpty()) { - pinentry.setWindowTitle(title); - } - - /* If we reuse the same dialog window. */ - pinentry.setPin(QString()); - - pinentry.setOkText(ok); - pinentry.setCancelText(cancel); - if (pe->error) { - pinentry.setError(from_utf8(pe->error)); - } - if (pe->quality_bar) { - pinentry.setQualityBar(from_utf8(pe->quality_bar)); - } - if (pe->quality_bar_tt) { - pinentry.setQualityBarTT(from_utf8(pe->quality_bar_tt)); - } - bool ret = pinentry.exec(); - if (!ret) { - if (pinentry.timedOut()) pe->specific_err = gpg_error(GPG_ERR_TIMEOUT); - return -1; - } - - const QString pinStr = pinentry.pin(); - QByteArray pin = pinStr.toUtf8(); - - if (!!pe->repeat_passphrase) { - /* Should not have been possible to accept - the dialog in that case but we do a safety - check here */ - pe->repeat_okay = (pinStr == pinentry.repeatedPin()); - } - - int len = strlen(pin.constData()); - if (len >= 0) { - pinentry_setbufferlen(pe, len + 1); - if (pe->pin) { - strcpy(pe->pin, pin.constData()); - return len; - } - } - return -1; - } else { - const QString desc = - pe->description ? from_utf8(pe->description) : QString(); - const QString notok = - pe->notok ? escape_accel(from_utf8(pe->notok)) : QString(); - - const QMessageBox::StandardButtons buttons = - pe->one_button ? QMessageBox::Ok - : pe->notok ? QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel - : - /* else */ QMessageBox::Ok | QMessageBox::Cancel; - - PinentryConfirm box{QMessageBox::Information, title, desc, buttons}; - box.setTextFormat(Qt::PlainText); - box.setTextInteractionFlags(Qt::TextSelectableByMouse); - box.setTimeout(std::chrono::seconds{pe->timeout}); - setup_foreground_window(&box, pe->parent_wid); - - const struct { - QMessageBox::StandardButton button; - QString label; - } buttonLabels[] = { - {QMessageBox::Ok, ok}, - {QMessageBox::Yes, ok}, - {QMessageBox::No, notok}, - {QMessageBox::Cancel, cancel}, - }; - - for (size_t i = 0; i < sizeof buttonLabels / sizeof *buttonLabels; ++i) - if ((buttons & buttonLabels[i].button) && - !buttonLabels[i].label.isEmpty()) { - box.button(buttonLabels[i].button)->setText(buttonLabels[i].label); - Accessibility::setDescription(box.button(buttonLabels[i].button), - buttonLabels[i].label); - } - - box.setIconPixmap(applicationIconPixmap()); - - if (!pe->one_button) { - box.setDefaultButton(QMessageBox::Cancel); - } - - box.show(); - raiseWindow(&box); - - const int rc = box.exec(); - - if (rc == QMessageBox::Cancel) { - pe->canceled = true; - } - if (box.timedOut()) { - pe->specific_err = gpg_error(GPG_ERR_TIMEOUT); - } - - return rc == QMessageBox::Ok || rc == QMessageBox::Yes; - } -} - -static int qt_cmd_handler_ex(pinentry_t pe) { - try { - return qt_cmd_handler(pe); - } catch (const InvalidUtf8 &) { - pe->locale_err = true; - return pe->pin ? -1 : false; - } catch (...) { - pe->canceled = true; - return pe->pin ? -1 : false; - } -} - -pinentry_cmd_handler_t pinentry_cmd_handler = qt_cmd_handler_ex; - -int pinentry_main(int argc, char *argv[]) { - pinentry_init("pinentry-qt"); - - QApplication *app = NULL; - int new_argc = 0; - -#ifdef FALLBACK_CURSES -#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) - // check a few environment variables that are usually set on X11 or Wayland - // sessions - const bool hasWaylandDisplay = qEnvironmentVariableIsSet("WAYLAND_DISPLAY"); - const bool isWaylandSessionType = qgetenv("XDG_SESSION_TYPE") == "wayland"; - const bool hasX11Display = pinentry_have_display(argc, argv); - const bool isX11SessionType = qgetenv("XDG_SESSION_TYPE") == "x11"; - const bool isGUISession = hasWaylandDisplay || isWaylandSessionType || - hasX11Display || isX11SessionType; - qCDebug(PINENTRY_LOG) << "hasWaylandDisplay:" << hasWaylandDisplay; - qCDebug(PINENTRY_LOG) << "isWaylandSessionType:" << isWaylandSessionType; - qCDebug(PINENTRY_LOG) << "hasX11Display:" << hasX11Display; - qCDebug(PINENTRY_LOG) << "isX11SessionType:" << isX11SessionType; - qCDebug(PINENTRY_LOG) << "isGUISession:" << isGUISession; -#else - const bool isGUISession = pinentry_have_display(argc, argv); -#endif - if (!isGUISession) { - pinentry_cmd_handler = curses_cmd_handler; - pinentry_set_flavor_flag("curses"); - } else -#endif - { - /* Qt does only understand -display but not --display; thus we - are fixing that here. The code is pretty simply and may get - confused if an argument is called "--display". */ - char **new_argv, *p; - size_t n; - int i, done; - - for (n = 0, i = 0; i < argc; i++) { - n += strlen(argv[i]) + 1; - } - n++; - new_argv = (char **)calloc(argc + 1, sizeof *new_argv); - if (new_argv) { - *new_argv = (char *)malloc(n); - } - if (!new_argv || !*new_argv) { - fprintf(stderr, "pinentry-qt: can't fixup argument list: %s\n", - strerror(errno)); - exit(EXIT_FAILURE); - } - for (done = 0, p = *new_argv, i = 0; i < argc; i++) - if (!done && !strcmp(argv[i], "--display")) { - new_argv[i] = strcpy(p, argv[i] + 1); - p += strlen(argv[i] + 1) + 1; - done = 1; - } else { - new_argv[i] = strcpy(p, argv[i]); - p += strlen(argv[i]) + 1; - } - - /* Note: QApplication uses int &argc so argc has to be valid - * for the full lifetime of the application. - * - * As Qt might modify argc / argv we use copies here so that - * we do not loose options that are handled in both. e.g. display. - */ - new_argc = argc; - Q_ASSERT(new_argc); - app = new QApplication(new_argc, new_argv); - app->setWindowIcon(QIcon(QLatin1String(":/document-encrypt.png"))); - (void)new KeyboardFocusIndication{app}; - } - - pinentry_parse_opts(argc, argv); - - int rc = pinentry_loop(); - delete app; - return rc ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/src/pinentry/pinentrydialog.cpp b/src/pinentry/pinentrydialog.cpp index f0fba73c..cbd8e891 100644 --- a/src/pinentry/pinentrydialog.cpp +++ b/src/pinentry/pinentrydialog.cpp @@ -24,6 +24,8 @@ */ #include <qnamespace.h> + +#include "pinentry.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -504,7 +506,8 @@ void PinEntryDialog::updateQuality(const QString &txt) { const QByteArray utf8_pin = txt.toUtf8(); const char *pin = utf8_pin.constData(); length = strlen(pin); - percent = length ? pinentry_inq_quality(_pinentry_info, pin, length) : 0; + percent = + length ? pinentry_inq_quality(_pinentry_info.get(), pin, length) : 0; if (!length) { _quality_bar->reset(); } else { @@ -521,7 +524,7 @@ void PinEntryDialog::updateQuality(const QString &txt) { } void PinEntryDialog::setPinentryInfo(pinentry_t peinfo) { - _pinentry_info = peinfo; + _pinentry_info = std::unique_ptr<struct pinentry>(peinfo); } void PinEntryDialog::focusChanged(QWidget *old, QWidget *now) { @@ -557,7 +560,7 @@ void PinEntryDialog::textChanged(const QString &text) { } void PinEntryDialog::generatePin() { - unique_malloced_ptr<char> pin{pinentry_inq_genpin(_pinentry_info)}; + unique_malloced_ptr<char> pin{pinentry_inq_genpin(_pinentry_info.get())}; if (pin) { if (_edit->echoMode() == QLineEdit::Password) { if (mVisiActionEdit) { @@ -685,7 +688,7 @@ PinEntryDialog::PassphraseCheckResult PinEntryDialog::checkConstraints() { const auto passphrase = _edit->pin().toUtf8(); unique_malloced_ptr<char> error{pinentry_inq_checkpin( - _pinentry_info, passphrase.constData(), passphrase.size())}; + _pinentry_info.get(), passphrase.constData(), passphrase.size())}; if (!error) { return PassphraseOk; diff --git a/src/pinentry/pinentrydialog.h b/src/pinentry/pinentrydialog.h index 97a90478..def61d20 100644 --- a/src/pinentry/pinentrydialog.h +++ b/src/pinentry/pinentrydialog.h @@ -30,6 +30,7 @@ #include <QDialog> #include <QStyle> #include <QTimer> +#include <memory> #include "pinentry.h" @@ -163,7 +164,8 @@ class PinEntryDialog : public QDialog bool _disable_echo_allowed = true; bool mEnforceConstraints = false; bool mFormatPassphrase = false; - pinentry_t _pinentry_info = nullptr; + std::unique_ptr<struct pinentry> _pinentry_info = + std::make_unique<struct pinentry>(); QTimer *_timer = nullptr; QString mVisibilityTT; QString mHideTT; diff --git a/src/pinentry/pinlineedit.h b/src/pinentry/pinlineedit.h index e67ced83..e8a3ca0f 100644 --- a/src/pinentry/pinlineedit.h +++ b/src/pinentry/pinlineedit.h @@ -23,41 +23,39 @@ #define _PINLINEEDIT_H_ #include <QLineEdit> - #include <memory> -class PinLineEdit : public QLineEdit -{ - Q_OBJECT +class PinLineEdit : public QLineEdit { + Q_OBJECT -public: - explicit PinLineEdit(QWidget *parent = nullptr); - ~PinLineEdit() override; + public: + explicit PinLineEdit(QWidget *parent = nullptr); + ~PinLineEdit() override; - void setPin(const QString &pin); - QString pin() const; + void setPin(const QString &pin); + QString pin() const; -public Q_SLOTS: - void setFormattedPassphrase(bool on); - void copy() const; - void cut(); + public Q_SLOTS: + void setFormattedPassphrase(bool on); + void copy() const; + void cut(); -Q_SIGNALS: - void backspacePressed(); + Q_SIGNALS: + void backspacePressed(); -protected: - void keyPressEvent(QKeyEvent *) override; + protected: + void keyPressEvent(QKeyEvent *) override; -private: - using QLineEdit::setText; - using QLineEdit::text; + private: + using QLineEdit::setText; + using QLineEdit::text; -private Q_SLOTS: - void textEdited(); + private Q_SLOTS: + void textEdited(); -private: - class Private; - std::unique_ptr<Private> d; + private: + class Private; + std::unique_ptr<Private> d; }; -#endif // _PINLINEEDIT_H_ +#endif // _PINLINEEDIT_H_ diff --git a/src/pinentry/secmem.cpp b/src/pinentry/secmem.cpp deleted file mode 100644 index cb4eeb4f..00000000 --- a/src/pinentry/secmem.cpp +++ /dev/null @@ -1,375 +0,0 @@ -/* secmem.c - memory allocation from a secure heap - * Copyright (C) 1998, 1999, 2003 Free Software Foundation, Inc. - * Copyright (C) 2015 g10 Code GmbH - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <https://www.gnu.org/licenses/>. - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#ifndef WINDOWS -#include <errno.h> -#endif -#include <stdarg.h> -#include <unistd.h> -#if defined(HAVE_MLOCK) || defined(HAVE_MMAP) -#include <fcntl.h> -#include <sys/mman.h> -#include <sys/types.h> -#endif -#include <string.h> - -#include "secmem.h" - -#ifdef ORIGINAL_GPG_VERSION -#include "types.h" -#include "util.h" -#else /* ORIGINAL_GPG_VERSION */ - -#include "secmem_util.h" - -typedef union { - int a; - short b; - char c[1]; - long d; -#ifdef HAVE_U64_TYPE - u64 e; -#endif - float f; - double g; -} PROPERLY_ALIGNED_TYPE; - -#define log_error log_info -#define log_bug log_fatal - -void log_info(char *template_, ...) { - va_list args; - - va_start(args, template_); - vfprintf(stderr, template_, args); - va_end(args); -} - -void log_fatal(char *template_, ...) { - va_list args; - - va_start(args, template_); - vfprintf(stderr, template_, args); - va_end(args); - exit(EXIT_FAILURE); -} - -#endif /* ORIGINAL_GPG_VERSION */ - -#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) -#define MAP_ANONYMOUS MAP_ANON -#endif - -#define DEFAULT_POOLSIZE 16384 - -typedef struct memblock_struct MEMBLOCK; -struct memblock_struct { - unsigned size; - union { - MEMBLOCK *next; - PROPERLY_ALIGNED_TYPE aligned; - } u; -}; - -static void *pool; -static volatile int pool_okay; /* may be checked in an atexit function */ -#if HAVE_MMAP -static int pool_is_mmapped; -#endif -static size_t poolsize; /* allocated length */ -static size_t poollen; /* used length */ -static MEMBLOCK *unused_blocks; -static unsigned max_alloced; -static unsigned cur_alloced; -static unsigned max_blocks; -static unsigned cur_blocks; -static int disable_secmem; -static int show_warning; -static int no_warning; -static int suspend_warning; - -static void print_warn(void) { - if (!no_warning) log_info("Warning: using insecure memory!\n"); -} - -static void lock_pool(void *p, size_t n) { -#if defined(HAVE_MLOCK) - uid_t uid; - int err; - - uid = getuid(); - -#ifdef HAVE_BROKEN_MLOCK - if (uid) { - errno = EPERM; - err = -1; - } else { - err = mlock(p, n); - } -#else - err = mlock(p, n); -#endif - - if (uid && !geteuid()) { - if (setuid(uid) || getuid() != geteuid()) - log_fatal("failed to reset uid: %s\n", strerror(errno)); - } - - if (err) { - if (errno != EPERM -#ifdef EAGAIN /* OpenBSD returns this */ - && errno != EAGAIN -#endif - ) - log_error("can't lock memory: %s\n", strerror(errno)); - show_warning = 1; - } - -#else - (void)p; - (void)n; - log_info("Please note that you don't have secure memory on this system\n"); -#endif -} - -static void init_pool(size_t n) { -#if HAVE_MMAP - size_t pgsize; -#endif - - poolsize = n; - - if (disable_secmem) log_bug("secure memory is disabled"); - -#if HAVE_MMAP -#ifdef HAVE_GETPAGESIZE - pgsize = getpagesize(); -#else - pgsize = 4096; -#endif - - poolsize = (poolsize + pgsize - 1) & ~(pgsize - 1); -#ifdef MAP_ANONYMOUS - pool = mmap(0, poolsize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, - -1, 0); -#else /* map /dev/zero instead */ - { - int fd; - - fd = open("/dev/zero", O_RDWR); - if (fd == -1) { - log_error("can't open /dev/zero: %s\n", strerror(errno)); - pool = (void *)-1; - } else { - pool = mmap(0, poolsize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - close(fd); - } - } -#endif - if (pool == (void *)-1) - log_info("can't mmap pool of %u bytes: %s - using malloc\n", - (unsigned)poolsize, strerror(errno)); - else { - pool_is_mmapped = 1; - pool_okay = 1; - } - -#endif - if (!pool_okay) { - pool = malloc(poolsize); - if (!pool) - log_fatal("can't allocate memory pool of %u bytes\n", (unsigned)poolsize); - else - pool_okay = 1; - } - lock_pool(pool, poolsize); - poollen = 0; -} - -/* concatenate unused blocks */ -static void compress_pool(void) { /* fixme: we really should do this */ -} - -void secmem_set_flags(unsigned flags) { - int was_susp = suspend_warning; - - no_warning = flags & 1; - suspend_warning = flags & 2; - - /* and now issue the warning if it is not longer suspended */ - if (was_susp && !suspend_warning && show_warning) { - show_warning = 0; - print_warn(); - } -} - -unsigned secmem_get_flags(void) { - unsigned flags; - - flags = no_warning ? 1 : 0; - flags |= suspend_warning ? 2 : 0; - return flags; -} - -void secmem_init(size_t n) { - if (!n) { -#if !defined(HAVE_DOSISH_SYSTEM) - uid_t uid; - - disable_secmem = 1; - uid = getuid(); - if (uid != geteuid()) { - if (setuid(uid) || getuid() != geteuid()) - log_fatal("failed to drop setuid\n"); - } -#endif - } else { - if (n < DEFAULT_POOLSIZE) n = DEFAULT_POOLSIZE; - if (!pool_okay) - init_pool(n); - else - log_error("Oops, secure memory pool already initialized\n"); - } -} - -void *secmem_malloc(size_t size) { - MEMBLOCK *mb, *mb2; - int compressed = 0; - - if (!pool_okay) { - log_info("operation is not possible without initialized secure memory\n"); - log_info("(you may have used the wrong program for this task)\n"); - exit(2); - } - if (show_warning && !suspend_warning) { - show_warning = 0; - print_warn(); - } - - /* blocks are always a multiple of 32 */ - size += sizeof(MEMBLOCK); - size = ((size + 31) / 32) * 32; - -retry: - /* try to get it from the used blocks */ - for (mb = unused_blocks, mb2 = NULL; mb; mb2 = mb, mb = mb->u.next) - if (mb->size >= size) { - if (mb2) - mb2->u.next = mb->u.next; - else - unused_blocks = mb->u.next; - goto leave; - } - /* allocate a new block */ - if ((poollen + size <= poolsize)) { - mb = (MEMBLOCK *)((char *)pool + poollen); - poollen += size; - mb->size = size; - } else if (!compressed) { - compressed = 1; - compress_pool(); - goto retry; - } else - return NULL; - -leave: - cur_alloced += mb->size; - cur_blocks++; - if (cur_alloced > max_alloced) max_alloced = cur_alloced; - if (cur_blocks > max_blocks) max_blocks = cur_blocks; - - memset(&mb->u.aligned.c, 0, - size - (size_t) & ((struct memblock_struct *)0)->u.aligned.c); - - return &mb->u.aligned.c; -} - -void *secmem_realloc(void *p, size_t newsize) { - MEMBLOCK *mb; - size_t size; - void *a; - - if (!p) return secmem_malloc(newsize); - - mb = (MEMBLOCK *)(void *)((char *)p - offsetof(MEMBLOCK, u.aligned.c)); - - size = mb->size; - if (newsize < size) return p; /* it is easier not to shrink the memory */ - a = secmem_malloc(newsize); - memcpy(a, p, size); - memset((char *)a + size, 0, newsize - size); - secmem_free(p); - return a; -} - -void secmem_free(void *a) { - MEMBLOCK *mb; - size_t size; - - if (!a) return; - - mb = (MEMBLOCK *)(void *)((char *)a - offsetof(MEMBLOCK, u.aligned.c)); - size = mb->size; - /* This does not make much sense: probably this memory is held in the - * cache. We do it anyway: */ - wipememory2(mb, 0xff, size); - wipememory2(mb, 0xaa, size); - wipememory2(mb, 0x55, size); - wipememory2(mb, 0x00, size); - mb->size = size; - mb->u.next = unused_blocks; - unused_blocks = mb; - cur_blocks--; - cur_alloced -= size; -} - -int m_is_secure(const void *p) { - return p >= pool && p < (void *)((char *)pool + poolsize); -} - -void secmem_term(void) { - if (!pool_okay) return; - - wipememory2(pool, 0xff, poolsize); - wipememory2(pool, 0xaa, poolsize); - wipememory2(pool, 0x55, poolsize); - wipememory2(pool, 0x00, poolsize); -#if HAVE_MMAP - if (pool_is_mmapped) munmap(pool, poolsize); -#endif - pool = NULL; - pool_okay = 0; - poolsize = 0; - poollen = 0; - unused_blocks = NULL; -} - -void secmem_dump_stats(void) { - if (disable_secmem) return; - fprintf(stderr, "secmem usage: %u/%u bytes in %u/%u blocks of pool %lu/%lu\n", - cur_alloced, max_alloced, cur_blocks, max_blocks, (ulong)poollen, - (ulong)poolsize); -} - -size_t secmem_get_max_size(void) { return poolsize; } diff --git a/src/pinentry/secmem.h b/src/pinentry/secmem.h deleted file mode 100644 index 75fe708b..00000000 --- a/src/pinentry/secmem.h +++ /dev/null @@ -1,55 +0,0 @@ -/* Quintuple Agent secure memory allocation - * Copyright (C) 1998,1999 Free Software Foundation, Inc. - * Copyright (C) 1999,2000 Robert Bihlmeyer <[email protected]> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <https://www.gnu.org/licenses/>. - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef _MEMORY_H -#define _MEMORY_H - -#include <sys/types.h> - -#ifdef __cplusplus -extern "C" { -#if 0 -} -#endif -#endif - - -/* values for flags, hardcoded in secmem.c */ -#define SECMEM_WARN 0 -#define SECMEM_DONT_WARN 1 -#define SECMEM_SUSPEND_WARN 2 - -void secmem_init( size_t npool ); -void secmem_term( void ); -void *secmem_malloc( size_t size ); -void *secmem_realloc( void *a, size_t newsize ); -void secmem_free( void *a ); -int m_is_secure( const void *p ); -void secmem_dump_stats(void); -void secmem_set_flags( unsigned flags ); -unsigned secmem_get_flags(void); -size_t secmem_get_max_size (void); - -#if 0 -{ -#endif -#ifdef __cplusplus -} -#endif -#endif /* _MEMORY_H */ diff --git a/src/pinentry/secmem_util.h b/src/pinentry/secmem_util.h deleted file mode 100644 index 3c8ffb8a..00000000 --- a/src/pinentry/secmem_util.h +++ /dev/null @@ -1,65 +0,0 @@ -/* Quintuple Agent utilities - * Copyright (C) 1999 Robert Bihlmeyer <[email protected]> - * Copyright (C) 2003 g10 Code GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <https://www.gnu.org/licenses/>. - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef _UTIL_H -#define _UTIL_H - -#include <sys/types.h> - -#ifndef HAVE_TYPE_BYTE -# undef byte -# if !(defined(_WIN32) && defined(cbNDRContext)) - /* Windows typedefs byte in the rpc headers. Avoid warning about - double definition. */ - typedef unsigned char byte; -# endif -# define HAVE_TYPE_BYTE -#endif - -#ifndef HAVE_TYPE_ULONG -# undef ulong - typedef unsigned long ulong; -# define HAVE_TYPE_ULONG -#endif - - -ssize_t xwrite(int, const void *, size_t); /* write until finished */ -int debugmsg(const char *, ...); /* output a debug message if debugging==on */ -void drop_privs(void); /* finally drop privileges */ - - -/* To avoid that a compiler optimizes certain memset calls away, these - macros may be used instead. */ -#define wipememory2(_ptr,_set,_len) do { \ - volatile char *_vptr=(volatile char *)(_ptr); \ - size_t _vlen=(_len); \ - while(_vlen) { *_vptr=(_set); _vptr++; _vlen--; } \ - } while(0) -#define wipememory(_ptr,_len) wipememory2(_ptr,0,_len) -#define wipe(_ptr,_len) wipememory2(_ptr,0,_len) - - - - -#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ - *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) -#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) - - -#endif diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 0006738c..06bea61a 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -50,15 +50,18 @@ generate_export_header(gpgfrontend_ui EXPORT_FILE_NAME "${_export_file}") # link Qt if(Qt6_DIR) target_link_libraries(gpgfrontend_ui - Qt6::Network Qt6::PrintSupport Qt6::Widgets Qt6::Test Qt6::Core5Compat Qt6::Core) + Qt6::Network Qt6::PrintSupport Qt6::Test Qt6::Core5Compat) else() target_link_libraries(gpgfrontend_ui - Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core) + Qt5::Network Qt5::PrintSupport Qt5::Test) endif() # link gpgfrontend_core target_link_libraries(gpgfrontend_ui gpgfrontend_core) +# link buddled pinentry +target_link_libraries(gpgfrontend_ui gpgfrontend_pinentry) + # set up pch target_precompile_headers(gpgfrontend_ui PUBLIC GpgFrontendUI.h) diff --git a/src/ui/UserInterfaceUtils.cpp b/src/ui/UserInterfaceUtils.cpp index 2e3596f8..dabdf657 100644 --- a/src/ui/UserInterfaceUtils.cpp +++ b/src/ui/UserInterfaceUtils.cpp @@ -43,7 +43,6 @@ #include "core/thread/TaskRunnerGetter.h" #include "core/utils/CacheUtils.h" #include "core/utils/IOUtils.h" -#include "spdlog/spdlog.h" #include "ui/UISignalStation.h" #include "ui/dialog/WaitingDialog.h" #include "ui/dialog/gnupg/GnuPGControllerDialog.h" diff --git a/src/ui/function/RaisePinentry.cpp b/src/ui/function/RaisePinentry.cpp new file mode 100644 index 00000000..7ed98b93 --- /dev/null +++ b/src/ui/function/RaisePinentry.cpp @@ -0,0 +1,84 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "RaisePinentry.h" + +#include "core/function/CoreSignalStation.h" +#include "pinentry/pinentrydialog.h" + +namespace GpgFrontend::UI { + +RaisePinentry::RaisePinentry(QWidget* parent) : QWidget(parent) {} + +auto RaisePinentry::Exec() -> int { + auto* pinentry = + new PinEntryDialog(this, 0, 0, true, false, QString(), + QString::fromStdString(_("Show passphrase")), + QString::fromStdString(_("Hide passphrase"))); + + SPDLOG_DEBUG("setting pinetry's arguments"); + + pinentry->setPinentryInfo(new struct pinentry()); + pinentry->setPrompt(QString::fromStdString(_("PIN:"))); + pinentry->setDescription(QString()); + pinentry->setRepeatErrorText( + QString::fromStdString(_("Passphrases do not match"))); + pinentry->setGenpinLabel(QString()); + pinentry->setGenpinTT(QString()); + pinentry->setCapsLockHint(QString::fromStdString(_("Caps Lock is on"))); + pinentry->setFormattedPassphrase({false, QString()}); + pinentry->setConstraintsOptions({false, QString(), QString(), QString()}); + + pinentry->setWindowTitle(_("Pinentry")); + + /* If we reuse the same dialog window. */ + pinentry->setPin(QString()); + pinentry->setOkText(_("Confirm")); + pinentry->setCancelText(_("Cancel")); + + SPDLOG_DEBUG("pinentry is ready to start"); + + connect(pinentry, &PinEntryDialog::finished, this, [pinentry](int result) { + bool ret = result != 0; + SPDLOG_DEBUG("PinEntryDialog finished, ret: {}", ret); + + if (!ret) { + emit CoreSignalStation::GetInstance()->SignalUserInputPassphraseCallback( + {}); + return -1; + } + + auto pin = pinentry->pin().toUtf8(); + emit CoreSignalStation::GetInstance()->SignalUserInputPassphraseCallback( + pin); + return 0; + }); + + pinentry->open(); +} +} // namespace GpgFrontend::UI diff --git a/src/ui/function/RaisePinentry.h b/src/ui/function/RaisePinentry.h new file mode 100644 index 00000000..b950d2b9 --- /dev/null +++ b/src/ui/function/RaisePinentry.h @@ -0,0 +1,42 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#pragma once + +#include <qwidget.h> +namespace GpgFrontend::UI { + +class RaisePinentry : QWidget { + Q_OBJECT + public: + explicit RaisePinentry(QWidget *parent); + + auto Exec() -> int; +}; + +} // namespace GpgFrontend::UI
\ No newline at end of file diff --git a/src/ui/function/SetOwnerTrustLevel.h b/src/ui/function/SetOwnerTrustLevel.h index ddd7a97f..29cece18 100644 --- a/src/ui/function/SetOwnerTrustLevel.h +++ b/src/ui/function/SetOwnerTrustLevel.h @@ -33,6 +33,7 @@ namespace GpgFrontend::UI { class SetOwnerTrustLevel : public QWidget { + Q_OBJECT public: /** * @brief Set the Owner Trust Level object diff --git a/src/ui/main_window/MainWindowSlotUI.cpp b/src/ui/main_window/MainWindowSlotUI.cpp index d640d337..65ead3ce 100644 --- a/src/ui/main_window/MainWindowSlotUI.cpp +++ b/src/ui/main_window/MainWindowSlotUI.cpp @@ -33,8 +33,7 @@ #include "core/GpgConstants.h" #include "core/function/CoreSignalStation.h" #include "core/function/GlobalSettingStation.h" -#include "pinentry/pinentrydialog.h" -#include "spdlog/spdlog.h" +#include "function/RaisePinentry.h" #include "ui/UserInterfaceUtils.h" #include "ui/dialog/Wizard.h" #include "ui/main_window/KeyMgmt.h" @@ -230,51 +229,8 @@ void MainWindow::SetCryptoMenuStatus( } void MainWindow::SlotRaisePinentry() { - auto* pinentry = - new PinEntryDialog(this, 0, 0, true, false, QString(), - QString::fromStdString(_("Show passphrase")), - QString::fromStdString(_("Hide passphrase"))); - - SPDLOG_DEBUG("setting pinetry's arguments"); - - pinentry->setPinentryInfo(new struct pinentry()); - pinentry->setPrompt(QString::fromStdString(_("PIN:"))); - pinentry->setDescription(QString()); - pinentry->setRepeatErrorText( - QString::fromStdString(_("Passphrases do not match"))); - pinentry->setGenpinLabel(QString()); - pinentry->setGenpinTT(QString()); - pinentry->setCapsLockHint(QString::fromStdString(_("Caps Lock is on"))); - pinentry->setFormattedPassphrase({false, QString()}); - pinentry->setConstraintsOptions({false, QString(), QString(), QString()}); - - pinentry->setWindowTitle(_("Pinentry")); - - /* If we reuse the same dialog window. */ - pinentry->setPin(QString()); - - pinentry->setOkText(_("Confirm")); - pinentry->setCancelText(_("Cancel")); - - SPDLOG_DEBUG("pinentry is ready to start"); - - connect(pinentry, &PinEntryDialog::finished, this, [pinentry](int result) { - bool ret = result != 0; - SPDLOG_DEBUG("PinEntryDialog finished, ret: {}", ret); - - if (!ret) { - emit CoreSignalStation::GetInstance()->SignalUserInputPassphraseCallback( - {}); - return -1; - } - - auto pin = pinentry->pin().toUtf8(); - emit CoreSignalStation::GetInstance()->SignalUserInputPassphraseCallback( - pin); - return 0; - }); - - pinentry->open(); + auto function = RaisePinentry(this); + function.Exec(); } } // namespace GpgFrontend::UI diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt index 829adbf6..0fdc8a16 100644 --- a/third_party/CMakeLists.txt +++ b/third_party/CMakeLists.txt @@ -28,4 +28,7 @@ set(JSON_BuildTests OFF CACHE INTERNAL "") add_subdirectory(json EXCLUDE_FROM_ALL) -add_subdirectory(spdlog EXCLUDE_FROM_ALL)
\ No newline at end of file +add_subdirectory(spdlog EXCLUDE_FROM_ALL) + +set(MI_SECURE ON) +add_subdirectory(mimalloc EXCLUDE_FROM_ALL)
\ No newline at end of file diff --git a/third_party/mimalloc b/third_party/mimalloc new file mode 160000 +Subproject 43ce4bd7fd34bcc730c1c7471c9999559741548 |