Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F33432218
call-gpg.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
19 KB
Subscribers
None
call-gpg.c
View Options
/* call-gpg.c - Communication with the GPG
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* 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 3 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 <http://www.gnu.org/licenses/>.
*/
#include
<config.h>
#include
<assert.h>
#include
<assuan.h>
#include
<errno.h>
#include
<npth.h>
#include
<stdlib.h>
#include
<stdio.h>
#include
<string.h>
#include
<time.h>
#include
"call-gpg.h"
#include
"exechelp.h"
#include
"i18n.h"
#include
"logging.h"
#include
"membuf.h"
#include
"strlist.h"
#include
"util.h"
static
GPGRT_INLINE
gpg_error_t
my_error_from_syserror
(
void
)
{
return
gpg_err_make
(
default_errsource
,
gpg_err_code_from_syserror
());
}
static
GPGRT_INLINE
gpg_error_t
my_error_from_errno
(
int
e
)
{
return
gpg_err_make
(
default_errsource
,
gpg_err_code_from_errno
(
e
));
}
/* Fire up a new GPG. Handle the server's initial greeting. Returns
0 on success and stores the assuan context at R_CTX. */
static
gpg_error_t
start_gpg
(
ctrl_t
ctrl
,
const
char
*
gpg_program
,
strlist_t
gpg_arguments
,
int
input_fd
,
int
output_fd
,
assuan_context_t
*
r_ctx
)
{
gpg_error_t
err
;
assuan_context_t
ctx
=
NULL
;
const
char
*
pgmname
;
const
char
**
argv
;
assuan_fd_t
no_close_list
[
5
];
int
i
;
char
line
[
ASSUAN_LINELENGTH
];
(
void
)
ctrl
;
*
r_ctx
=
NULL
;
err
=
assuan_new
(
&
ctx
);
if
(
err
)
{
log_error
(
"can't allocate assuan context: %s
\n
"
,
gpg_strerror
(
err
));
return
err
;
}
/* The first time we are used, intialize the gpg_program variable. */
if
(
!
gpg_program
||
!*
gpg_program
)
gpg_program
=
gnupg_module_name
(
GNUPG_MODULE_NAME_GPG
);
/* Compute argv[0]. */
if
(
!
(
pgmname
=
strrchr
(
gpg_program
,
'/'
)))
pgmname
=
gpg_program
;
else
pgmname
++
;
if
(
fflush
(
NULL
))
{
err
=
my_error_from_syserror
();
log_error
(
"error flushing pending output: %s
\n
"
,
gpg_strerror
(
err
));
return
err
;
}
argv
=
xtrycalloc
(
strlist_length
(
gpg_arguments
)
+
3
,
sizeof
*
argv
);
if
(
argv
==
NULL
)
{
err
=
my_error_from_syserror
();
return
err
;
}
i
=
0
;
argv
[
i
++
]
=
pgmname
;
argv
[
i
++
]
=
"--server"
;
for
(;
gpg_arguments
;
gpg_arguments
=
gpg_arguments
->
next
)
argv
[
i
++
]
=
gpg_arguments
->
d
;
argv
[
i
++
]
=
NULL
;
i
=
0
;
if
(
log_get_fd
()
!=
-1
)
no_close_list
[
i
++
]
=
assuan_fd_from_posix_fd
(
log_get_fd
());
no_close_list
[
i
++
]
=
assuan_fd_from_posix_fd
(
fileno
(
stderr
));
if
(
input_fd
!=
-1
)
no_close_list
[
i
++
]
=
assuan_fd_from_posix_fd
(
input_fd
);
if
(
output_fd
!=
-1
)
no_close_list
[
i
++
]
=
assuan_fd_from_posix_fd
(
output_fd
);
no_close_list
[
i
]
=
ASSUAN_INVALID_FD
;
/* Connect to GPG and perform initial handshaking. */
err
=
assuan_pipe_connect
(
ctx
,
gpg_program
,
argv
,
no_close_list
,
NULL
,
NULL
,
0
);
if
(
err
)
{
assuan_release
(
ctx
);
log_error
(
"can't connect to GPG: %s
\n
"
,
gpg_strerror
(
err
));
return
gpg_error
(
GPG_ERR_NO_ENGINE
);
}
if
(
input_fd
!=
-1
)
{
snprintf
(
line
,
sizeof
line
,
"INPUT FD=%d"
,
input_fd
);
err
=
assuan_transact
(
ctx
,
line
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
);
if
(
err
)
{
assuan_release
(
ctx
);
log_error
(
"error sending INPUT command: %s
\n
"
,
gpg_strerror
(
err
));
return
err
;
}
}
if
(
output_fd
!=
-1
)
{
snprintf
(
line
,
sizeof
line
,
"OUTPUT FD=%d"
,
output_fd
);
err
=
assuan_transact
(
ctx
,
line
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
);
if
(
err
)
{
assuan_release
(
ctx
);
log_error
(
"error sending OUTPUT command: %s
\n
"
,
gpg_strerror
(
err
));
return
err
;
}
}
*
r_ctx
=
ctx
;
return
0
;
}
/* Release the assuan context created by start_gpg. */
static
void
release_gpg
(
assuan_context_t
ctx
)
{
assuan_release
(
ctx
);
}
/* The data passed to the writer_thread. */
struct
writer_thread_parms
{
int
fd
;
const
void
*
data
;
size_t
datalen
;
estream_t
stream
;
gpg_error_t
*
err_addr
;
};
/* The thread started by start_writer. */
static
void
*
writer_thread_main
(
void
*
arg
)
{
gpg_error_t
err
=
0
;
struct
writer_thread_parms
*
parm
=
arg
;
char
_buffer
[
4096
];
char
*
buffer
;
size_t
length
;
if
(
parm
->
stream
)
{
buffer
=
_buffer
;
err
=
es_read
(
parm
->
stream
,
buffer
,
sizeof
_buffer
,
&
length
);
if
(
err
)
{
log_error
(
"reading stream failed: %s
\n
"
,
gpg_strerror
(
err
));
goto
leave
;
}
}
else
{
buffer
=
(
char
*
)
parm
->
data
;
length
=
parm
->
datalen
;
}
while
(
length
)
{
ssize_t
nwritten
;
nwritten
=
npth_write
(
parm
->
fd
,
buffer
,
length
<
4096
?
length
:
4096
);
if
(
nwritten
<
0
)
{
if
(
errno
==
EINTR
)
continue
;
err
=
my_error_from_syserror
();
break
;
/* Write error. */
}
length
-=
nwritten
;
if
(
parm
->
stream
)
{
if
(
length
==
0
)
{
err
=
es_read
(
parm
->
stream
,
buffer
,
sizeof
_buffer
,
&
length
);
if
(
err
)
{
log_error
(
"reading stream failed: %s
\n
"
,
gpg_strerror
(
err
));
break
;
}
if
(
length
==
0
)
/* We're done. */
break
;
}
}
else
buffer
+=
nwritten
;
}
leave
:
*
parm
->
err_addr
=
err
;
if
(
close
(
parm
->
fd
))
log_error
(
"closing writer fd %d failed: %s
\n
"
,
parm
->
fd
,
strerror
(
errno
));
xfree
(
parm
);
return
NULL
;
}
/* Fire up a thread to send (DATA,DATALEN) to the file descriptor FD.
On success the thread receives the ownership over FD. The thread
ID is stored at R_TID. WRITER_ERR is the address of an gpg_error_t
variable to receive a possible write error after the thread has
finished. */
static
gpg_error_t
start_writer
(
int
fd
,
const
void
*
data
,
size_t
datalen
,
estream_t
stream
,
npth_t
*
r_thread
,
gpg_error_t
*
err_addr
)
{
gpg_error_t
err
;
struct
writer_thread_parms
*
parm
;
npth_attr_t
tattr
;
npth_t
thread
;
int
ret
;
memset
(
r_thread
,
'\0'
,
sizeof
(
*
r_thread
));
*
err_addr
=
0
;
parm
=
xtrymalloc
(
sizeof
*
parm
);
if
(
!
parm
)
return
my_error_from_syserror
();
parm
->
fd
=
fd
;
parm
->
data
=
data
;
parm
->
datalen
=
datalen
;
parm
->
stream
=
stream
;
parm
->
err_addr
=
err_addr
;
npth_attr_init
(
&
tattr
);
npth_attr_setdetachstate
(
&
tattr
,
NPTH_CREATE_JOINABLE
);
ret
=
npth_create
(
&
thread
,
&
tattr
,
writer_thread_main
,
parm
);
if
(
ret
)
{
err
=
my_error_from_errno
(
ret
);
log_error
(
"error spawning writer thread: %s
\n
"
,
gpg_strerror
(
err
));
}
else
{
npth_setname_np
(
thread
,
"fd-writer"
);
err
=
0
;
*
r_thread
=
thread
;
}
npth_attr_destroy
(
&
tattr
);
return
err
;
}
/* The data passed to the reader_thread. */
struct
reader_thread_parms
{
int
fd
;
membuf_t
*
mb
;
estream_t
stream
;
gpg_error_t
*
err_addr
;
};
/* The thread started by start_reader. */
static
void
*
reader_thread_main
(
void
*
arg
)
{
gpg_error_t
err
=
0
;
struct
reader_thread_parms
*
parm
=
arg
;
char
buffer
[
4096
];
int
nread
;
while
(
(
nread
=
npth_read
(
parm
->
fd
,
buffer
,
sizeof
buffer
))
)
{
if
(
nread
<
0
)
{
if
(
errno
==
EINTR
)
continue
;
err
=
my_error_from_syserror
();
break
;
/* Read error. */
}
if
(
parm
->
stream
)
{
const
char
*
p
=
buffer
;
size_t
nwritten
;
while
(
nread
)
{
err
=
es_write
(
parm
->
stream
,
p
,
nread
,
&
nwritten
);
if
(
err
)
{
log_error
(
"writing stream failed: %s
\n
"
,
gpg_strerror
(
err
));
goto
leave
;
}
nread
-=
nwritten
;
p
+=
nwritten
;
}
}
else
put_membuf
(
parm
->
mb
,
buffer
,
nread
);
}
leave
:
*
parm
->
err_addr
=
err
;
if
(
close
(
parm
->
fd
))
log_error
(
"closing reader fd %d failed: %s
\n
"
,
parm
->
fd
,
strerror
(
errno
));
xfree
(
parm
);
return
NULL
;
}
/* Fire up a thread to receive data from the file descriptor FD. On
success the thread receives the ownership over FD. The thread ID
is stored at R_TID. After the thread has finished an error from
the thread will be stored at ERR_ADDR. */
static
gpg_error_t
start_reader
(
int
fd
,
membuf_t
*
mb
,
estream_t
stream
,
npth_t
*
r_thread
,
gpg_error_t
*
err_addr
)
{
gpg_error_t
err
;
struct
reader_thread_parms
*
parm
;
npth_attr_t
tattr
;
npth_t
thread
;
int
ret
;
memset
(
r_thread
,
'\0'
,
sizeof
(
*
r_thread
));
*
err_addr
=
0
;
parm
=
xtrymalloc
(
sizeof
*
parm
);
if
(
!
parm
)
return
my_error_from_syserror
();
parm
->
fd
=
fd
;
parm
->
mb
=
mb
;
parm
->
stream
=
stream
;
parm
->
err_addr
=
err_addr
;
npth_attr_init
(
&
tattr
);
npth_attr_setdetachstate
(
&
tattr
,
NPTH_CREATE_JOINABLE
);
ret
=
npth_create
(
&
thread
,
&
tattr
,
reader_thread_main
,
parm
);
if
(
ret
)
{
err
=
my_error_from_errno
(
ret
);
log_error
(
"error spawning reader thread: %s
\n
"
,
gpg_strerror
(
err
));
}
else
{
npth_setname_np
(
thread
,
"fd-reader"
);
err
=
0
;
*
r_thread
=
thread
;
}
npth_attr_destroy
(
&
tattr
);
return
err
;
}
/* Call GPG to encrypt a block of data.
*/
static
gpg_error_t
_gpg_encrypt
(
ctrl_t
ctrl
,
const
char
*
gpg_program
,
strlist_t
gpg_arguments
,
const
void
*
plain
,
size_t
plainlen
,
estream_t
plain_stream
,
strlist_t
keys
,
membuf_t
*
reader_mb
,
estream_t
cipher_stream
)
{
gpg_error_t
err
;
assuan_context_t
ctx
=
NULL
;
int
outbound_fds
[
2
]
=
{
-1
,
-1
};
int
inbound_fds
[
2
]
=
{
-1
,
-1
};
npth_t
writer_thread
=
(
npth_t
)
0
;
npth_t
reader_thread
=
(
npth_t
)
0
;
gpg_error_t
writer_err
,
reader_err
;
char
line
[
ASSUAN_LINELENGTH
];
strlist_t
sl
;
int
ret
;
/* Make sure that either the stream interface xor the buffer
interface is used. */
assert
((
plain
==
NULL
)
!=
(
plain_stream
==
NULL
));
assert
((
reader_mb
==
NULL
)
!=
(
cipher_stream
==
NULL
));
/* Create two pipes. */
err
=
gnupg_create_outbound_pipe
(
outbound_fds
,
NULL
,
0
);
if
(
!
err
)
err
=
gnupg_create_inbound_pipe
(
inbound_fds
,
NULL
,
0
);
if
(
err
)
{
log_error
(
_
(
"error creating a pipe: %s
\n
"
),
gpg_strerror
(
err
));
goto
leave
;
}
/* Start GPG and send the INPUT and OUTPUT commands. */
err
=
start_gpg
(
ctrl
,
gpg_program
,
gpg_arguments
,
outbound_fds
[
0
],
inbound_fds
[
1
],
&
ctx
);
if
(
err
)
goto
leave
;
close
(
outbound_fds
[
0
]);
outbound_fds
[
0
]
=
-1
;
close
(
inbound_fds
[
1
]);
inbound_fds
[
1
]
=
-1
;
/* Start a writer thread to feed the INPUT command of the server. */
err
=
start_writer
(
outbound_fds
[
1
],
plain
,
plainlen
,
plain_stream
,
&
writer_thread
,
&
writer_err
);
if
(
err
)
return
err
;
outbound_fds
[
1
]
=
-1
;
/* The thread owns the FD now. */
/* Start a reader thread to eat from the OUTPUT command of the
server. */
err
=
start_reader
(
inbound_fds
[
0
],
reader_mb
,
cipher_stream
,
&
reader_thread
,
&
reader_err
);
if
(
err
)
return
err
;
outbound_fds
[
0
]
=
-1
;
/* The thread owns the FD now. */
/* Run the encryption. */
for
(
sl
=
keys
;
sl
;
sl
=
sl
->
next
)
{
snprintf
(
line
,
sizeof
line
,
"RECIPIENT -- %s"
,
sl
->
d
);
err
=
assuan_transact
(
ctx
,
line
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
);
if
(
err
)
{
log_error
(
"the engine's RECIPIENT command failed: %s <%s>
\n
"
,
gpg_strerror
(
err
),
gpg_strsource
(
err
));
goto
leave
;
}
}
err
=
assuan_transact
(
ctx
,
"ENCRYPT"
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
);
if
(
err
)
{
log_error
(
"the engine's ENCRYPT command failed: %s <%s>
\n
"
,
gpg_strerror
(
err
),
gpg_strsource
(
err
));
goto
leave
;
}
/* Wait for reader and return the data. */
ret
=
npth_join
(
reader_thread
,
NULL
);
if
(
ret
)
{
err
=
my_error_from_errno
(
ret
);
log_error
(
"waiting for reader thread failed: %s
\n
"
,
gpg_strerror
(
err
));
goto
leave
;
}
/* FIXME: Not really valid, as npth_t is an opaque type. */
memset
(
&
reader_thread
,
'\0'
,
sizeof
(
reader_thread
));
if
(
reader_err
)
{
err
=
reader_err
;
log_error
(
"read error in reader thread: %s
\n
"
,
gpg_strerror
(
err
));
goto
leave
;
}
/* Wait for the writer to catch a writer error. */
ret
=
npth_join
(
writer_thread
,
NULL
);
if
(
ret
)
{
err
=
my_error_from_errno
(
ret
);
log_error
(
"waiting for writer thread failed: %s
\n
"
,
gpg_strerror
(
err
));
goto
leave
;
}
memset
(
&
writer_thread
,
'\0'
,
sizeof
(
writer_thread
));
if
(
writer_err
)
{
err
=
writer_err
;
log_error
(
"write error in writer thread: %s
\n
"
,
gpg_strerror
(
err
));
goto
leave
;
}
leave
:
/* FIXME: Not valid, as npth_t is an opaque type. */
if
(
reader_thread
)
npth_detach
(
reader_thread
);
if
(
writer_thread
)
npth_detach
(
writer_thread
);
if
(
outbound_fds
[
0
]
!=
-1
)
close
(
outbound_fds
[
0
]);
if
(
outbound_fds
[
1
]
!=
-1
)
close
(
outbound_fds
[
1
]);
if
(
inbound_fds
[
0
]
!=
-1
)
close
(
inbound_fds
[
0
]);
if
(
inbound_fds
[
1
]
!=
-1
)
close
(
inbound_fds
[
1
]);
release_gpg
(
ctx
);
return
err
;
}
gpg_error_t
gpg_encrypt_blob
(
ctrl_t
ctrl
,
const
char
*
gpg_program
,
strlist_t
gpg_arguments
,
const
void
*
plain
,
size_t
plainlen
,
strlist_t
keys
,
void
**
r_ciph
,
size_t
*
r_ciphlen
)
{
gpg_error_t
err
;
membuf_t
reader_mb
;
*
r_ciph
=
NULL
;
*
r_ciphlen
=
0
;
/* Init the memory buffer to receive the encrypted stuff. */
init_membuf
(
&
reader_mb
,
4096
);
err
=
_gpg_encrypt
(
ctrl
,
gpg_program
,
gpg_arguments
,
plain
,
plainlen
,
NULL
,
keys
,
&
reader_mb
,
NULL
);
if
(
!
err
)
{
/* Return the data. */
*
r_ciph
=
get_membuf
(
&
reader_mb
,
r_ciphlen
);
if
(
!*
r_ciph
)
{
err
=
my_error_from_syserror
();
log_error
(
"error while storing the data in the reader thread: %s
\n
"
,
gpg_strerror
(
err
));
}
}
xfree
(
get_membuf
(
&
reader_mb
,
NULL
));
return
err
;
}
gpg_error_t
gpg_encrypt_stream
(
ctrl_t
ctrl
,
const
char
*
gpg_program
,
strlist_t
gpg_arguments
,
estream_t
plain_stream
,
strlist_t
keys
,
estream_t
cipher_stream
)
{
return
_gpg_encrypt
(
ctrl
,
gpg_program
,
gpg_arguments
,
NULL
,
0
,
plain_stream
,
keys
,
NULL
,
cipher_stream
);
}
/* Call GPG to decrypt a block of data.
*/
static
gpg_error_t
_gpg_decrypt
(
ctrl_t
ctrl
,
const
char
*
gpg_program
,
strlist_t
gpg_arguments
,
const
void
*
ciph
,
size_t
ciphlen
,
estream_t
cipher_stream
,
membuf_t
*
reader_mb
,
estream_t
plain_stream
)
{
gpg_error_t
err
;
assuan_context_t
ctx
=
NULL
;
int
outbound_fds
[
2
]
=
{
-1
,
-1
};
int
inbound_fds
[
2
]
=
{
-1
,
-1
};
npth_t
writer_thread
=
(
npth_t
)
0
;
npth_t
reader_thread
=
(
npth_t
)
0
;
gpg_error_t
writer_err
,
reader_err
;
int
ret
;
/* Make sure that either the stream interface xor the buffer
interface is used. */
assert
((
ciph
==
NULL
)
!=
(
cipher_stream
==
NULL
));
assert
((
reader_mb
==
NULL
)
!=
(
plain_stream
==
NULL
));
/* Create two pipes. */
err
=
gnupg_create_outbound_pipe
(
outbound_fds
,
NULL
,
0
);
if
(
!
err
)
err
=
gnupg_create_inbound_pipe
(
inbound_fds
,
NULL
,
0
);
if
(
err
)
{
log_error
(
_
(
"error creating a pipe: %s
\n
"
),
gpg_strerror
(
err
));
goto
leave
;
}
/* Start GPG and send the INPUT and OUTPUT commands. */
err
=
start_gpg
(
ctrl
,
gpg_program
,
gpg_arguments
,
outbound_fds
[
0
],
inbound_fds
[
1
],
&
ctx
);
if
(
err
)
goto
leave
;
close
(
outbound_fds
[
0
]);
outbound_fds
[
0
]
=
-1
;
close
(
inbound_fds
[
1
]);
inbound_fds
[
1
]
=
-1
;
/* Start a writer thread to feed the INPUT command of the server. */
err
=
start_writer
(
outbound_fds
[
1
],
ciph
,
ciphlen
,
cipher_stream
,
&
writer_thread
,
&
writer_err
);
if
(
err
)
return
err
;
outbound_fds
[
1
]
=
-1
;
/* The thread owns the FD now. */
/* Start a reader thread to eat from the OUTPUT command of the
server. */
err
=
start_reader
(
inbound_fds
[
0
],
reader_mb
,
plain_stream
,
&
reader_thread
,
&
reader_err
);
if
(
err
)
return
err
;
outbound_fds
[
0
]
=
-1
;
/* The thread owns the FD now. */
/* Run the decryption. */
err
=
assuan_transact
(
ctx
,
"DECRYPT"
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
);
if
(
err
)
{
log_error
(
"the engine's DECRYPT command failed: %s <%s>
\n
"
,
gpg_strerror
(
err
),
gpg_strsource
(
err
));
goto
leave
;
}
/* Wait for reader and return the data. */
ret
=
npth_join
(
reader_thread
,
NULL
);
if
(
ret
)
{
err
=
my_error_from_errno
(
ret
);
log_error
(
"waiting for reader thread failed: %s
\n
"
,
gpg_strerror
(
err
));
goto
leave
;
}
memset
(
&
reader_thread
,
'\0'
,
sizeof
(
reader_thread
));
if
(
reader_err
)
{
err
=
reader_err
;
log_error
(
"read error in reader thread: %s
\n
"
,
gpg_strerror
(
err
));
goto
leave
;
}
/* Wait for the writer to catch a writer error. */
ret
=
npth_join
(
writer_thread
,
NULL
);
if
(
ret
)
{
err
=
my_error_from_errno
(
ret
);
log_error
(
"waiting for writer thread failed: %s
\n
"
,
gpg_strerror
(
err
));
goto
leave
;
}
memset
(
&
writer_thread
,
'\0'
,
sizeof
(
writer_thread
));
if
(
writer_err
)
{
err
=
writer_err
;
log_error
(
"write error in writer thread: %s
\n
"
,
gpg_strerror
(
err
));
goto
leave
;
}
leave
:
if
(
reader_thread
)
npth_detach
(
reader_thread
);
if
(
writer_thread
)
npth_detach
(
writer_thread
);
if
(
outbound_fds
[
0
]
!=
-1
)
close
(
outbound_fds
[
0
]);
if
(
outbound_fds
[
1
]
!=
-1
)
close
(
outbound_fds
[
1
]);
if
(
inbound_fds
[
0
]
!=
-1
)
close
(
inbound_fds
[
0
]);
if
(
inbound_fds
[
1
]
!=
-1
)
close
(
inbound_fds
[
1
]);
release_gpg
(
ctx
);
return
err
;
}
gpg_error_t
gpg_decrypt_blob
(
ctrl_t
ctrl
,
const
char
*
gpg_program
,
strlist_t
gpg_arguments
,
const
void
*
ciph
,
size_t
ciphlen
,
void
**
r_plain
,
size_t
*
r_plainlen
)
{
gpg_error_t
err
;
membuf_t
reader_mb
;
*
r_plain
=
NULL
;
*
r_plainlen
=
0
;
/* Init the memory buffer to receive the encrypted stuff. */
init_membuf_secure
(
&
reader_mb
,
1024
);
err
=
_gpg_decrypt
(
ctrl
,
gpg_program
,
gpg_arguments
,
ciph
,
ciphlen
,
NULL
,
&
reader_mb
,
NULL
);
if
(
!
err
)
{
/* Return the data. */
*
r_plain
=
get_membuf
(
&
reader_mb
,
r_plainlen
);
if
(
!*
r_plain
)
{
err
=
my_error_from_syserror
();
log_error
(
"error while storing the data in the reader thread: %s
\n
"
,
gpg_strerror
(
err
));
}
}
xfree
(
get_membuf
(
&
reader_mb
,
NULL
));
return
err
;
}
gpg_error_t
gpg_decrypt_stream
(
ctrl_t
ctrl
,
const
char
*
gpg_program
,
strlist_t
gpg_arguments
,
estream_t
cipher_stream
,
estream_t
plain_stream
)
{
return
_gpg_decrypt
(
ctrl
,
gpg_program
,
gpg_arguments
,
NULL
,
0
,
cipher_stream
,
NULL
,
plain_stream
);
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sat, Nov 22, 1:28 PM (1 d, 13 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
68/d2/56f72f49c700df8fd79570c4513f
Attached To
rG GnuPG
Event Timeline
Log In to Comment