File indexing completed on 2024-05-12 05:20:02
0001 /* -*- mode: c++; c-basic-offset:4 -*- 0002 tests/test_uiserver.cpp 0003 0004 This file is part of Kleopatra, the KDE keymanager 0005 SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 // 0011 // Usage: test_uiserver <socket> --verify-detached <signed data> <signature> 0012 // 0013 0014 #include <config-kleopatra.h> 0015 0016 #include <assuan.h> 0017 #include <gpg-error.h> 0018 0019 #include <Libkleo/Hex> 0020 #include <Libkleo/KleoException> 0021 0022 #include "utils/wsastarter.h" 0023 0024 #ifndef Q_OS_WIN 0025 #include <errno.h> 0026 #include <fcntl.h> 0027 #include <sys/stat.h> 0028 #include <sys/types.h> 0029 #include <unistd.h> 0030 #endif 0031 0032 #include <cstdlib> 0033 #include <iostream> 0034 #include <map> 0035 #include <string> 0036 #include <vector> 0037 0038 using namespace Kleo; 0039 0040 #ifdef Q_OS_WIN 0041 static const bool HAVE_FD_PASSING = false; 0042 #else 0043 static const bool HAVE_FD_PASSING = true; 0044 #endif 0045 0046 static const unsigned int ASSUAN_CONNECT_FLAGS = HAVE_FD_PASSING ? 1 : 0; 0047 0048 static std::vector<int> inFDs, outFDs, msgFDs; 0049 static std::vector<std::string> inFiles, outFiles, msgFiles; 0050 static std::map<std::string, std::string> inquireData; 0051 0052 static void usage(const std::string &msg = std::string()) 0053 { 0054 std::cerr << msg << std::endl 0055 << "\n" 0056 "Usage: test_uiserver <socket> [<io>] [<options>] [<inquire>] command [<args>]\n" 0057 "where:\n" 0058 #ifdef Q_OS_WIN 0059 " <io>: [--input[-fd] <file>] [--output[-fd] <file>] [--message[-fd] <file>]\n" 0060 #else 0061 " <io>: [--input <file>] [--output <file>] [--message <file>]\n" 0062 #endif 0063 " <options>: *[--option name=value]\n" 0064 " <inquire>: [--inquire keyword=<file>]\n"; 0065 exit(1); 0066 } 0067 0068 static gpg_error_t data(void *void_ctx, const void *buffer, size_t len) 0069 { 0070 (void)void_ctx; 0071 (void)buffer; 0072 (void)len; 0073 return 0; // ### implement me 0074 } 0075 0076 static gpg_error_t status(void *void_ctx, const char *line) 0077 { 0078 (void)void_ctx; 0079 (void)line; 0080 return 0; 0081 } 0082 0083 static gpg_error_t inquire(void *void_ctx, const char *keyword) 0084 { 0085 assuan_context_t ctx = (assuan_context_t)void_ctx; 0086 Q_ASSERT(ctx); 0087 const std::map<std::string, std::string>::const_iterator it = inquireData.find(keyword); 0088 if (it == inquireData.end()) { 0089 return gpg_error(GPG_ERR_UNKNOWN_COMMAND); 0090 } 0091 0092 if (!it->second.empty() && it->second[0] == '@') { 0093 return gpg_error(GPG_ERR_NOT_IMPLEMENTED); 0094 } 0095 0096 if (const gpg_error_t err = assuan_send_data(ctx, it->second.c_str(), it->second.size())) { 0097 qDebug("assuan_write_data: %s", gpg_strerror(err)); 0098 return err; 0099 } 0100 0101 return 0; 0102 } 0103 0104 int main(int argc, char *argv[]) 0105 { 0106 const Kleo::WSAStarter _wsastarter; 0107 0108 assuan_set_gpg_err_source(GPG_ERR_SOURCE_DEFAULT); 0109 0110 if (argc < 3) { 0111 usage(); // need socket and command, at least 0112 } 0113 0114 const char *socket = argv[1]; 0115 0116 std::vector<const char *> options; 0117 0118 std::string command; 0119 for (int optind = 2; optind < argc; ++optind) { 0120 const char *const arg = argv[optind]; 0121 if (qstrcmp(arg, "--input") == 0) { 0122 const std::string file = argv[++optind]; 0123 inFiles.push_back(file); 0124 } else if (qstrcmp(arg, "--output") == 0) { 0125 const std::string file = argv[++optind]; 0126 outFiles.push_back(file); 0127 } else if (qstrcmp(arg, "--message") == 0) { 0128 const std::string file = argv[++optind]; 0129 msgFiles.push_back(file); 0130 #ifndef Q_OS_WIN 0131 } else if (qstrcmp(arg, "--input-fd") == 0) { 0132 int inFD; 0133 if ((inFD = open(argv[++optind], O_RDONLY)) == -1) { 0134 perror("--input-fd open()"); 0135 return 1; 0136 } 0137 inFDs.push_back(inFD); 0138 } else if (qstrcmp(arg, "--output-fd") == 0) { 0139 int outFD; 0140 if ((outFD = open(argv[++optind], O_WRONLY | O_CREAT, 0666)) == -1) { 0141 perror("--output-fd open()"); 0142 return 1; 0143 } 0144 outFDs.push_back(outFD); 0145 } else if (qstrcmp(arg, "--message-fd") == 0) { 0146 int msgFD; 0147 if ((msgFD = open(argv[++optind], O_RDONLY)) == -1) { 0148 perror("--message-fd open()"); 0149 return 1; 0150 } 0151 msgFDs.push_back(msgFD); 0152 #endif 0153 } else if (qstrcmp(arg, "--option") == 0) { 0154 options.push_back(argv[++optind]); 0155 } else if (qstrcmp(arg, "--inquire") == 0) { 0156 const std::string inqval = argv[++optind]; 0157 const size_t pos = inqval.find('='); 0158 // ### implement indirection with "@file"... 0159 inquireData[inqval.substr(0, pos)] = inqval.substr(pos + 1); 0160 } else { 0161 while (optind < argc) { 0162 if (!command.empty()) { 0163 command += ' '; 0164 } 0165 command += argv[optind++]; 0166 } 0167 } 0168 } 0169 if (command.empty()) { 0170 usage("Command expected, but only options found"); 0171 } 0172 0173 assuan_context_t ctx = nullptr; 0174 0175 if (const gpg_error_t err = assuan_new(&ctx)) { 0176 qDebug("%s", Exception(err, "assuan_new").what()); 0177 return 1; 0178 } 0179 0180 if (const gpg_error_t err = assuan_socket_connect(ctx, socket, -1, ASSUAN_CONNECT_FLAGS)) { 0181 qDebug("%s", Exception(err, "assuan_socket_connect").what()); 0182 return 1; 0183 } 0184 0185 assuan_set_log_stream(ctx, stderr); 0186 0187 #ifndef Q_OS_WIN 0188 for (std::vector<int>::const_iterator it = inFDs.begin(), end = inFDs.end(); it != end; ++it) { 0189 if (const gpg_error_t err = assuan_sendfd(ctx, *it)) { 0190 qDebug("%s", Exception(err, "assuan_sendfd( inFD )").what()); 0191 return 1; 0192 } 0193 0194 if (const gpg_error_t err = assuan_transact(ctx, "INPUT FD", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)) { 0195 qDebug("%s", Exception(err, "INPUT FD").what()); 0196 return 1; 0197 } 0198 } 0199 0200 for (std::vector<int>::const_iterator it = msgFDs.begin(), end = msgFDs.end(); it != end; ++it) { 0201 if (const gpg_error_t err = assuan_sendfd(ctx, *it)) { 0202 qDebug("%s", Exception(err, "assuan_sendfd( msgFD )").what()); 0203 return 1; 0204 } 0205 0206 if (const gpg_error_t err = assuan_transact(ctx, "MESSAGE FD", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)) { 0207 qDebug("%s", Exception(err, "MESSAGE FD").what()); 0208 return 1; 0209 } 0210 } 0211 0212 for (std::vector<int>::const_iterator it = outFDs.begin(), end = outFDs.end(); it != end; ++it) { 0213 if (const gpg_error_t err = assuan_sendfd(ctx, *it)) { 0214 qDebug("%s", Exception(err, "assuan_sendfd( outFD )").what()); 0215 return 1; 0216 } 0217 0218 if (const gpg_error_t err = assuan_transact(ctx, "OUTPUT FD", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)) { 0219 qDebug("%s", Exception(err, "OUTPUT FD").what()); 0220 return 1; 0221 } 0222 } 0223 #endif 0224 0225 for (std::vector<std::string>::const_iterator it = inFiles.begin(), end = inFiles.end(); it != end; ++it) { 0226 char buffer[1024]; 0227 sprintf(buffer, "INPUT FILE=%s", hexencode(*it).c_str()); 0228 0229 if (const gpg_error_t err = assuan_transact(ctx, buffer, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)) { 0230 qDebug("%s", Exception(err, buffer).what()); 0231 return 1; 0232 } 0233 } 0234 0235 for (std::vector<std::string>::const_iterator it = msgFiles.begin(), end = msgFiles.end(); it != end; ++it) { 0236 char buffer[1024]; 0237 sprintf(buffer, "MESSAGE FILE=%s", hexencode(*it).c_str()); 0238 0239 if (const gpg_error_t err = assuan_transact(ctx, buffer, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)) { 0240 qDebug("%s", Exception(err, buffer).what()); 0241 return 1; 0242 } 0243 } 0244 0245 for (std::vector<std::string>::const_iterator it = outFiles.begin(), end = outFiles.end(); it != end; ++it) { 0246 char buffer[1024]; 0247 sprintf(buffer, "OUTPUT FILE=%s", hexencode(*it).c_str()); 0248 0249 if (const gpg_error_t err = assuan_transact(ctx, buffer, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)) { 0250 qDebug("%s", Exception(err, buffer).what()); 0251 return 1; 0252 } 0253 } 0254 0255 for (const char *opt : std::as_const(options)) { 0256 std::string line = "OPTION "; 0257 line += opt; 0258 if (const gpg_error_t err = assuan_transact(ctx, line.c_str(), nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)) { 0259 qDebug("%s", Exception(err, line).what()); 0260 return 1; 0261 } 0262 } 0263 0264 if (const gpg_error_t err = assuan_transact(ctx, command.c_str(), data, ctx, inquire, ctx, status, ctx)) { 0265 qDebug("%s", Exception(err, command).what()); 0266 return 1; 0267 } 0268 0269 assuan_release(ctx); 0270 0271 return 0; 0272 }