1 /*
2 callbacks.cpp - callback targets for internal use:
3 Copyright (C) 2003,2004 Klarälvdalens Datakonsult AB
4 2016 Bundesamt für Sicherheit in der Informationstechnik
5 Software engineering by Intevation GmbH
6
7 This file is part of GPGME++.
8
9 GPGME++ is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Library General Public
11 License as published by the Free Software Foundation; either
12 version 2 of the License, or (at your option) any later version.
13
14 GPGME++ is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU Library General Public License for more details.
18
19 You should have received a copy of the GNU Library General Public License
20 along with GPGME++; see the file COPYING.LIB. If not, write to the
21 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 Boston, MA 02110-1301, USA.
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include "callbacks.h"
30 #include "util.h"
31
32 #include <interfaces/progressprovider.h>
33 #include <interfaces/passphraseprovider.h>
34 #include <interfaces/dataprovider.h>
35 #include <error.h>
36
37 #include <gpgme.h>
38 #include <gpg-error.h>
39
40 #include <cassert>
41 #include <cerrno>
42 #include <cstring>
43 #include <unistd.h>
44 #include <stdlib.h>
45
make_err_from_syserror()46 static inline gpgme_error_t make_err_from_syserror()
47 {
48 return gpgme_error_from_syserror();
49 }
50
51 using GpgME::ProgressProvider;
52 using GpgME::PassphraseProvider;
53 using GpgME::DataProvider;
54
progress_callback(void * opaque,const char * what,int type,int current,int total)55 void progress_callback(void *opaque, const char *what,
56 int type, int current, int total)
57 {
58 ProgressProvider *provider = static_cast<ProgressProvider *>(opaque);
59 if (provider) {
60 provider->showProgress(what, type, current, total);
61 }
62 }
63
64 /* To avoid that a compiler optimizes certain memset calls away, these
65 macros may be used instead. */
66 #define wipememory2(_ptr,_set,_len) do { \
67 volatile char *_vptr=(volatile char *)(_ptr); \
68 size_t _vlen=(_len); \
69 while(_vlen) { *_vptr=(_set); _vptr++; _vlen--; } \
70 } while(0)
71 #define wipememory(_ptr,_len) wipememory2(_ptr,0,_len)
72
passphrase_callback(void * opaque,const char * uid_hint,const char * desc,int prev_was_bad,int fd)73 gpgme_error_t passphrase_callback(void *opaque, const char *uid_hint, const char *desc,
74 int prev_was_bad, int fd)
75 {
76 PassphraseProvider *provider = static_cast<PassphraseProvider *>(opaque);
77 bool canceled = false;
78 gpgme_error_t err = GPG_ERR_NO_ERROR;
79 char *passphrase = provider ? provider->getPassphrase(uid_hint, desc, prev_was_bad, canceled) : nullptr ;
80 if (canceled) {
81 err = make_error(GPG_ERR_CANCELED);
82 } else {
83 if (passphrase && *passphrase) {
84 size_t passphrase_length = std::strlen(passphrase);
85 size_t written = 0;
86 do {
87 ssize_t now_written = gpgme_io_write(fd, passphrase + written, passphrase_length - written);
88 if (now_written < 0) {
89 err = make_err_from_syserror();
90 break;
91 }
92 written += now_written;
93 } while (written < passphrase_length);
94 }
95 }
96
97 if (passphrase && *passphrase) {
98 wipememory(passphrase, std::strlen(passphrase));
99 }
100 free(passphrase);
101 gpgme_io_write(fd, "\n", 1);
102 return err;
103 }
104
105 static gpgme_ssize_t
data_read_callback(void * opaque,void * buf,size_t buflen)106 data_read_callback(void *opaque, void *buf, size_t buflen)
107 {
108 DataProvider *provider = static_cast<DataProvider *>(opaque);
109 if (!provider) {
110 gpgme_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL));
111 return -1;
112 }
113 return (gpgme_ssize_t)provider->read(buf, buflen);
114 }
115
116 static gpgme_ssize_t
data_write_callback(void * opaque,const void * buf,size_t buflen)117 data_write_callback(void *opaque, const void *buf, size_t buflen)
118 {
119 DataProvider *provider = static_cast<DataProvider *>(opaque);
120 if (!provider) {
121 gpgme_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL));
122 return -1;
123 }
124 return (gpgme_ssize_t)provider->write(buf, buflen);
125 }
126
127 static gpgme_off_t
data_seek_callback(void * opaque,gpgme_off_t offset,int whence)128 data_seek_callback(void *opaque, gpgme_off_t offset, int whence)
129 {
130 DataProvider *provider = static_cast<DataProvider *>(opaque);
131 if (!provider) {
132 gpgme_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL));
133 return -1;
134 }
135 if (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) {
136 gpgme_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL));
137 return -1;
138 }
139 return provider->seek((off_t)offset, whence);
140 }
141
data_release_callback(void * opaque)142 static void data_release_callback(void *opaque)
143 {
144 DataProvider *provider = static_cast<DataProvider *>(opaque);
145 if (provider) {
146 provider->release();
147 }
148 }
149
150 const gpgme_data_cbs GpgME::data_provider_callbacks = {
151 &data_read_callback,
152 &data_write_callback,
153 &data_seek_callback,
154 &data_release_callback
155 };
156