mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
0441ed6e1c
* g10/photoid.c (get_default_photo_command): Change parameter for xdg-open. -- xdg-open spawns the user's preferred image viewer and then exits. Therefore we must not remove the temp file when it exits, otherwise by the time the actual image viewer is started the file doesn't exist any more. Signed-off-by: Nicolas Fella <nicolas.fella@gmx.de>
402 lines
9.2 KiB
C
402 lines
9.2 KiB
C
/* photoid.c - photo ID handling code
|
|
* Copyright (C) 2001, 2002, 2005, 2006, 2008, 2011 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 <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#ifdef _WIN32
|
|
# ifdef HAVE_WINSOCK2_H
|
|
# include <winsock2.h>
|
|
# endif
|
|
# include <windows.h>
|
|
# ifndef VER_PLATFORM_WIN32_WINDOWS
|
|
# define VER_PLATFORM_WIN32_WINDOWS 1
|
|
# endif
|
|
#endif
|
|
|
|
#include "gpg.h"
|
|
#include "../common/util.h"
|
|
#include "packet.h"
|
|
#include "../common/status.h"
|
|
#include "exec.h"
|
|
#include "keydb.h"
|
|
#include "../common/i18n.h"
|
|
#include "../common/iobuf.h"
|
|
#include "options.h"
|
|
#include "main.h"
|
|
#include "photoid.h"
|
|
#include "../common/ttyio.h"
|
|
#include "trustdb.h"
|
|
|
|
/* Generate a new photo id packet, or return NULL if canceled.
|
|
FIXME: Should we add a duplicates check similar to generate_user_id? */
|
|
PKT_user_id *
|
|
generate_photo_id (ctrl_t ctrl, PKT_public_key *pk,const char *photo_name)
|
|
{
|
|
PKT_user_id *uid;
|
|
int error=1,i;
|
|
unsigned int len;
|
|
char *filename;
|
|
byte *photo=NULL;
|
|
byte header[16];
|
|
IOBUF file;
|
|
int overflow;
|
|
|
|
header[0]=0x10; /* little side of photo header length */
|
|
header[1]=0; /* big side of photo header length */
|
|
header[2]=1; /* 1 == version of photo header */
|
|
header[3]=1; /* 1 == JPEG */
|
|
|
|
for(i=4;i<16;i++) /* The reserved bytes */
|
|
header[i]=0;
|
|
|
|
#define EXTRA_UID_NAME_SPACE 71
|
|
uid=xmalloc_clear(sizeof(*uid)+71);
|
|
|
|
if(photo_name && *photo_name)
|
|
filename=make_filename(photo_name,(void *)NULL);
|
|
else
|
|
{
|
|
tty_printf(_("\nPick an image to use for your photo ID."
|
|
" The image must be a JPEG file.\n"
|
|
"Remember that the image is stored within your public key."
|
|
" If you use a\n"
|
|
"very large picture, your key will become very large"
|
|
" as well!\n"
|
|
"Keeping the image close to 240x288 is a good size"
|
|
" to use.\n"));
|
|
filename=NULL;
|
|
}
|
|
|
|
while(photo==NULL)
|
|
{
|
|
if(filename==NULL)
|
|
{
|
|
char *tempname;
|
|
|
|
tty_printf("\n");
|
|
|
|
tty_enable_completion(NULL);
|
|
|
|
tempname=cpr_get("photoid.jpeg.add",
|
|
_("Enter JPEG filename for photo ID: "));
|
|
|
|
tty_disable_completion();
|
|
|
|
filename=make_filename(tempname,(void *)NULL);
|
|
|
|
xfree(tempname);
|
|
|
|
if(strlen(filename)==0)
|
|
goto scram;
|
|
}
|
|
|
|
file=iobuf_open(filename);
|
|
if (file && is_secured_file (iobuf_get_fd (file)))
|
|
{
|
|
iobuf_close (file);
|
|
file = NULL;
|
|
gpg_err_set_errno (EPERM);
|
|
}
|
|
if(!file)
|
|
{
|
|
log_error(_("unable to open JPEG file '%s': %s\n"),
|
|
filename,strerror(errno));
|
|
xfree(filename);
|
|
filename=NULL;
|
|
continue;
|
|
}
|
|
|
|
|
|
len=iobuf_get_filelength(file, &overflow);
|
|
if(len>6144 || overflow)
|
|
{
|
|
tty_printf( _("This JPEG is really large (%d bytes) !\n"),len);
|
|
if(!cpr_get_answer_is_yes("photoid.jpeg.size",
|
|
_("Are you sure you want to use it? (y/N) ")))
|
|
{
|
|
iobuf_close(file);
|
|
xfree(filename);
|
|
filename=NULL;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
photo=xmalloc(len);
|
|
iobuf_read(file,photo,len);
|
|
iobuf_close(file);
|
|
|
|
/* Is it a JPEG? */
|
|
if(photo[0]!=0xFF || photo[1]!=0xD8)
|
|
{
|
|
log_error(_("'%s' is not a JPEG file\n"),filename);
|
|
xfree(photo);
|
|
photo=NULL;
|
|
xfree(filename);
|
|
filename=NULL;
|
|
continue;
|
|
}
|
|
|
|
/* Build the packet */
|
|
build_attribute_subpkt(uid,1,photo,len,header,16);
|
|
parse_attribute_subpkts(uid);
|
|
make_attribute_uidname(uid, EXTRA_UID_NAME_SPACE);
|
|
|
|
/* Showing the photo is not safe when noninteractive since the
|
|
"user" may not be able to dismiss a viewer window! */
|
|
if(opt.command_fd==-1)
|
|
{
|
|
show_photos (ctrl, uid->attribs, uid->numattribs, pk, uid);
|
|
switch(cpr_get_answer_yes_no_quit("photoid.jpeg.okay",
|
|
_("Is this photo correct (y/N/q)? ")))
|
|
{
|
|
case -1:
|
|
goto scram;
|
|
case 0:
|
|
free_attributes(uid);
|
|
xfree(photo);
|
|
photo=NULL;
|
|
xfree(filename);
|
|
filename=NULL;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
error=0;
|
|
uid->ref=1;
|
|
|
|
scram:
|
|
xfree(filename);
|
|
xfree(photo);
|
|
|
|
if(error)
|
|
{
|
|
free_attributes(uid);
|
|
xfree(uid);
|
|
return NULL;
|
|
}
|
|
|
|
return uid;
|
|
}
|
|
|
|
/* Returns 0 for error, 1 for valid */
|
|
int parse_image_header(const struct user_attribute *attr,byte *type,u32 *len)
|
|
{
|
|
u16 headerlen;
|
|
|
|
if(attr->len<3)
|
|
return 0;
|
|
|
|
/* For historical reasons (i.e. "oops!"), the header length is
|
|
little endian. */
|
|
headerlen=(attr->data[1]<<8) | attr->data[0];
|
|
|
|
if(headerlen>attr->len)
|
|
return 0;
|
|
|
|
if(type && attr->len>=4)
|
|
{
|
|
if(attr->data[2]==1) /* header version 1 */
|
|
*type=attr->data[3];
|
|
else
|
|
*type=0;
|
|
}
|
|
|
|
*len=attr->len-headerlen;
|
|
|
|
if(*len==0)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* style==0 for extension, 1 for name, 2 for MIME type. Remember that
|
|
the "name" style string could be used in a user ID name field, so
|
|
make sure it is not too big (see parse-packet.c:parse_attribute).
|
|
Extensions should be 3 characters long for the best cross-platform
|
|
compatibility. */
|
|
char *image_type_to_string(byte type,int style)
|
|
{
|
|
char *string;
|
|
|
|
switch(type)
|
|
{
|
|
case 1: /* jpeg */
|
|
if(style==0)
|
|
string="jpg";
|
|
else if(style==1)
|
|
string="jpeg";
|
|
else
|
|
string="image/jpeg";
|
|
break;
|
|
|
|
default:
|
|
if(style==0)
|
|
string="bin";
|
|
else if(style==1)
|
|
string="unknown";
|
|
else
|
|
string="image/x-unknown";
|
|
break;
|
|
}
|
|
|
|
return string;
|
|
}
|
|
|
|
#if !defined(FIXED_PHOTO_VIEWER) && !defined(DISABLE_PHOTO_VIEWER)
|
|
static const char *
|
|
get_default_photo_command(void)
|
|
{
|
|
#if defined(_WIN32)
|
|
OSVERSIONINFO osvi;
|
|
|
|
memset(&osvi,0,sizeof(osvi));
|
|
osvi.dwOSVersionInfoSize=sizeof(osvi);
|
|
GetVersionEx(&osvi);
|
|
|
|
if(osvi.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS)
|
|
return "start /w %i";
|
|
else
|
|
return "!ShellExecute 400 %i";
|
|
#elif defined(__APPLE__)
|
|
/* OS X. This really needs more than just __APPLE__. */
|
|
return "open %I";
|
|
#elif defined(__riscos__)
|
|
return "Filer_Run %I";
|
|
#else
|
|
if (!path_access ("xloadimage", X_OK))
|
|
return "xloadimage -fork -quiet -title 'KeyID 0x%k' stdin";
|
|
else if (!path_access ("display",X_OK))
|
|
return "display -title 'KeyID 0x%k' %i";
|
|
else if (getuid () && !path_access ("xdg-open", X_OK))
|
|
{
|
|
/* xdg-open spawns the actual program and exits so we need to
|
|
* keep the temp file */
|
|
return "xdg-open %I";
|
|
}
|
|
else
|
|
return "/bin/true";
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
|
|
void
|
|
show_photos (ctrl_t ctrl, const struct user_attribute *attrs, int count,
|
|
PKT_public_key *pk, PKT_user_id *uid)
|
|
{
|
|
#ifdef DISABLE_PHOTO_VIEWER
|
|
(void)attrs;
|
|
(void)count;
|
|
(void)pk;
|
|
(void)uid;
|
|
#else /*!DISABLE_PHOTO_VIEWER*/
|
|
int i;
|
|
struct expando_args args;
|
|
u32 len;
|
|
u32 kid[2]={0,0};
|
|
|
|
memset (&args, 0, sizeof(args));
|
|
args.pk = pk;
|
|
args.validity_info = get_validity_info (ctrl, NULL, pk, uid);
|
|
args.validity_string = get_validity_string (ctrl, pk, uid);
|
|
namehash_from_uid (uid);
|
|
args.namehash = uid->namehash;
|
|
|
|
if (pk)
|
|
keyid_from_pk (pk, kid);
|
|
|
|
es_fflush (es_stdout);
|
|
|
|
for(i=0;i<count;i++)
|
|
if(attrs[i].type==ATTRIB_IMAGE &&
|
|
parse_image_header(&attrs[i],&args.imagetype,&len))
|
|
{
|
|
char *command,*name;
|
|
struct exec_info *spawn;
|
|
int offset=attrs[i].len-len;
|
|
|
|
#ifdef FIXED_PHOTO_VIEWER
|
|
opt.photo_viewer=FIXED_PHOTO_VIEWER;
|
|
#else
|
|
if(!opt.photo_viewer)
|
|
opt.photo_viewer=get_default_photo_command();
|
|
#endif
|
|
|
|
/* make command grow */
|
|
command=pct_expando(opt.photo_viewer,&args);
|
|
if(!command)
|
|
goto fail;
|
|
if (!*command)
|
|
{
|
|
xfree (command);
|
|
goto fail;
|
|
}
|
|
|
|
name=xmalloc(16+strlen(EXTSEP_S)+
|
|
strlen(image_type_to_string(args.imagetype,0))+1);
|
|
|
|
/* Make the filename. Notice we are not using the image
|
|
encoding type for more than cosmetics. Most external image
|
|
viewers can handle a multitude of types, and even if one
|
|
cannot understand a particular type, we have no way to know
|
|
which. The spec permits this, by the way. -dms */
|
|
|
|
#ifdef USE_ONLY_8DOT3
|
|
sprintf(name,"%08lX" EXTSEP_S "%s",(ulong)kid[1],
|
|
image_type_to_string(args.imagetype,0));
|
|
#else
|
|
sprintf(name,"%08lX%08lX" EXTSEP_S "%s",(ulong)kid[0],(ulong)kid[1],
|
|
image_type_to_string(args.imagetype,0));
|
|
#endif
|
|
|
|
if(exec_write(&spawn,NULL,command,name,1,1)!=0)
|
|
{
|
|
xfree(name);
|
|
goto fail;
|
|
}
|
|
|
|
#ifdef __riscos__
|
|
riscos_set_filetype_by_mimetype(spawn->tempfile_in,
|
|
image_type_to_string(args.imagetype,2));
|
|
#endif
|
|
|
|
xfree(name);
|
|
|
|
fwrite(&attrs[i].data[offset],attrs[i].len-offset,1,spawn->tochild);
|
|
|
|
if(exec_read(spawn)!=0)
|
|
{
|
|
exec_finish(spawn);
|
|
goto fail;
|
|
}
|
|
|
|
if(exec_finish(spawn)!=0)
|
|
goto fail;
|
|
}
|
|
|
|
return;
|
|
|
|
fail:
|
|
log_error(_("unable to display photo ID!\n"));
|
|
#endif /*!DISABLE_PHOTO_VIEWER*/
|
|
}
|