2003-08-05 17:11:04 +00:00
|
|
|
|
/* server.c - Server mode and main entry point
|
2004-05-11 09:15:56 +00:00
|
|
|
|
* Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
|
2003-08-05 17:11:04 +00:00
|
|
|
|
*
|
|
|
|
|
* 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 2 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, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
|
|
#include <assuan.h>
|
|
|
|
|
|
|
|
|
|
#include "gpgsm.h"
|
|
|
|
|
|
|
|
|
|
#define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* The filepointer for status message used in non-server mode */
|
|
|
|
|
static FILE *statusfp;
|
|
|
|
|
|
|
|
|
|
/* Data used to assuciate an Assuan context with local server data */
|
|
|
|
|
struct server_local_s {
|
2003-12-17 17:12:14 +00:00
|
|
|
|
assuan_context_t assuan_ctx;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
int message_fd;
|
|
|
|
|
int list_internal;
|
|
|
|
|
int list_external;
|
2003-12-17 17:12:14 +00:00
|
|
|
|
certlist_t recplist;
|
|
|
|
|
certlist_t signerlist;
|
|
|
|
|
certlist_t default_recplist; /* As set by main() - don't release. */
|
2003-08-05 17:11:04 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-12-16 11:31:46 +00:00
|
|
|
|
/* Note that it is sufficient to allocate the target string D as
|
2003-08-05 17:11:04 +00:00
|
|
|
|
long as the source string S, i.e.: strlen(s)+1; */
|
|
|
|
|
static void
|
|
|
|
|
strcpy_escaped_plus (char *d, const unsigned char *s)
|
|
|
|
|
{
|
|
|
|
|
while (*s)
|
|
|
|
|
{
|
|
|
|
|
if (*s == '%' && s[1] && s[2])
|
|
|
|
|
{
|
|
|
|
|
s++;
|
|
|
|
|
*d++ = xtoi_2 ( s);
|
|
|
|
|
s += 2;
|
|
|
|
|
}
|
|
|
|
|
else if (*s == '+')
|
|
|
|
|
*d++ = ' ', s++;
|
|
|
|
|
else
|
|
|
|
|
*d++ = *s++;
|
|
|
|
|
}
|
|
|
|
|
*d = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Check whether the option NAME appears in LINE */
|
|
|
|
|
static int
|
|
|
|
|
has_option (const char *line, const char *name)
|
|
|
|
|
{
|
|
|
|
|
const char *s;
|
|
|
|
|
int n = strlen (name);
|
|
|
|
|
|
|
|
|
|
s = strstr (line, name);
|
|
|
|
|
return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
close_message_fd (CTRL ctrl)
|
|
|
|
|
{
|
|
|
|
|
if (ctrl->server_local->message_fd != -1)
|
|
|
|
|
{
|
|
|
|
|
close (ctrl->server_local->message_fd);
|
|
|
|
|
ctrl->server_local->message_fd = -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
|
|
|
|
|
{
|
|
|
|
|
CTRL ctrl = assuan_get_pointer (ctx);
|
|
|
|
|
|
|
|
|
|
if (!strcmp (key, "include-certs"))
|
|
|
|
|
{
|
|
|
|
|
int i = *value? atoi (value) : -1;
|
|
|
|
|
if (ctrl->include_certs < -2)
|
|
|
|
|
return ASSUAN_Parameter_Error;
|
|
|
|
|
ctrl->include_certs = i;
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (key, "display"))
|
|
|
|
|
{
|
|
|
|
|
if (opt.display)
|
|
|
|
|
free (opt.display);
|
|
|
|
|
opt.display = strdup (value);
|
|
|
|
|
if (!opt.display)
|
|
|
|
|
return ASSUAN_Out_Of_Core;
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (key, "ttyname"))
|
|
|
|
|
{
|
|
|
|
|
if (opt.ttyname)
|
|
|
|
|
free (opt.ttyname);
|
|
|
|
|
opt.ttyname = strdup (value);
|
|
|
|
|
if (!opt.ttyname)
|
|
|
|
|
return ASSUAN_Out_Of_Core;
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (key, "ttytype"))
|
|
|
|
|
{
|
|
|
|
|
if (opt.ttytype)
|
|
|
|
|
free (opt.ttytype);
|
|
|
|
|
opt.ttytype = strdup (value);
|
|
|
|
|
if (!opt.ttytype)
|
|
|
|
|
return ASSUAN_Out_Of_Core;
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (key, "lc-ctype"))
|
|
|
|
|
{
|
|
|
|
|
if (opt.lc_ctype)
|
|
|
|
|
free (opt.lc_ctype);
|
|
|
|
|
opt.lc_ctype = strdup (value);
|
|
|
|
|
if (!opt.lc_ctype)
|
|
|
|
|
return ASSUAN_Out_Of_Core;
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (key, "lc-messages"))
|
|
|
|
|
{
|
|
|
|
|
if (opt.lc_messages)
|
|
|
|
|
free (opt.lc_messages);
|
|
|
|
|
opt.lc_messages = strdup (value);
|
|
|
|
|
if (!opt.lc_messages)
|
|
|
|
|
return ASSUAN_Out_Of_Core;
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (key, "list-mode"))
|
|
|
|
|
{
|
|
|
|
|
int i = *value? atoi (value) : 0;
|
|
|
|
|
if (!i || i == 1) /* default and mode 1 */
|
|
|
|
|
{
|
|
|
|
|
ctrl->server_local->list_internal = 1;
|
|
|
|
|
ctrl->server_local->list_external = 0;
|
|
|
|
|
}
|
|
|
|
|
else if (i == 2)
|
|
|
|
|
{
|
|
|
|
|
ctrl->server_local->list_internal = 0;
|
|
|
|
|
ctrl->server_local->list_external = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (i == 3)
|
|
|
|
|
{
|
|
|
|
|
ctrl->server_local->list_internal = 1;
|
|
|
|
|
ctrl->server_local->list_external = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return ASSUAN_Parameter_Error;
|
|
|
|
|
}
|
2004-02-17 15:05:04 +00:00
|
|
|
|
else if (!strcmp (key, "with-validation"))
|
|
|
|
|
{
|
2004-02-17 17:21:07 +00:00
|
|
|
|
int i = *value? atoi (value) : 0;
|
|
|
|
|
ctrl->with_validation = i;
|
2004-02-17 15:05:04 +00:00
|
|
|
|
}
|
2003-08-05 17:11:04 +00:00
|
|
|
|
else
|
|
|
|
|
return ASSUAN_Invalid_Option;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
reset_notify (ASSUAN_CONTEXT ctx)
|
|
|
|
|
{
|
|
|
|
|
CTRL ctrl = assuan_get_pointer (ctx);
|
|
|
|
|
|
|
|
|
|
gpgsm_release_certlist (ctrl->server_local->recplist);
|
|
|
|
|
gpgsm_release_certlist (ctrl->server_local->signerlist);
|
|
|
|
|
ctrl->server_local->recplist = NULL;
|
|
|
|
|
ctrl->server_local->signerlist = NULL;
|
|
|
|
|
close_message_fd (ctrl);
|
|
|
|
|
assuan_close_input_fd (ctx);
|
|
|
|
|
assuan_close_output_fd (ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
input_notify (ASSUAN_CONTEXT ctx, const char *line)
|
|
|
|
|
{
|
|
|
|
|
CTRL ctrl = assuan_get_pointer (ctx);
|
|
|
|
|
|
|
|
|
|
ctrl->autodetect_encoding = 0;
|
|
|
|
|
ctrl->is_pem = 0;
|
|
|
|
|
ctrl->is_base64 = 0;
|
|
|
|
|
if (strstr (line, "--armor"))
|
|
|
|
|
ctrl->is_pem = 1;
|
|
|
|
|
else if (strstr (line, "--base64"))
|
|
|
|
|
ctrl->is_base64 = 1;
|
|
|
|
|
else if (strstr (line, "--binary"))
|
|
|
|
|
;
|
|
|
|
|
else
|
|
|
|
|
ctrl->autodetect_encoding = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
output_notify (ASSUAN_CONTEXT ctx, const char *line)
|
|
|
|
|
{
|
|
|
|
|
CTRL ctrl = assuan_get_pointer (ctx);
|
|
|
|
|
|
|
|
|
|
ctrl->create_pem = 0;
|
|
|
|
|
ctrl->create_base64 = 0;
|
|
|
|
|
if (strstr (line, "--armor"))
|
|
|
|
|
ctrl->create_pem = 1;
|
|
|
|
|
else if (strstr (line, "--base64"))
|
|
|
|
|
ctrl->create_base64 = 1; /* just the raw output */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* RECIPIENT <userID>
|
|
|
|
|
|
|
|
|
|
Set the recipient for the encryption. <userID> should be the
|
|
|
|
|
internal representation of the key; the server may accept any other
|
|
|
|
|
way of specification [we will support this]. If this is a valid and
|
|
|
|
|
trusted recipient the server does respond with OK, otherwise the
|
|
|
|
|
return is an ERR with the reason why the recipient can't be used,
|
2003-12-17 17:12:14 +00:00
|
|
|
|
the encryption will then not be done for this recipient. If the
|
2003-08-05 17:11:04 +00:00
|
|
|
|
policy is not to encrypt at all if not all recipients are valid, the
|
|
|
|
|
client has to take care of this. All RECIPIENT commands are
|
|
|
|
|
cumulative until a RESET or an successful ENCRYPT command. */
|
|
|
|
|
static int
|
|
|
|
|
cmd_recipient (ASSUAN_CONTEXT ctx, char *line)
|
|
|
|
|
{
|
|
|
|
|
CTRL ctrl = assuan_get_pointer (ctx);
|
|
|
|
|
int rc;
|
|
|
|
|
|
2003-12-17 17:12:14 +00:00
|
|
|
|
rc = gpgsm_add_to_certlist (ctrl, line, 0, &ctrl->server_local->recplist, 0);
|
2003-08-05 17:11:04 +00:00
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
gpg_err_code_t r = gpg_err_code (rc);
|
|
|
|
|
gpgsm_status2 (ctrl, STATUS_INV_RECP,
|
|
|
|
|
r == -1? "1":
|
|
|
|
|
r == GPG_ERR_NO_PUBKEY? "1":
|
|
|
|
|
r == GPG_ERR_AMBIGUOUS_NAME? "2":
|
|
|
|
|
r == GPG_ERR_WRONG_KEY_USAGE? "3":
|
|
|
|
|
r == GPG_ERR_CERT_REVOKED? "4":
|
|
|
|
|
r == GPG_ERR_CERT_EXPIRED? "5":
|
|
|
|
|
r == GPG_ERR_NO_CRL_KNOWN? "6":
|
|
|
|
|
r == GPG_ERR_CRL_TOO_OLD? "7":
|
|
|
|
|
r == GPG_ERR_NO_POLICY_MATCH? "8":
|
|
|
|
|
"0",
|
|
|
|
|
line, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return map_to_assuan_status (rc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* SIGNER <userID>
|
|
|
|
|
|
|
|
|
|
Set the signer's keys for the signature creation. <userID> should
|
|
|
|
|
be the internal representation of the key; the server may accept any
|
|
|
|
|
other way of specification [we will support this]. If this is a
|
|
|
|
|
valid and usable signing key the server does respond with OK,
|
|
|
|
|
otherwise it returns an ERR with the reason why the key can't be
|
|
|
|
|
used, the signing will then not be done for this key. If the policy
|
|
|
|
|
is not to sign at all if not all signer keys are valid, the client
|
|
|
|
|
has to take care of this. All SIGNER commands are cumulative until
|
|
|
|
|
a RESET but they are *not* reset by an SIGN command becuase it can
|
|
|
|
|
be expected that set of signers are used for more than one sign
|
|
|
|
|
operation.
|
|
|
|
|
|
|
|
|
|
Note that this command returns an INV_RECP status which is a bit
|
|
|
|
|
strange, but they are very similar. */
|
|
|
|
|
static int
|
|
|
|
|
cmd_signer (ASSUAN_CONTEXT ctx, char *line)
|
|
|
|
|
{
|
|
|
|
|
CTRL ctrl = assuan_get_pointer (ctx);
|
|
|
|
|
int rc;
|
|
|
|
|
|
2003-12-17 17:12:14 +00:00
|
|
|
|
rc = gpgsm_add_to_certlist (ctrl, line, 1,
|
|
|
|
|
&ctrl->server_local->signerlist, 0);
|
2003-08-05 17:11:04 +00:00
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
gpg_err_code_t r = gpg_err_code (rc);
|
|
|
|
|
gpgsm_status2 (ctrl, STATUS_INV_RECP,
|
|
|
|
|
r == -1? "1":
|
|
|
|
|
r == GPG_ERR_NO_PUBKEY? "1":
|
|
|
|
|
r == GPG_ERR_AMBIGUOUS_NAME? "2":
|
|
|
|
|
r == GPG_ERR_WRONG_KEY_USAGE? "3":
|
|
|
|
|
r == GPG_ERR_CERT_REVOKED? "4":
|
|
|
|
|
r == GPG_ERR_CERT_EXPIRED? "5":
|
|
|
|
|
r == GPG_ERR_NO_CRL_KNOWN? "6":
|
|
|
|
|
r == GPG_ERR_CRL_TOO_OLD? "7":
|
|
|
|
|
r == GPG_ERR_NO_POLICY_MATCH? "8":
|
|
|
|
|
r == GPG_ERR_NO_SECKEY? "9":
|
|
|
|
|
"0",
|
|
|
|
|
line, NULL);
|
|
|
|
|
}
|
|
|
|
|
return map_to_assuan_status (rc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ENCRYPT
|
|
|
|
|
|
|
|
|
|
Do the actual encryption process. Takes the plaintext from the INPUT
|
|
|
|
|
command, writes to the ciphertext to the file descriptor set with
|
|
|
|
|
the OUTPUT command, take the recipients form all the recipients set
|
|
|
|
|
so far. If this command fails the clients should try to delete all
|
|
|
|
|
output currently done or otherwise mark it as invalid. GPGSM does
|
|
|
|
|
ensure that there won't be any security problem with leftover data
|
|
|
|
|
on the output in this case.
|
|
|
|
|
|
|
|
|
|
This command should in general not fail, as all necessary checks
|
|
|
|
|
have been done while setting the recipients. The input and output
|
|
|
|
|
pipes are closed. */
|
|
|
|
|
static int
|
|
|
|
|
cmd_encrypt (ASSUAN_CONTEXT ctx, char *line)
|
|
|
|
|
{
|
|
|
|
|
CTRL ctrl = assuan_get_pointer (ctx);
|
2003-12-17 17:12:14 +00:00
|
|
|
|
certlist_t cl;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
int inp_fd, out_fd;
|
|
|
|
|
FILE *out_fp;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
inp_fd = assuan_get_input_fd (ctx);
|
|
|
|
|
if (inp_fd == -1)
|
|
|
|
|
return set_error (No_Input, NULL);
|
|
|
|
|
out_fd = assuan_get_output_fd (ctx);
|
|
|
|
|
if (out_fd == -1)
|
|
|
|
|
return set_error (No_Output, NULL);
|
|
|
|
|
|
|
|
|
|
out_fp = fdopen ( dup(out_fd), "w");
|
|
|
|
|
if (!out_fp)
|
|
|
|
|
return set_error (General_Error, "fdopen() failed");
|
2003-12-17 17:12:14 +00:00
|
|
|
|
|
|
|
|
|
/* Now add all encrypt-to marked recipients from the default
|
|
|
|
|
list. */
|
|
|
|
|
rc = 0;
|
|
|
|
|
if (!opt.no_encrypt_to)
|
|
|
|
|
{
|
2004-08-16 11:15:55 +00:00
|
|
|
|
for (cl=ctrl->server_local->default_recplist; !rc && cl; cl = cl->next)
|
2003-12-17 17:12:14 +00:00
|
|
|
|
if (cl->is_encrypt_to)
|
|
|
|
|
rc = gpgsm_add_cert_to_certlist (ctrl, cl->cert,
|
|
|
|
|
&ctrl->server_local->recplist, 1);
|
|
|
|
|
}
|
|
|
|
|
if (!rc)
|
|
|
|
|
rc = gpgsm_encrypt (assuan_get_pointer (ctx),
|
|
|
|
|
ctrl->server_local->recplist,
|
|
|
|
|
inp_fd, out_fp);
|
2003-08-05 17:11:04 +00:00
|
|
|
|
fclose (out_fp);
|
|
|
|
|
|
|
|
|
|
gpgsm_release_certlist (ctrl->server_local->recplist);
|
|
|
|
|
ctrl->server_local->recplist = NULL;
|
2003-12-17 17:12:14 +00:00
|
|
|
|
/* Close and reset the fd */
|
2003-08-05 17:11:04 +00:00
|
|
|
|
close_message_fd (ctrl);
|
|
|
|
|
assuan_close_input_fd (ctx);
|
|
|
|
|
assuan_close_output_fd (ctx);
|
|
|
|
|
return map_to_assuan_status (rc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* DECRYPT
|
|
|
|
|
|
|
|
|
|
This performs the decrypt operation after doing some check on the
|
|
|
|
|
internal state. (e.g. that only needed data has been set). Because
|
|
|
|
|
it utilizes the GPG-Agent for the session key decryption, there is
|
|
|
|
|
no need to ask the client for a protecting passphrase - GpgAgent
|
|
|
|
|
does take care of this by requesting this from the user. */
|
|
|
|
|
static int
|
|
|
|
|
cmd_decrypt (ASSUAN_CONTEXT ctx, char *line)
|
|
|
|
|
{
|
|
|
|
|
CTRL ctrl = assuan_get_pointer (ctx);
|
|
|
|
|
int inp_fd, out_fd;
|
|
|
|
|
FILE *out_fp;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
inp_fd = assuan_get_input_fd (ctx);
|
|
|
|
|
if (inp_fd == -1)
|
|
|
|
|
return set_error (No_Input, NULL);
|
|
|
|
|
out_fd = assuan_get_output_fd (ctx);
|
|
|
|
|
if (out_fd == -1)
|
|
|
|
|
return set_error (No_Output, NULL);
|
|
|
|
|
|
|
|
|
|
out_fp = fdopen ( dup(out_fd), "w");
|
|
|
|
|
if (!out_fp)
|
|
|
|
|
return set_error (General_Error, "fdopen() failed");
|
|
|
|
|
rc = gpgsm_decrypt (ctrl, inp_fd, out_fp);
|
|
|
|
|
fclose (out_fp);
|
|
|
|
|
|
|
|
|
|
/* close and reset the fd */
|
|
|
|
|
close_message_fd (ctrl);
|
|
|
|
|
assuan_close_input_fd (ctx);
|
|
|
|
|
assuan_close_output_fd (ctx);
|
|
|
|
|
|
|
|
|
|
return map_to_assuan_status (rc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* VERIFY
|
|
|
|
|
|
|
|
|
|
This does a verify operation on the message send to the input-FD.
|
|
|
|
|
The result is written out using status lines. If an output FD was
|
|
|
|
|
given, the signed text will be written to that.
|
|
|
|
|
|
|
|
|
|
If the signature is a detached one, the server will inquire about
|
|
|
|
|
the signed material and the client must provide it.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
cmd_verify (ASSUAN_CONTEXT ctx, char *line)
|
|
|
|
|
{
|
|
|
|
|
int rc;
|
|
|
|
|
CTRL ctrl = assuan_get_pointer (ctx);
|
|
|
|
|
int fd = assuan_get_input_fd (ctx);
|
|
|
|
|
int out_fd = assuan_get_output_fd (ctx);
|
|
|
|
|
FILE *out_fp = NULL;
|
|
|
|
|
|
|
|
|
|
if (fd == -1)
|
|
|
|
|
return set_error (No_Input, NULL);
|
|
|
|
|
|
|
|
|
|
if (out_fd != -1)
|
|
|
|
|
{
|
|
|
|
|
out_fp = fdopen ( dup(out_fd), "w");
|
|
|
|
|
if (!out_fp)
|
|
|
|
|
return set_error (General_Error, "fdopen() failed");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = gpgsm_verify (assuan_get_pointer (ctx), fd,
|
|
|
|
|
ctrl->server_local->message_fd, out_fp);
|
|
|
|
|
if (out_fp)
|
|
|
|
|
fclose (out_fp);
|
|
|
|
|
|
|
|
|
|
/* close and reset the fd */
|
|
|
|
|
close_message_fd (ctrl);
|
|
|
|
|
assuan_close_input_fd (ctx);
|
|
|
|
|
assuan_close_output_fd (ctx);
|
|
|
|
|
|
|
|
|
|
return map_to_assuan_status (rc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* SIGN [--detached]
|
|
|
|
|
|
|
|
|
|
Sign the data set with the INPUT command and write it to the sink
|
|
|
|
|
set by OUTPUT. With "--detached" specified, a detached signature is
|
|
|
|
|
created (surprise). */
|
|
|
|
|
static int
|
|
|
|
|
cmd_sign (ASSUAN_CONTEXT ctx, char *line)
|
|
|
|
|
{
|
|
|
|
|
CTRL ctrl = assuan_get_pointer (ctx);
|
|
|
|
|
int inp_fd, out_fd;
|
|
|
|
|
FILE *out_fp;
|
|
|
|
|
int detached;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
inp_fd = assuan_get_input_fd (ctx);
|
|
|
|
|
if (inp_fd == -1)
|
|
|
|
|
return set_error (No_Input, NULL);
|
|
|
|
|
out_fd = assuan_get_output_fd (ctx);
|
|
|
|
|
if (out_fd == -1)
|
|
|
|
|
return set_error (No_Output, NULL);
|
|
|
|
|
|
|
|
|
|
detached = has_option (line, "--detached");
|
|
|
|
|
|
|
|
|
|
out_fp = fdopen ( dup(out_fd), "w");
|
|
|
|
|
if (!out_fp)
|
|
|
|
|
return set_error (General_Error, "fdopen() failed");
|
|
|
|
|
|
|
|
|
|
rc = gpgsm_sign (assuan_get_pointer (ctx), ctrl->server_local->signerlist,
|
|
|
|
|
inp_fd, detached, out_fp);
|
|
|
|
|
fclose (out_fp);
|
|
|
|
|
|
|
|
|
|
/* close and reset the fd */
|
|
|
|
|
close_message_fd (ctrl);
|
|
|
|
|
assuan_close_input_fd (ctx);
|
|
|
|
|
assuan_close_output_fd (ctx);
|
|
|
|
|
|
|
|
|
|
return map_to_assuan_status (rc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* IMPORT
|
|
|
|
|
|
|
|
|
|
Import the certificates read form the input-fd, return status
|
|
|
|
|
message for each imported one. The import checks the validity of
|
|
|
|
|
the certificate but not of the entire chain. It is possible to
|
|
|
|
|
import expired certificates. */
|
|
|
|
|
static int
|
|
|
|
|
cmd_import (ASSUAN_CONTEXT ctx, char *line)
|
|
|
|
|
{
|
|
|
|
|
CTRL ctrl = assuan_get_pointer (ctx);
|
|
|
|
|
int rc;
|
|
|
|
|
int fd = assuan_get_input_fd (ctx);
|
|
|
|
|
|
|
|
|
|
if (fd == -1)
|
|
|
|
|
return set_error (No_Input, NULL);
|
|
|
|
|
|
|
|
|
|
rc = gpgsm_import (assuan_get_pointer (ctx), fd);
|
|
|
|
|
|
|
|
|
|
/* close and reset the fd */
|
|
|
|
|
close_message_fd (ctrl);
|
|
|
|
|
assuan_close_input_fd (ctx);
|
|
|
|
|
assuan_close_output_fd (ctx);
|
|
|
|
|
|
|
|
|
|
return map_to_assuan_status (rc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
cmd_export (ASSUAN_CONTEXT ctx, char *line)
|
|
|
|
|
{
|
|
|
|
|
CTRL ctrl = assuan_get_pointer (ctx);
|
|
|
|
|
int fd = assuan_get_output_fd (ctx);
|
|
|
|
|
FILE *out_fp;
|
|
|
|
|
char *p;
|
|
|
|
|
STRLIST list, sl;
|
|
|
|
|
|
|
|
|
|
if (fd == -1)
|
|
|
|
|
return set_error (No_Output, NULL);
|
|
|
|
|
|
|
|
|
|
/* break the line down into an STRLIST */
|
|
|
|
|
list = NULL;
|
|
|
|
|
for (p=line; *p; line = p)
|
|
|
|
|
{
|
|
|
|
|
while (*p && *p != ' ')
|
|
|
|
|
p++;
|
|
|
|
|
if (*p)
|
|
|
|
|
*p++ = 0;
|
|
|
|
|
if (*line)
|
|
|
|
|
{
|
|
|
|
|
sl = xtrymalloc (sizeof *sl + strlen (line));
|
|
|
|
|
if (!sl)
|
|
|
|
|
{
|
|
|
|
|
free_strlist (list);
|
|
|
|
|
return ASSUAN_Out_Of_Core;
|
|
|
|
|
}
|
|
|
|
|
sl->flags = 0;
|
|
|
|
|
strcpy_escaped_plus (sl->d, line);
|
|
|
|
|
sl->next = list;
|
|
|
|
|
list = sl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out_fp = fdopen ( dup(fd), "w");
|
|
|
|
|
if (!out_fp)
|
|
|
|
|
{
|
|
|
|
|
free_strlist (list);
|
|
|
|
|
return set_error (General_Error, "fdopen() failed");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gpgsm_export (ctrl, list, out_fp);
|
|
|
|
|
fclose (out_fp);
|
|
|
|
|
free_strlist (list);
|
|
|
|
|
/* close and reset the fd */
|
|
|
|
|
close_message_fd (ctrl);
|
|
|
|
|
assuan_close_input_fd (ctx);
|
|
|
|
|
assuan_close_output_fd (ctx);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
cmd_delkeys (ASSUAN_CONTEXT ctx, char *line)
|
|
|
|
|
{
|
|
|
|
|
CTRL ctrl = assuan_get_pointer (ctx);
|
|
|
|
|
char *p;
|
|
|
|
|
STRLIST list, sl;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
/* break the line down into an STRLIST */
|
|
|
|
|
list = NULL;
|
|
|
|
|
for (p=line; *p; line = p)
|
|
|
|
|
{
|
|
|
|
|
while (*p && *p != ' ')
|
|
|
|
|
p++;
|
|
|
|
|
if (*p)
|
|
|
|
|
*p++ = 0;
|
|
|
|
|
if (*line)
|
|
|
|
|
{
|
|
|
|
|
sl = xtrymalloc (sizeof *sl + strlen (line));
|
|
|
|
|
if (!sl)
|
|
|
|
|
{
|
|
|
|
|
free_strlist (list);
|
|
|
|
|
return ASSUAN_Out_Of_Core;
|
|
|
|
|
}
|
|
|
|
|
sl->flags = 0;
|
|
|
|
|
strcpy_escaped_plus (sl->d, line);
|
|
|
|
|
sl->next = list;
|
|
|
|
|
list = sl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = gpgsm_delete (ctrl, list);
|
|
|
|
|
free_strlist (list);
|
|
|
|
|
|
|
|
|
|
/* close and reset the fd */
|
|
|
|
|
close_message_fd (ctrl);
|
|
|
|
|
assuan_close_input_fd (ctx);
|
|
|
|
|
assuan_close_output_fd (ctx);
|
|
|
|
|
|
|
|
|
|
return map_to_assuan_status (rc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* MESSAGE FD=<n>
|
|
|
|
|
|
|
|
|
|
Set the file descriptor to read a message which is used with
|
|
|
|
|
detached signatures */
|
|
|
|
|
static int
|
|
|
|
|
cmd_message (ASSUAN_CONTEXT ctx, char *line)
|
|
|
|
|
{
|
|
|
|
|
char *endp;
|
|
|
|
|
int fd;
|
|
|
|
|
CTRL ctrl = assuan_get_pointer (ctx);
|
|
|
|
|
|
|
|
|
|
if (strncmp (line, "FD=", 3))
|
|
|
|
|
return set_error (Syntax_Error, "FD=<n> expected");
|
|
|
|
|
line += 3;
|
|
|
|
|
if (!digitp (line))
|
|
|
|
|
return set_error (Syntax_Error, "number required");
|
|
|
|
|
fd = strtoul (line, &endp, 10);
|
|
|
|
|
if (*endp)
|
|
|
|
|
return set_error (Syntax_Error, "garbage found");
|
|
|
|
|
if (fd == -1)
|
|
|
|
|
return set_error (No_Input, NULL);
|
|
|
|
|
|
|
|
|
|
ctrl->server_local->message_fd = fd;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
do_listkeys (ASSUAN_CONTEXT ctx, char *line, int mode)
|
|
|
|
|
{
|
|
|
|
|
CTRL ctrl = assuan_get_pointer (ctx);
|
|
|
|
|
FILE *fp = assuan_get_data_fp (ctx);
|
|
|
|
|
char *p;
|
|
|
|
|
STRLIST list, sl;
|
|
|
|
|
unsigned int listmode;
|
2004-02-21 13:05:52 +00:00
|
|
|
|
gpg_error_t err;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
|
|
|
|
|
if (!fp)
|
|
|
|
|
return set_error (General_Error, "no data stream");
|
|
|
|
|
|
|
|
|
|
/* break the line down into an STRLIST */
|
|
|
|
|
list = NULL;
|
|
|
|
|
for (p=line; *p; line = p)
|
|
|
|
|
{
|
|
|
|
|
while (*p && *p != ' ')
|
|
|
|
|
p++;
|
|
|
|
|
if (*p)
|
|
|
|
|
*p++ = 0;
|
|
|
|
|
if (*line)
|
|
|
|
|
{
|
|
|
|
|
sl = xtrymalloc (sizeof *sl + strlen (line));
|
|
|
|
|
if (!sl)
|
|
|
|
|
{
|
|
|
|
|
free_strlist (list);
|
|
|
|
|
return ASSUAN_Out_Of_Core;
|
|
|
|
|
}
|
|
|
|
|
sl->flags = 0;
|
|
|
|
|
strcpy_escaped_plus (sl->d, line);
|
|
|
|
|
sl->next = list;
|
|
|
|
|
list = sl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctrl->with_colons = 1;
|
|
|
|
|
listmode = mode;
|
|
|
|
|
if (ctrl->server_local->list_internal)
|
|
|
|
|
listmode |= (1<<6);
|
|
|
|
|
if (ctrl->server_local->list_external)
|
|
|
|
|
listmode |= (1<<7);
|
2004-02-21 13:05:52 +00:00
|
|
|
|
err = gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, listmode);
|
2003-08-05 17:11:04 +00:00
|
|
|
|
free_strlist (list);
|
2004-02-21 13:05:52 +00:00
|
|
|
|
return map_to_assuan_status (err);
|
2003-08-05 17:11:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
cmd_listkeys (ASSUAN_CONTEXT ctx, char *line)
|
|
|
|
|
{
|
|
|
|
|
return do_listkeys (ctx, line, 3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
cmd_listsecretkeys (ASSUAN_CONTEXT ctx, char *line)
|
|
|
|
|
{
|
|
|
|
|
return do_listkeys (ctx, line, 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* GENKEY
|
|
|
|
|
|
|
|
|
|
Read the parameters in native format from the input fd and write a
|
|
|
|
|
certificate request to the output.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
cmd_genkey (ASSUAN_CONTEXT ctx, char *line)
|
|
|
|
|
{
|
|
|
|
|
CTRL ctrl = assuan_get_pointer (ctx);
|
|
|
|
|
int inp_fd, out_fd;
|
|
|
|
|
FILE *out_fp;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
inp_fd = assuan_get_input_fd (ctx);
|
|
|
|
|
if (inp_fd == -1)
|
|
|
|
|
return set_error (No_Input, NULL);
|
|
|
|
|
out_fd = assuan_get_output_fd (ctx);
|
|
|
|
|
if (out_fd == -1)
|
|
|
|
|
return set_error (No_Output, NULL);
|
|
|
|
|
|
|
|
|
|
out_fp = fdopen ( dup(out_fd), "w");
|
|
|
|
|
if (!out_fp)
|
|
|
|
|
return set_error (General_Error, "fdopen() failed");
|
|
|
|
|
rc = gpgsm_genkey (ctrl, inp_fd, out_fp);
|
|
|
|
|
fclose (out_fp);
|
|
|
|
|
|
|
|
|
|
/* close and reset the fds */
|
|
|
|
|
assuan_close_input_fd (ctx);
|
|
|
|
|
assuan_close_output_fd (ctx);
|
|
|
|
|
|
|
|
|
|
return map_to_assuan_status (rc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Tell the assuan library about our commands */
|
|
|
|
|
static int
|
|
|
|
|
register_commands (ASSUAN_CONTEXT ctx)
|
|
|
|
|
{
|
|
|
|
|
static struct {
|
|
|
|
|
const char *name;
|
|
|
|
|
int (*handler)(ASSUAN_CONTEXT, char *line);
|
|
|
|
|
} table[] = {
|
|
|
|
|
{ "RECIPIENT", cmd_recipient },
|
|
|
|
|
{ "SIGNER", cmd_signer },
|
|
|
|
|
{ "ENCRYPT", cmd_encrypt },
|
|
|
|
|
{ "DECRYPT", cmd_decrypt },
|
|
|
|
|
{ "VERIFY", cmd_verify },
|
|
|
|
|
{ "SIGN", cmd_sign },
|
|
|
|
|
{ "IMPORT", cmd_import },
|
|
|
|
|
{ "EXPORT", cmd_export },
|
|
|
|
|
{ "INPUT", NULL },
|
|
|
|
|
{ "OUTPUT", NULL },
|
|
|
|
|
{ "MESSAGE", cmd_message },
|
|
|
|
|
{ "LISTKEYS", cmd_listkeys },
|
|
|
|
|
{ "LISTSECRETKEYS",cmd_listsecretkeys },
|
|
|
|
|
{ "GENKEY", cmd_genkey },
|
|
|
|
|
{ "DELKEYS", cmd_delkeys },
|
|
|
|
|
{ NULL }
|
|
|
|
|
};
|
|
|
|
|
int i, rc;
|
|
|
|
|
|
|
|
|
|
for (i=0; table[i].name; i++)
|
|
|
|
|
{
|
|
|
|
|
rc = assuan_register_command (ctx, table[i].name, table[i].handler);
|
|
|
|
|
if (rc)
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2003-12-17 17:12:14 +00:00
|
|
|
|
/* Startup the server. DEFAULT_RECPLIST is the list of recipients as
|
|
|
|
|
set from the command line or config file. We only require those
|
|
|
|
|
marked as encrypt-to. */
|
2003-08-05 17:11:04 +00:00
|
|
|
|
void
|
2003-12-17 17:12:14 +00:00
|
|
|
|
gpgsm_server (certlist_t default_recplist)
|
2003-08-05 17:11:04 +00:00
|
|
|
|
{
|
|
|
|
|
int rc;
|
|
|
|
|
int filedes[2];
|
|
|
|
|
ASSUAN_CONTEXT ctx;
|
|
|
|
|
struct server_control_s ctrl;
|
2004-05-11 09:15:56 +00:00
|
|
|
|
static const char hello[] = ("GNU Privacy Guard's S/M server "
|
|
|
|
|
VERSION " ready");
|
2003-08-05 17:11:04 +00:00
|
|
|
|
|
|
|
|
|
memset (&ctrl, 0, sizeof ctrl);
|
|
|
|
|
gpgsm_init_default_ctrl (&ctrl);
|
|
|
|
|
|
|
|
|
|
/* For now we use a simple pipe based server so that we can work
|
|
|
|
|
from scripts. We will later add options to run as a daemon and
|
|
|
|
|
wait for requests on a Unix domain socket */
|
|
|
|
|
filedes[0] = 0;
|
|
|
|
|
filedes[1] = 1;
|
|
|
|
|
rc = assuan_init_pipe_server (&ctx, filedes);
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
log_error ("failed to initialize the server: %s\n",
|
|
|
|
|
assuan_strerror(rc));
|
|
|
|
|
gpgsm_exit (2);
|
|
|
|
|
}
|
|
|
|
|
rc = register_commands (ctx);
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
log_error ("failed to the register commands with Assuan: %s\n",
|
|
|
|
|
assuan_strerror(rc));
|
|
|
|
|
gpgsm_exit (2);
|
|
|
|
|
}
|
2004-05-11 09:54:52 +00:00
|
|
|
|
if (opt.verbose || opt.debug)
|
2004-05-11 09:15:56 +00:00
|
|
|
|
{
|
|
|
|
|
char *tmp = NULL;
|
2004-05-11 09:24:09 +00:00
|
|
|
|
const char *s1 = getenv ("GPG_AGENT_INFO");
|
|
|
|
|
const char *s2 = getenv ("DIRMNGR_INFO");
|
|
|
|
|
|
2004-05-11 09:15:56 +00:00
|
|
|
|
if (asprintf (&tmp,
|
2004-05-11 09:24:09 +00:00
|
|
|
|
"Home: %s\n"
|
|
|
|
|
"Config: %s\n"
|
|
|
|
|
"AgentInfo: %s\n"
|
|
|
|
|
"DirmngrInfo: %s\n"
|
|
|
|
|
"%s",
|
|
|
|
|
opt.homedir,
|
|
|
|
|
opt.config_filename,
|
|
|
|
|
s1?s1:"[not set]",
|
|
|
|
|
s2?s2:"[not set]",
|
|
|
|
|
hello) > 0)
|
2004-05-11 09:15:56 +00:00
|
|
|
|
{
|
|
|
|
|
assuan_set_hello_line (ctx, tmp);
|
|
|
|
|
free (tmp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
assuan_set_hello_line (ctx, hello);
|
2003-08-05 17:11:04 +00:00
|
|
|
|
|
|
|
|
|
assuan_register_reset_notify (ctx, reset_notify);
|
|
|
|
|
assuan_register_input_notify (ctx, input_notify);
|
|
|
|
|
assuan_register_output_notify (ctx, output_notify);
|
|
|
|
|
assuan_register_option_handler (ctx, option_handler);
|
|
|
|
|
|
|
|
|
|
assuan_set_pointer (ctx, &ctrl);
|
|
|
|
|
ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
|
|
|
|
|
ctrl.server_local->assuan_ctx = ctx;
|
|
|
|
|
ctrl.server_local->message_fd = -1;
|
|
|
|
|
ctrl.server_local->list_internal = 1;
|
|
|
|
|
ctrl.server_local->list_external = 0;
|
2003-12-17 17:12:14 +00:00
|
|
|
|
ctrl.server_local->default_recplist = default_recplist;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
|
|
|
|
|
if (DBG_ASSUAN)
|
|
|
|
|
assuan_set_log_stream (ctx, log_get_stream ());
|
|
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
|
{
|
|
|
|
|
rc = assuan_accept (ctx);
|
|
|
|
|
if (rc == -1)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else if (rc)
|
|
|
|
|
{
|
|
|
|
|
log_info ("Assuan accept problem: %s\n", assuan_strerror (rc));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = assuan_process (ctx);
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
log_info ("Assuan processing failed: %s\n", assuan_strerror (rc));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gpgsm_release_certlist (ctrl.server_local->recplist);
|
|
|
|
|
ctrl.server_local->recplist = NULL;
|
|
|
|
|
gpgsm_release_certlist (ctrl.server_local->signerlist);
|
|
|
|
|
ctrl.server_local->signerlist = NULL;
|
|
|
|
|
|
|
|
|
|
assuan_deinit_server (ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
|
get_status_string ( int no )
|
|
|
|
|
{
|
|
|
|
|
const char *s;
|
|
|
|
|
|
|
|
|
|
switch (no)
|
|
|
|
|
{
|
|
|
|
|
case STATUS_ENTER : s = "ENTER"; break;
|
|
|
|
|
case STATUS_LEAVE : s = "LEAVE"; break;
|
|
|
|
|
case STATUS_ABORT : s = "ABORT"; break;
|
2004-04-06 07:37:52 +00:00
|
|
|
|
case STATUS_NEWSIG : s = "NEWSIG"; break;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
case STATUS_GOODSIG: s = "GOODSIG"; break;
|
|
|
|
|
case STATUS_SIGEXPIRED: s = "SIGEXPIRED"; break;
|
|
|
|
|
case STATUS_KEYREVOKED: s = "KEYREVOKED"; break;
|
|
|
|
|
case STATUS_BADSIG : s = "BADSIG"; break;
|
|
|
|
|
case STATUS_ERRSIG : s = "ERRSIG"; break;
|
|
|
|
|
case STATUS_BADARMOR : s = "BADARMOR"; break;
|
|
|
|
|
case STATUS_RSA_OR_IDEA : s= "RSA_OR_IDEA"; break;
|
|
|
|
|
case STATUS_TRUST_UNDEFINED: s = "TRUST_UNDEFINED"; break;
|
|
|
|
|
case STATUS_TRUST_NEVER : s = "TRUST_NEVER"; break;
|
|
|
|
|
case STATUS_TRUST_MARGINAL : s = "TRUST_MARGINAL"; break;
|
|
|
|
|
case STATUS_TRUST_FULLY : s = "TRUST_FULLY"; break;
|
|
|
|
|
case STATUS_TRUST_ULTIMATE : s = "TRUST_ULTIMATE"; break;
|
|
|
|
|
case STATUS_GET_BOOL : s = "GET_BOOL"; break;
|
|
|
|
|
case STATUS_GET_LINE : s = "GET_LINE"; break;
|
|
|
|
|
case STATUS_GET_HIDDEN : s = "GET_HIDDEN"; break;
|
|
|
|
|
case STATUS_GOT_IT : s = "GOT_IT"; break;
|
|
|
|
|
case STATUS_SHM_INFO : s = "SHM_INFO"; break;
|
|
|
|
|
case STATUS_SHM_GET : s = "SHM_GET"; break;
|
|
|
|
|
case STATUS_SHM_GET_BOOL : s = "SHM_GET_BOOL"; break;
|
|
|
|
|
case STATUS_SHM_GET_HIDDEN : s = "SHM_GET_HIDDEN"; break;
|
|
|
|
|
case STATUS_NEED_PASSPHRASE: s = "NEED_PASSPHRASE"; break;
|
|
|
|
|
case STATUS_VALIDSIG : s = "VALIDSIG"; break;
|
|
|
|
|
case STATUS_SIG_ID : s = "SIG_ID"; break;
|
|
|
|
|
case STATUS_ENC_TO : s = "ENC_TO"; break;
|
|
|
|
|
case STATUS_NODATA : s = "NODATA"; break;
|
|
|
|
|
case STATUS_BAD_PASSPHRASE : s = "BAD_PASSPHRASE"; break;
|
|
|
|
|
case STATUS_NO_PUBKEY : s = "NO_PUBKEY"; break;
|
|
|
|
|
case STATUS_NO_SECKEY : s = "NO_SECKEY"; break;
|
|
|
|
|
case STATUS_NEED_PASSPHRASE_SYM: s = "NEED_PASSPHRASE_SYM"; break;
|
|
|
|
|
case STATUS_DECRYPTION_FAILED: s = "DECRYPTION_FAILED"; break;
|
|
|
|
|
case STATUS_DECRYPTION_OKAY: s = "DECRYPTION_OKAY"; break;
|
|
|
|
|
case STATUS_MISSING_PASSPHRASE: s = "MISSING_PASSPHRASE"; break;
|
|
|
|
|
case STATUS_GOOD_PASSPHRASE : s = "GOOD_PASSPHRASE"; break;
|
|
|
|
|
case STATUS_GOODMDC : s = "GOODMDC"; break;
|
|
|
|
|
case STATUS_BADMDC : s = "BADMDC"; break;
|
|
|
|
|
case STATUS_ERRMDC : s = "ERRMDC"; break;
|
|
|
|
|
case STATUS_IMPORTED : s = "IMPORTED"; break;
|
2004-02-17 15:05:04 +00:00
|
|
|
|
case STATUS_IMPORT_OK : s = "IMPORT_OK"; break;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
case STATUS_IMPORT_RES : s = "IMPORT_RES"; break;
|
|
|
|
|
case STATUS_FILE_START : s = "FILE_START"; break;
|
|
|
|
|
case STATUS_FILE_DONE : s = "FILE_DONE"; break;
|
|
|
|
|
case STATUS_FILE_ERROR : s = "FILE_ERROR"; break;
|
|
|
|
|
case STATUS_BEGIN_DECRYPTION:s = "BEGIN_DECRYPTION"; break;
|
|
|
|
|
case STATUS_END_DECRYPTION : s = "END_DECRYPTION"; break;
|
|
|
|
|
case STATUS_BEGIN_ENCRYPTION:s = "BEGIN_ENCRYPTION"; break;
|
|
|
|
|
case STATUS_END_ENCRYPTION : s = "END_ENCRYPTION"; break;
|
|
|
|
|
case STATUS_DELETE_PROBLEM : s = "DELETE_PROBLEM"; break;
|
|
|
|
|
case STATUS_PROGRESS : s = "PROGRESS"; break;
|
|
|
|
|
case STATUS_SIG_CREATED : s = "SIG_CREATED"; break;
|
|
|
|
|
case STATUS_SESSION_KEY : s = "SESSION_KEY"; break;
|
|
|
|
|
case STATUS_NOTATION_NAME : s = "NOTATION_NAME" ; break;
|
|
|
|
|
case STATUS_NOTATION_DATA : s = "NOTATION_DATA" ; break;
|
|
|
|
|
case STATUS_POLICY_URL : s = "POLICY_URL" ; break;
|
|
|
|
|
case STATUS_BEGIN_STREAM : s = "BEGIN_STREAM"; break;
|
|
|
|
|
case STATUS_END_STREAM : s = "END_STREAM"; break;
|
|
|
|
|
case STATUS_KEY_CREATED : s = "KEY_CREATED"; break;
|
|
|
|
|
case STATUS_UNEXPECTED : s = "UNEXPECTED"; break;
|
|
|
|
|
case STATUS_INV_RECP : s = "INV_RECP"; break;
|
|
|
|
|
case STATUS_NO_RECP : s = "NO_RECP"; break;
|
|
|
|
|
case STATUS_ALREADY_SIGNED : s = "ALREADY_SIGNED"; break;
|
|
|
|
|
case STATUS_EXPSIG : s = "EXPSIG"; break;
|
|
|
|
|
case STATUS_EXPKEYSIG : s = "EXPKEYSIG"; break;
|
|
|
|
|
case STATUS_TRUNCATED : s = "TRUNCATED"; break;
|
|
|
|
|
case STATUS_ERROR : s = "ERROR"; break;
|
|
|
|
|
case STATUS_IMPORT_PROBLEM : s = "IMPORT_PROBLEM"; break;
|
|
|
|
|
default: s = "?"; break;
|
|
|
|
|
}
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-12-17 14:36:16 +00:00
|
|
|
|
gpg_error_t
|
2003-08-05 17:11:04 +00:00
|
|
|
|
gpgsm_status2 (CTRL ctrl, int no, ...)
|
|
|
|
|
{
|
2004-12-17 14:36:16 +00:00
|
|
|
|
gpg_error_t err = 0;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
va_list arg_ptr;
|
|
|
|
|
const char *text;
|
|
|
|
|
|
|
|
|
|
va_start (arg_ptr, no);
|
|
|
|
|
|
2004-12-17 14:36:16 +00:00
|
|
|
|
if (ctrl->no_server && ctrl->status_fd == -1)
|
|
|
|
|
; /* No status wanted. */
|
|
|
|
|
else if (ctrl->no_server)
|
2003-08-05 17:11:04 +00:00
|
|
|
|
{
|
|
|
|
|
if (!statusfp)
|
|
|
|
|
{
|
|
|
|
|
if (ctrl->status_fd == 1)
|
|
|
|
|
statusfp = stdout;
|
|
|
|
|
else if (ctrl->status_fd == 2)
|
|
|
|
|
statusfp = stderr;
|
|
|
|
|
else
|
|
|
|
|
statusfp = fdopen (ctrl->status_fd, "w");
|
|
|
|
|
|
|
|
|
|
if (!statusfp)
|
|
|
|
|
{
|
|
|
|
|
log_fatal ("can't open fd %d for status output: %s\n",
|
|
|
|
|
ctrl->status_fd, strerror(errno));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fputs ("[GNUPG:] ", statusfp);
|
|
|
|
|
fputs (get_status_string (no), statusfp);
|
|
|
|
|
|
|
|
|
|
while ( (text = va_arg (arg_ptr, const char*) ))
|
|
|
|
|
{
|
|
|
|
|
putc ( ' ', statusfp );
|
|
|
|
|
for (; *text; text++)
|
|
|
|
|
{
|
|
|
|
|
if (*text == '\n')
|
|
|
|
|
fputs ( "\\n", statusfp );
|
|
|
|
|
else if (*text == '\r')
|
|
|
|
|
fputs ( "\\r", statusfp );
|
|
|
|
|
else
|
|
|
|
|
putc ( *(const byte *)text, statusfp );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
putc ('\n', statusfp);
|
|
|
|
|
fflush (statusfp);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ASSUAN_CONTEXT ctx = ctrl->server_local->assuan_ctx;
|
|
|
|
|
char buf[950], *p;
|
|
|
|
|
size_t n;
|
|
|
|
|
|
|
|
|
|
p = buf;
|
|
|
|
|
n = 0;
|
|
|
|
|
while ( (text = va_arg (arg_ptr, const char *)) )
|
|
|
|
|
{
|
|
|
|
|
if (n)
|
|
|
|
|
{
|
|
|
|
|
*p++ = ' ';
|
|
|
|
|
n++;
|
|
|
|
|
}
|
|
|
|
|
for ( ; *text && n < DIM (buf)-2; n++)
|
|
|
|
|
*p++ = *text++;
|
|
|
|
|
}
|
|
|
|
|
*p = 0;
|
2004-12-17 14:36:16 +00:00
|
|
|
|
err = map_assuan_err (assuan_write_status (ctx,
|
|
|
|
|
get_status_string (no), buf));
|
2003-08-05 17:11:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
va_end (arg_ptr);
|
2004-12-17 14:36:16 +00:00
|
|
|
|
return err;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-12-17 14:36:16 +00:00
|
|
|
|
gpg_error_t
|
2003-08-05 17:11:04 +00:00
|
|
|
|
gpgsm_status (CTRL ctrl, int no, const char *text)
|
|
|
|
|
{
|
2004-12-17 14:36:16 +00:00
|
|
|
|
return gpgsm_status2 (ctrl, no, text, NULL);
|
2003-08-05 17:11:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-12-17 14:36:16 +00:00
|
|
|
|
gpg_error_t
|
2003-08-05 17:11:04 +00:00
|
|
|
|
gpgsm_status_with_err_code (CTRL ctrl, int no, const char *text,
|
|
|
|
|
gpg_err_code_t ec)
|
|
|
|
|
{
|
|
|
|
|
char buf[30];
|
|
|
|
|
|
|
|
|
|
sprintf (buf, "%u", (unsigned int)ec);
|
|
|
|
|
if (text)
|
2004-12-17 14:36:16 +00:00
|
|
|
|
return gpgsm_status2 (ctrl, no, text, buf, NULL);
|
2003-08-05 17:11:04 +00:00
|
|
|
|
else
|
2004-12-17 14:36:16 +00:00
|
|
|
|
return gpgsm_status2 (ctrl, no, buf, NULL);
|
2003-08-05 17:11:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
/*
|
|
|
|
|
* Write a status line with a buffer using %XX escapes. If WRAP is >
|
|
|
|
|
* 0 wrap the line after this length. If STRING is not NULL it will
|
|
|
|
|
* be prepended to the buffer, no escaping is done for string.
|
|
|
|
|
* A wrap of -1 forces spaces not to be encoded as %20.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
write_status_text_and_buffer ( int no, const char *string,
|
|
|
|
|
const char *buffer, size_t len, int wrap )
|
|
|
|
|
{
|
|
|
|
|
const char *s, *text;
|
|
|
|
|
int esc, first;
|
|
|
|
|
int lower_limit = ' ';
|
|
|
|
|
size_t n, count, dowrap;
|
|
|
|
|
|
|
|
|
|
if( !statusfp )
|
|
|
|
|
return; /* not enabled */
|
|
|
|
|
|
|
|
|
|
if (wrap == -1) {
|
|
|
|
|
lower_limit--;
|
|
|
|
|
wrap = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
text = get_status_string (no);
|
|
|
|
|
count = dowrap = first = 1;
|
|
|
|
|
do {
|
|
|
|
|
if (dowrap) {
|
|
|
|
|
fprintf (statusfp, "[GNUPG:] %s ", text );
|
|
|
|
|
count = dowrap = 0;
|
|
|
|
|
if (first && string) {
|
|
|
|
|
fputs (string, statusfp);
|
|
|
|
|
count += strlen (string);
|
|
|
|
|
}
|
|
|
|
|
first = 0;
|
|
|
|
|
}
|
|
|
|
|
for (esc=0, s=buffer, n=len; n && !esc; s++, n-- ) {
|
|
|
|
|
if ( *s == '%' || *(const byte*)s <= lower_limit
|
|
|
|
|
|| *(const byte*)s == 127 )
|
|
|
|
|
esc = 1;
|
|
|
|
|
if ( wrap && ++count > wrap ) {
|
|
|
|
|
dowrap=1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (esc) {
|
|
|
|
|
s--; n++;
|
|
|
|
|
}
|
|
|
|
|
if (s != buffer)
|
|
|
|
|
fwrite (buffer, s-buffer, 1, statusfp );
|
|
|
|
|
if ( esc ) {
|
|
|
|
|
fprintf (statusfp, "%%%02X", *(const byte*)s );
|
|
|
|
|
s++; n--;
|
|
|
|
|
}
|
|
|
|
|
buffer = s;
|
|
|
|
|
len = n;
|
|
|
|
|
if ( dowrap && len )
|
|
|
|
|
putc ( '\n', statusfp );
|
|
|
|
|
} while ( len );
|
|
|
|
|
|
|
|
|
|
putc ('\n',statusfp);
|
|
|
|
|
fflush (statusfp);
|
|
|
|
|
}
|
|
|
|
|
#endif
|