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