mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-02 22:46:30 +02:00
Preparing 2.0.4
This commit is contained in:
parent
8bf339ab59
commit
edb3dc99e9
44 changed files with 2519 additions and 1922 deletions
|
@ -1,3 +1,8 @@
|
|||
2007-05-08 Werner Koch <wk@g10code.com>
|
||||
|
||||
* sockprox.c: New. It needs to be build manually. By Moritz
|
||||
Schulte.
|
||||
|
||||
2007-04-20 Werner Koch <wk@g10code.com>
|
||||
|
||||
* symcryptrun.c (my_gcry_logger): Removed.
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
EXTRA_DIST = \
|
||||
Manifest watchgnupg.c \
|
||||
addgnupghome applygnupgdefaults gpgsm-gencert.sh \
|
||||
lspgpot mail-signed-keys convert-from-106
|
||||
lspgpot mail-signed-keys convert-from-106 sockprox.c
|
||||
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/common
|
||||
|
|
553
tools/sockprox.c
Normal file
553
tools/sockprox.c
Normal file
|
@ -0,0 +1,553 @@
|
|||
/* sockprox - Proxy for local sockets with logging facilities
|
||||
* Copyright (C) 2007 g10 Code GmbH.
|
||||
*
|
||||
* sockprox 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.
|
||||
*
|
||||
* sockprox 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/* Hacked by Moritz Schulte <moritz@g10code.com>.
|
||||
|
||||
Usage example:
|
||||
|
||||
Run a server which binds to a local socket. For example,
|
||||
gpg-agent. gpg-agent's local socket is specified with --server.
|
||||
sockprox opens a new local socket (here "mysock"); the whole
|
||||
traffic between server and client is written to "/tmp/prot" in this
|
||||
case.
|
||||
|
||||
./sockprox --server /tmp/gpg-PKdD8r/S.gpg-agent.ssh \
|
||||
--listen mysock --protocol /tmp/prot
|
||||
|
||||
Then, redirect your ssh-agent client to sockprox by setting
|
||||
SSH_AUTH_SOCK to "mysock".
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
|
||||
struct opt
|
||||
{
|
||||
char *protocol_file;
|
||||
char *server_spec;
|
||||
char *listen_spec;
|
||||
int verbose;
|
||||
};
|
||||
|
||||
struct opt opt = { NULL, NULL, NULL, 0 };
|
||||
|
||||
struct thread_data
|
||||
{
|
||||
int client_sock;
|
||||
FILE *protocol_file;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static int
|
||||
create_server_socket (const char *filename, int *new_sock)
|
||||
{
|
||||
struct sockaddr_un name;
|
||||
size_t size;
|
||||
int sock;
|
||||
int ret;
|
||||
int err;
|
||||
|
||||
/* Create the socket. */
|
||||
sock = socket (PF_LOCAL, SOCK_STREAM, 0);
|
||||
if (sock < 0)
|
||||
{
|
||||
err = errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Bind a name to the socket. */
|
||||
name.sun_family = AF_LOCAL;
|
||||
strncpy (name.sun_path, filename, sizeof (name.sun_path));
|
||||
name.sun_path[sizeof (name.sun_path) - 1] = '\0';
|
||||
|
||||
size = SUN_LEN (&name);
|
||||
|
||||
remove (filename);
|
||||
|
||||
ret = bind (sock, (struct sockaddr *) &name, size);
|
||||
if (ret < 0)
|
||||
{
|
||||
err = errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = listen (sock, 2);
|
||||
if (ret < 0)
|
||||
{
|
||||
err = errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*new_sock = sock;
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
connect_to_socket (const char *filename, int *new_sock)
|
||||
{
|
||||
struct sockaddr_un srvr_addr;
|
||||
size_t len;
|
||||
int sock;
|
||||
int ret;
|
||||
int err;
|
||||
|
||||
sock = socket (PF_LOCAL, SOCK_STREAM, 0);
|
||||
if (sock == -1)
|
||||
{
|
||||
err = errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset (&srvr_addr, 0, sizeof srvr_addr);
|
||||
srvr_addr.sun_family = AF_LOCAL;
|
||||
strncpy (srvr_addr.sun_path, filename, sizeof (srvr_addr.sun_path) - 1);
|
||||
srvr_addr.sun_path[sizeof (srvr_addr.sun_path) - 1] = 0;
|
||||
len = SUN_LEN (&srvr_addr);
|
||||
|
||||
ret = connect (sock, (struct sockaddr *) &srvr_addr, len);
|
||||
if (ret == -1)
|
||||
{
|
||||
close (sock);
|
||||
err = errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*new_sock = sock;
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
log_data (unsigned char *data, size_t length,
|
||||
FILE *from, FILE *to, FILE *protocol)
|
||||
{
|
||||
unsigned int i;
|
||||
int ret;
|
||||
int err;
|
||||
|
||||
flockfile (protocol);
|
||||
fprintf (protocol, "%i -> %i: ", fileno (from), fileno (to));
|
||||
for (i = 0; i < length; i++)
|
||||
fprintf (protocol, "%02X", data[i]);
|
||||
fprintf (protocol, "\n");
|
||||
funlockfile (protocol);
|
||||
|
||||
ret = fflush (protocol);
|
||||
if (ret == EOF)
|
||||
err = errno;
|
||||
else
|
||||
err = 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
transfer_data (FILE *from, FILE *to, FILE *protocol)
|
||||
{
|
||||
unsigned char buffer[BUFSIZ];
|
||||
size_t len, written;
|
||||
int err;
|
||||
int ret;
|
||||
|
||||
err = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
len = fread (buffer, 1, sizeof (buffer), from);
|
||||
if (len == 0)
|
||||
break;
|
||||
|
||||
err = log_data (buffer, len, from, to, protocol);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
written = fwrite (buffer, 1, len, to);
|
||||
if (written != len)
|
||||
{
|
||||
err = errno;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = fflush (to);
|
||||
if (ret == EOF)
|
||||
{
|
||||
err = errno;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ferror (from))
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
io_loop (FILE *client, FILE *server, FILE *protocol)
|
||||
{
|
||||
fd_set active_fd_set, read_fd_set;
|
||||
int ret;
|
||||
int err;
|
||||
|
||||
FD_ZERO (&active_fd_set);
|
||||
FD_SET (fileno (client), &active_fd_set);
|
||||
FD_SET (fileno (server), &active_fd_set);
|
||||
|
||||
err = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
read_fd_set = active_fd_set;
|
||||
|
||||
/* FIXME: eof? */
|
||||
|
||||
ret = select (FD_SETSIZE, &read_fd_set, NULL, NULL, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
err = errno;
|
||||
break;
|
||||
}
|
||||
|
||||
if (FD_ISSET (fileno (client), &read_fd_set))
|
||||
{
|
||||
if (feof (client))
|
||||
break;
|
||||
|
||||
/* Forward data from client to server. */
|
||||
err = transfer_data (client, server, protocol);
|
||||
}
|
||||
else if (FD_ISSET (fileno (server), &read_fd_set))
|
||||
{
|
||||
if (feof (server))
|
||||
break;
|
||||
|
||||
/* Forward data from server to client. */
|
||||
err = transfer_data (server, client, protocol);
|
||||
}
|
||||
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Set the `O_NONBLOCK' flag of DESC if VALUE is nonzero,
|
||||
or clear the flag if VALUE is 0.
|
||||
Return 0 on success, or -1 on error with `errno' set. */
|
||||
|
||||
int
|
||||
set_nonblock_flag (int desc, int value)
|
||||
{
|
||||
int oldflags = fcntl (desc, F_GETFL, 0);
|
||||
int err;
|
||||
int ret;
|
||||
|
||||
/* If reading the flags failed, return error indication now. */
|
||||
if (oldflags == -1)
|
||||
return -1;
|
||||
/* Set just the flag we want to set. */
|
||||
if (value != 0)
|
||||
oldflags |= O_NONBLOCK;
|
||||
else
|
||||
oldflags &= ~O_NONBLOCK;
|
||||
/* Store modified flag word in the descriptor. */
|
||||
|
||||
ret = fcntl (desc, F_SETFL, oldflags);
|
||||
if (ret == -1)
|
||||
err = errno;
|
||||
else
|
||||
err = 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void *
|
||||
serve_client (void *data)
|
||||
{
|
||||
struct thread_data *thread_data = data;
|
||||
int client_sock = thread_data->client_sock;
|
||||
int server_sock;
|
||||
FILE *protocol = thread_data->protocol_file;
|
||||
FILE *client;
|
||||
FILE *server;
|
||||
int err;
|
||||
|
||||
client = NULL;
|
||||
server = NULL;
|
||||
|
||||
/* Connect to server. */
|
||||
err = connect_to_socket (opt.server_spec, &server_sock);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Set IO mode to nonblicking. */
|
||||
err = set_nonblock_flag (server_sock, 1);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
client = fdopen (client_sock, "r+");
|
||||
if (! client)
|
||||
{
|
||||
err = errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
server = fdopen (server_sock, "r+");
|
||||
if (! server)
|
||||
{
|
||||
err = errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = io_loop (client, server, protocol);
|
||||
|
||||
out:
|
||||
|
||||
if (client)
|
||||
fclose (client);
|
||||
else
|
||||
close (client_sock);
|
||||
|
||||
if (server)
|
||||
fclose (server);
|
||||
else
|
||||
close (server_sock);
|
||||
|
||||
free (data);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
run_proxy (void)
|
||||
{
|
||||
int client_sock;
|
||||
int my_sock;
|
||||
int err;
|
||||
struct sockaddr_un clientname;
|
||||
size_t size;
|
||||
pthread_t mythread;
|
||||
struct thread_data *thread_data;
|
||||
FILE *protocol_file;
|
||||
pthread_attr_t thread_attr;
|
||||
|
||||
protocol_file = NULL;
|
||||
|
||||
err = pthread_attr_init (&thread_attr);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = pthread_attr_setdetachstate (&thread_attr, PTHREAD_CREATE_DETACHED);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (opt.protocol_file)
|
||||
{
|
||||
protocol_file = fopen (opt.protocol_file, "a");
|
||||
if (! protocol_file)
|
||||
{
|
||||
err = errno;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else
|
||||
protocol_file = stdout;
|
||||
|
||||
err = create_server_socket (opt.listen_spec, &my_sock);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Accept new client. */
|
||||
size = sizeof (clientname);
|
||||
client_sock = accept (my_sock,
|
||||
(struct sockaddr *) &clientname,
|
||||
&size);
|
||||
if (client_sock < 0)
|
||||
{
|
||||
err = errno;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set IO mode to nonblicking. */
|
||||
err = set_nonblock_flag (client_sock, 1);
|
||||
if (err)
|
||||
{
|
||||
close (client_sock);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Got new client -> handle in new process. */
|
||||
|
||||
thread_data = malloc (sizeof (*thread_data));
|
||||
if (! thread_data)
|
||||
{
|
||||
err = errno;
|
||||
break;
|
||||
}
|
||||
thread_data->client_sock = client_sock;
|
||||
thread_data->protocol_file = protocol_file;
|
||||
|
||||
err = pthread_create (&mythread, &thread_attr, serve_client, thread_data);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* ? */
|
||||
|
||||
out:
|
||||
|
||||
pthread_attr_destroy (&thread_attr);
|
||||
fclose (protocol_file); /* FIXME, err checking. */
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
print_help (int ret)
|
||||
{
|
||||
printf ("Usage: sockprox [options] "
|
||||
"--server SERVER-SOCKET --listen PROXY-SOCKET\n");
|
||||
exit (ret);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
struct option long_options[] =
|
||||
{
|
||||
{ "help", no_argument, 0, 'h' },
|
||||
{ "verbose", no_argument, &opt.verbose, 1 },
|
||||
{ "protocol", required_argument, 0, 'p' },
|
||||
{ "server", required_argument, 0, 's' },
|
||||
{ "listen", required_argument, 0, 'l' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
int ret;
|
||||
int err;
|
||||
int c;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int opt_idx = 0;
|
||||
c = getopt_long (argc, argv, "hvp:s:l:",
|
||||
long_options, &opt_idx);
|
||||
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 0:
|
||||
if (long_options[opt_idx].flag)
|
||||
break;
|
||||
printf ("option %s", long_options[opt_idx].name);
|
||||
if (optarg)
|
||||
printf (" with arg %s", optarg);
|
||||
printf ("\n");
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
opt.protocol_file = optarg;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
opt.server_spec = optarg;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
opt.listen_spec = optarg;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
opt.verbose = 1;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
print_help (EXIT_SUCCESS);
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
if (opt.verbose)
|
||||
{
|
||||
printf ("server: %s\n", opt.server_spec ? opt.server_spec : "");
|
||||
printf ("listen: %s\n", opt.listen_spec ? opt.listen_spec : "");
|
||||
printf ("protocol: %s\n", opt.protocol_file ? opt.protocol_file : "");
|
||||
}
|
||||
|
||||
if (! (opt.server_spec && opt.listen_spec))
|
||||
print_help (EXIT_FAILURE);
|
||||
|
||||
err = run_proxy ();
|
||||
if (err)
|
||||
{
|
||||
fprintf (stderr, "run_proxy() failed: %s\n", strerror (err));
|
||||
ret = EXIT_FAILURE;
|
||||
}
|
||||
else
|
||||
/* ? */
|
||||
ret = EXIT_SUCCESS;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
compile-command: "cc -Wall -g -o sockprox sockprox.c -lpthread"
|
||||
End:
|
||||
*/
|
Loading…
Add table
Add a link
Reference in a new issue