Line data Source code
1 : /* photoid.c - photo ID handling code
2 : * Copyright (C) 2001, 2002, 2005, 2006, 2008, 2011 Free Software Foundation, Inc.
3 : *
4 : * This file is part of GnuPG.
5 : *
6 : * GnuPG is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation; either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * GnuPG is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include <config.h>
21 : #include <errno.h>
22 : #include <stdio.h>
23 : #include <string.h>
24 : #ifdef _WIN32
25 : # ifdef HAVE_WINSOCK2_H
26 : # include <winsock2.h>
27 : # endif
28 : # include <windows.h>
29 : # ifndef VER_PLATFORM_WIN32_WINDOWS
30 : # define VER_PLATFORM_WIN32_WINDOWS 1
31 : # endif
32 : #endif
33 :
34 : #include "gpg.h"
35 : #include "util.h"
36 : #include "packet.h"
37 : #include "status.h"
38 : #include "exec.h"
39 : #include "keydb.h"
40 : #include "i18n.h"
41 : #include "iobuf.h"
42 : #include "options.h"
43 : #include "main.h"
44 : #include "photoid.h"
45 : #include "ttyio.h"
46 : #include "trustdb.h"
47 :
48 : /* Generate a new photo id packet, or return NULL if canceled.
49 : FIXME: Should we add a duplicates check similar to generate_user_id? */
50 : PKT_user_id *
51 0 : generate_photo_id(PKT_public_key *pk,const char *photo_name)
52 : {
53 : PKT_user_id *uid;
54 0 : int error=1,i;
55 : unsigned int len;
56 : char *filename;
57 0 : byte *photo=NULL;
58 : byte header[16];
59 : IOBUF file;
60 : int overflow;
61 :
62 0 : header[0]=0x10; /* little side of photo header length */
63 0 : header[1]=0; /* big side of photo header length */
64 0 : header[2]=1; /* 1 == version of photo header */
65 0 : header[3]=1; /* 1 == JPEG */
66 :
67 0 : for(i=4;i<16;i++) /* The reserved bytes */
68 0 : header[i]=0;
69 :
70 : #define EXTRA_UID_NAME_SPACE 71
71 0 : uid=xmalloc_clear(sizeof(*uid)+71);
72 :
73 0 : if(photo_name && *photo_name)
74 0 : filename=make_filename(photo_name,(void *)NULL);
75 : else
76 : {
77 0 : tty_printf(_("\nPick an image to use for your photo ID."
78 : " The image must be a JPEG file.\n"
79 : "Remember that the image is stored within your public key."
80 : " If you use a\n"
81 : "very large picture, your key will become very large"
82 : " as well!\n"
83 : "Keeping the image close to 240x288 is a good size"
84 : " to use.\n"));
85 0 : filename=NULL;
86 : }
87 :
88 0 : while(photo==NULL)
89 : {
90 0 : if(filename==NULL)
91 : {
92 : char *tempname;
93 :
94 0 : tty_printf("\n");
95 :
96 : tty_enable_completion(NULL);
97 :
98 0 : tempname=cpr_get("photoid.jpeg.add",
99 0 : _("Enter JPEG filename for photo ID: "));
100 :
101 : tty_disable_completion();
102 :
103 0 : filename=make_filename(tempname,(void *)NULL);
104 :
105 0 : xfree(tempname);
106 :
107 0 : if(strlen(filename)==0)
108 0 : goto scram;
109 : }
110 :
111 0 : file=iobuf_open(filename);
112 0 : if (file && is_secured_file (iobuf_get_fd (file)))
113 : {
114 0 : iobuf_close (file);
115 0 : file = NULL;
116 0 : gpg_err_set_errno (EPERM);
117 : }
118 0 : if(!file)
119 : {
120 0 : log_error(_("unable to open JPEG file '%s': %s\n"),
121 0 : filename,strerror(errno));
122 0 : xfree(filename);
123 0 : filename=NULL;
124 0 : continue;
125 : }
126 :
127 :
128 0 : len=iobuf_get_filelength(file, &overflow);
129 0 : if(len>6144 || overflow)
130 : {
131 0 : tty_printf( _("This JPEG is really large (%d bytes) !\n"),len);
132 0 : if(!cpr_get_answer_is_yes("photoid.jpeg.size",
133 0 : _("Are you sure you want to use it? (y/N) ")))
134 : {
135 0 : iobuf_close(file);
136 0 : xfree(filename);
137 0 : filename=NULL;
138 0 : continue;
139 : }
140 : }
141 :
142 0 : photo=xmalloc(len);
143 0 : iobuf_read(file,photo,len);
144 0 : iobuf_close(file);
145 :
146 : /* Is it a JPEG? */
147 0 : if(photo[0]!=0xFF || photo[1]!=0xD8)
148 : {
149 0 : log_error(_("'%s' is not a JPEG file\n"),filename);
150 0 : xfree(photo);
151 0 : photo=NULL;
152 0 : xfree(filename);
153 0 : filename=NULL;
154 0 : continue;
155 : }
156 :
157 : /* Build the packet */
158 0 : build_attribute_subpkt(uid,1,photo,len,header,16);
159 0 : parse_attribute_subpkts(uid);
160 0 : make_attribute_uidname(uid, EXTRA_UID_NAME_SPACE);
161 :
162 : /* Showing the photo is not safe when noninteractive since the
163 : "user" may not be able to dismiss a viewer window! */
164 0 : if(opt.command_fd==-1)
165 : {
166 0 : show_photos (uid->attribs, uid->numattribs, pk, uid);
167 0 : switch(cpr_get_answer_yes_no_quit("photoid.jpeg.okay",
168 0 : _("Is this photo correct (y/N/q)? ")))
169 : {
170 : case -1:
171 0 : goto scram;
172 : case 0:
173 0 : free_attributes(uid);
174 0 : xfree(photo);
175 0 : photo=NULL;
176 0 : xfree(filename);
177 0 : filename=NULL;
178 0 : continue;
179 : }
180 : }
181 : }
182 :
183 0 : error=0;
184 0 : uid->ref=1;
185 :
186 : scram:
187 0 : xfree(filename);
188 0 : xfree(photo);
189 :
190 0 : if(error)
191 : {
192 0 : free_attributes(uid);
193 0 : xfree(uid);
194 0 : return NULL;
195 : }
196 :
197 0 : return uid;
198 : }
199 :
200 : /* Returns 0 for error, 1 for valid */
201 0 : int parse_image_header(const struct user_attribute *attr,byte *type,u32 *len)
202 : {
203 : u16 headerlen;
204 :
205 0 : if(attr->len<3)
206 0 : return 0;
207 :
208 : /* For historical reasons (i.e. "oops!"), the header length is
209 : little endian. */
210 0 : headerlen=(attr->data[1]<<8) | attr->data[0];
211 :
212 0 : if(headerlen>attr->len)
213 0 : return 0;
214 :
215 0 : if(type && attr->len>=4)
216 : {
217 0 : if(attr->data[2]==1) /* header version 1 */
218 0 : *type=attr->data[3];
219 : else
220 0 : *type=0;
221 : }
222 :
223 0 : *len=attr->len-headerlen;
224 :
225 0 : if(*len==0)
226 0 : return 0;
227 :
228 0 : return 1;
229 : }
230 :
231 : /* style==0 for extension, 1 for name, 2 for MIME type. Remember that
232 : the "name" style string could be used in a user ID name field, so
233 : make sure it is not too big (see parse-packet.c:parse_attribute).
234 : Extensions should be 3 characters long for the best cross-platform
235 : compatibility. */
236 0 : char *image_type_to_string(byte type,int style)
237 : {
238 : char *string;
239 :
240 0 : switch(type)
241 : {
242 : case 1: /* jpeg */
243 0 : if(style==0)
244 0 : string="jpg";
245 0 : else if(style==1)
246 0 : string="jpeg";
247 : else
248 0 : string="image/jpeg";
249 0 : break;
250 :
251 : default:
252 0 : if(style==0)
253 0 : string="bin";
254 0 : else if(style==1)
255 0 : string="unknown";
256 : else
257 0 : string="image/x-unknown";
258 0 : break;
259 : }
260 :
261 0 : return string;
262 : }
263 :
264 : #if !defined(FIXED_PHOTO_VIEWER) && !defined(DISABLE_PHOTO_VIEWER)
265 0 : static const char *get_default_photo_command(void)
266 : {
267 : #if defined(_WIN32)
268 : OSVERSIONINFO osvi;
269 :
270 : memset(&osvi,0,sizeof(osvi));
271 : osvi.dwOSVersionInfoSize=sizeof(osvi);
272 : GetVersionEx(&osvi);
273 :
274 : if(osvi.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS)
275 : return "start /w %i";
276 : else
277 : return "cmd /c start /w %i";
278 : #elif defined(__APPLE__)
279 : /* OS X. This really needs more than just __APPLE__. */
280 : return "open %I";
281 : #elif defined(__riscos__)
282 : return "Filer_Run %I";
283 : #else
284 0 : return "xloadimage -fork -quiet -title 'KeyID 0x%k' stdin";
285 : #endif
286 : }
287 : #endif
288 :
289 : void
290 0 : show_photos(const struct user_attribute *attrs, int count,
291 : PKT_public_key *pk, PKT_user_id *uid)
292 : {
293 : #ifdef DISABLE_PHOTO_VIEWER
294 : (void)attrs;
295 : (void)count;
296 : (void)pk;
297 : (void)uid;
298 : #else /*!DISABLE_PHOTO_VIEWER*/
299 : int i;
300 : struct expando_args args;
301 : u32 len;
302 0 : u32 kid[2]={0,0};
303 :
304 0 : memset (&args, 0, sizeof(args));
305 0 : args.pk = pk;
306 0 : args.validity_info = get_validity_info (pk, uid);
307 0 : args.validity_string = get_validity_string (pk, uid);
308 0 : namehash_from_uid (uid);
309 0 : args.namehash = uid->namehash;
310 :
311 0 : if (pk)
312 0 : keyid_from_pk (pk, kid);
313 :
314 0 : for(i=0;i<count;i++)
315 0 : if(attrs[i].type==ATTRIB_IMAGE &&
316 0 : parse_image_header(&attrs[i],&args.imagetype,&len))
317 : {
318 : char *command,*name;
319 : struct exec_info *spawn;
320 0 : int offset=attrs[i].len-len;
321 :
322 : #ifdef FIXED_PHOTO_VIEWER
323 : opt.photo_viewer=FIXED_PHOTO_VIEWER;
324 : #else
325 0 : if(!opt.photo_viewer)
326 0 : opt.photo_viewer=get_default_photo_command();
327 : #endif
328 :
329 : /* make command grow */
330 0 : command=pct_expando(opt.photo_viewer,&args);
331 0 : if(!command)
332 0 : goto fail;
333 :
334 0 : name=xmalloc(16+strlen(EXTSEP_S)+
335 : strlen(image_type_to_string(args.imagetype,0))+1);
336 :
337 : /* Make the filename. Notice we are not using the image
338 : encoding type for more than cosmetics. Most external image
339 : viewers can handle a multitude of types, and even if one
340 : cannot understand a particular type, we have no way to know
341 : which. The spec permits this, by the way. -dms */
342 :
343 : #ifdef USE_ONLY_8DOT3
344 : sprintf(name,"%08lX" EXTSEP_S "%s",(ulong)kid[1],
345 : image_type_to_string(args.imagetype,0));
346 : #else
347 0 : sprintf(name,"%08lX%08lX" EXTSEP_S "%s",(ulong)kid[0],(ulong)kid[1],
348 0 : image_type_to_string(args.imagetype,0));
349 : #endif
350 :
351 0 : if(exec_write(&spawn,NULL,command,name,1,1)!=0)
352 : {
353 0 : xfree(name);
354 0 : goto fail;
355 : }
356 :
357 : #ifdef __riscos__
358 : riscos_set_filetype_by_mimetype(spawn->tempfile_in,
359 : image_type_to_string(args.imagetype,2));
360 : #endif
361 :
362 0 : xfree(name);
363 :
364 0 : fwrite(&attrs[i].data[offset],attrs[i].len-offset,1,spawn->tochild);
365 :
366 0 : if(exec_read(spawn)!=0)
367 : {
368 0 : exec_finish(spawn);
369 0 : goto fail;
370 : }
371 :
372 0 : if(exec_finish(spawn)!=0)
373 0 : goto fail;
374 : }
375 :
376 0 : return;
377 :
378 : fail:
379 0 : log_error(_("unable to display photo ID!\n"));
380 : #endif /*!DISABLE_PHOTO_VIEWER*/
381 : }
|