diff options
Diffstat (limited to '')
-rw-r--r-- | g10/photoid.c | 401 |
1 files changed, 401 insertions, 0 deletions
diff --git a/g10/photoid.c b/g10/photoid.c new file mode 100644 index 0000000..dbef7d7 --- /dev/null +++ b/g10/photoid.c @@ -0,0 +1,401 @@ +/* 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*/ +} |