/[winpt]/trunk/Src/wptKeyEdit.cpp
ViewVC logotype

Contents of /trunk/Src/wptKeyEdit.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 24 - (show annotations)
Sat Oct 8 10:43:08 2005 UTC (19 years, 4 months ago) by twoaday
File size: 17886 byte(s)
Bug fixes to correct some problems introduced by
the MyGPGME to GPGME port.

1 /* wptKeyEdit.cpp - GPG key edit abstraction
2 * Copyright (C) 2005 Timo Schulz
3 * Copyright (C) 2005 g10 Code GmbH
4 *
5 * This file is part of WinPT.
6 *
7 * WinPT is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * WinPT is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with WinPT; if not, write to the Free Software Foundation,
19 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include <windows.h>
23
24 #include "w32gpgme.h"
25 #include "wptCommonCtl.h"
26 #include "wptContext.h"
27 #include "wptKeyEdit.h"
28 #include "wptTypes.h"
29 #include "wptW32API.h"
30 #include "wptGPG.h"
31 #include "wptErrors.h"
32
33 /* Parse the colon status information of @line and store
34 the information in @rev.
35 Return value: 0 on success. */
36 static gpgme_error_t
37 rev_key_colon_handler (gpg_desig_rev_t *rev, char *line)
38 {
39 char *p, *pend;
40 gpg_desig_rev_t r, t;
41 int field = 0;
42
43 if (!line || strlen (line) < 3)
44 return gpg_error (GPG_ERR_EOF);
45 if (strncmp (line, "rvk", 3))
46 return 0; /* skip this line. */
47
48 log_debug ("rev_key: line=%s\r\n", line);
49
50 r = (gpg_desig_rev_t)calloc (1, sizeof *r);
51 if (!r)
52 return gpg_error (GPG_ERR_ENOMEM);
53 if (!*rev)
54 *rev = r;
55 else {
56 for (t=*rev; t->next; t=t->next)
57 ;
58 t->next = r;
59 }
60
61 p = strdup (line);
62 if (!p)
63 return gpg_error (GPG_ERR_ENOMEM);
64
65 for (;;) {
66 field++;
67 pend = strsep (&p, ":");
68 if (pend == NULL)
69 break;
70 switch (field) {
71 case 4: r->pubkey_algo = (gpgme_pubkey_algo_t)atol (pend); break;
72 case 10: strncpy (r->fpr, pend, 40); r->fpr[40] = 0; break;
73 }
74 }
75 if (p)
76 free (p);
77 return 0;
78 }
79
80
81 /* Parse the colon data output of edit key from @line and
82 store the information in the @inf context.
83 Return value: 0 on success. */
84 static gpgme_error_t
85 uid_inf_colon_handler (gpg_uid_info_t *inf, char *line)
86 {
87 char *p, *pend;
88 int field = 0, len = 0;
89 gpg_uid_info_t i, t;
90
91 if (!line || strlen (line) < 3 || strncmp (line, "uid", 3))
92 return gpg_error (GPG_ERR_EOF);
93
94 i = (gpg_uid_info_t)calloc (1, sizeof *i);
95 if (!i)
96 return gpg_error (GPG_ERR_ENOMEM);
97 if (!*inf)
98 *inf = i;
99 else {
100 for (t=*inf; t->next; t=t->next)
101 ;
102 t->next = i;
103 }
104
105 p = strdup (line);
106 if (!p)
107 return gpg_error (GPG_ERR_ENOMEM);;
108 for (;;) {
109 field++;
110 pend = strsep (&p, ":");
111 if (pend == NULL)
112 break;
113
114 switch (field) {
115 case 2: /* trust info */
116 break;
117
118 case 10: /* user ID */
119 i->name = (char *)calloc (1, strlen (pend)+1);
120 if (!i->name)
121 return gpg_error (GPG_ERR_ENOMEM);;
122 gpg_decode_c_string (pend, &i->name, strlen (pend)+ 1);
123 if (strchr (pend, '<') != NULL && strchr (pend, '>') != NULL) {
124 int pos = strchr (i->name, '<')- i->name + 1;
125 int end = strchr (i->name, '>') - i->name;
126 i->email = (char*) calloc (1, end-pos+2);
127 if (!i->email)
128 return gpg_error (GPG_ERR_ENOMEM);;
129 memcpy (i->email, i->name+pos, (end-pos));
130 }
131 break;
132
133 case 13: /* preferences */
134 if (strstr (pend, "mdc")) {
135 len = strlen (pend) - 4; /* ,mdc */
136 if (strstr (pend, "no-ks-modify")) {
137 i->flags.no_ks_modify = 1;
138 len -= 13; /* ,no-ks-modify */
139 }
140 i->prefs = (char*)calloc (1, len+1);
141 if (!i->prefs)
142 return gpg_error (GPG_ERR_ENOMEM);
143 memcpy (i->prefs, pend, len);
144 i->prefs[len] = '\0';
145 i->flags.mdc = 1;
146 }
147 else {
148 i->prefs = strdup (pend);
149 if (!i->prefs)
150 return gpg_error (GPG_ERR_ENOMEM);
151 i->flags.mdc = 0;
152 }
153 break;
154
155 case 14: /* index/flags */
156 i->index = atol (pend);
157 if (strchr (pend, 'r'))
158 i->flags.revoked = 1;
159 if (strchr (pend, 'p'))
160 i->flags.primary = 1;
161 break;
162 }
163 }
164 if (p)
165 free (p);
166 return 0;
167 }
168
169
170 /* Release the context in @inf. */
171 void
172 gpg_uid_info_release (gpg_uid_info_t list)
173 {
174 gpg_uid_info_t i;
175
176 while (list) {
177 i = list->next;
178 if (list->name) {
179 if (list->name)
180 free (list->name);
181 list->name = NULL;
182 }
183 if (list->prefs) {
184 if (list->prefs)
185 free (list->prefs);
186 list->prefs = NULL;
187 }
188 free (list);
189 list = i;
190 }
191 }
192
193
194 /* Release the context in @rev. */
195 void
196 gpg_desig_rev_release (gpg_desig_rev_t rev)
197 {
198 gpg_desig_rev_t r;
199
200 while (rev) {
201 r = rev->next;
202 free (rev);
203 rev = r;
204 }
205 }
206
207
208 /* Dummy handler to get the colon data and then quit. */
209 static gpgme_error_t
210 list_handler (void *opaque, gpgme_status_code_t code, const char *key, int fd)
211 {
212 static int step=0;
213 const char *s="";
214 DWORD n;
215
216 if (!strcmp (key, "keyedit.prompt") && step == 0) {
217 step = 1;
218 s = "list\n";
219 WriteFile ((HANDLE)fd, s, strlen (s), &n, NULL);
220 }
221 else if (!strcmp (key, "keyedit.prompt") && step == 1) {
222 step = 0;
223 s = "quit\n";
224 WriteFile ((HANDLE)fd, s, strlen (s), &n, NULL);
225 }
226 return 0;
227 }
228
229
230 /* Return all designated revokers for this key. If no revoker
231 was set, @r_rev is NULL.
232 Return value: 0 on success. */
233 gpgme_error_t
234 GpgKeyEdit::getDesignatedRevoker (gpg_desig_rev_t *r_rev)
235 {
236 gpgme_data_t out=NULL;
237 gpg_desig_rev_t rev = NULL;
238 gpgme_error_t err;
239 char buf[200];
240 int n;
241
242 if (!this->key)
243 return gpg_error (GPG_ERR_INV_OBJ);
244
245 err = gpgme_data_new (&out);
246 if (err)
247 goto leave;
248
249 err = gpgme_op_edit (ctx, key, list_handler, NULL, out);
250 if (err)
251 goto leave;
252
253 gpgme_data_rewind (out);
254 while ((n=gpg_data_readline (out, buf, 199)) > 0)
255 rev_key_colon_handler (&rev, buf);
256 *r_rev = rev;
257 /* XXX: each revoker is twice in the list. */
258
259 leave:
260 if (out)
261 gpgme_data_release (out);
262 if (err) {
263 gpg_desig_rev_release (rev);
264 *r_rev = NULL;
265 }
266 return err;
267 }
268
269 /* Retrieve all user ID information of the key set via setKey
270 in @r_inf. The result also contains the user ID number which
271 is needed to securely delete the user-ID. */
272 gpgme_error_t
273 GpgKeyEdit::getUseridInfo (gpg_uid_info_t *r_uinf)
274 {
275 gpgme_data_t out = NULL;
276 gpgme_error_t err;
277 gpg_uid_info_t inf = NULL;
278 char buf[200];
279
280 if (!this->key)
281 return gpg_error (GPG_ERR_INV_OBJ);
282
283 err = gpgme_data_new (&out);
284 if (err)
285 goto leave;
286
287 err = gpgme_op_edit (ctx, key, NULL, NULL, out);
288 if (err)
289 goto leave;
290
291 while (gpg_data_readline (out, buf, sizeof buf -1))
292 uid_inf_colon_handler (&inf, buf);
293
294 *r_uinf = inf;
295
296 leave:
297 if (out)
298 gpgme_data_release (out);
299 if (err) {
300 gpg_uid_info_release (inf);
301 *r_uinf = NULL;
302 }
303 return err;
304 }
305
306
307 /* Construct an object with the given key in @key. */
308 GpgKeyEdit::GpgKeyEdit (gpgme_key_t key)
309 {
310 this->key = key;
311 pass = NULL;
312 type = 0;
313 name = NULL;
314 cmt = NULL;
315 email = NULL;
316 cnt = 0;
317 cmd_sent = 0;
318 resval = 0;
319 gpgme_new (&ctx); /* FIXME */
320 }
321
322 /* Construct an object and fetch the key with the keyid @keyid. */
323 GpgKeyEdit::GpgKeyEdit (const char *keyid)
324 {
325 get_pubkey (keyid, &this->key);
326 pass = NULL;
327 type = 0;
328 name = NULL;
329 cmt = NULL;
330 email = NULL;
331 cmd_sent = 0;
332 resval = 0;
333 gpgme_new (&ctx); /* FIXME */
334 }
335
336 /* Delete the given object. */
337 GpgKeyEdit::~GpgKeyEdit (void)
338 {
339 free_if_alloc (name);
340 free_if_alloc (cmt);
341 free_if_alloc (email);
342 gpgme_release (ctx);
343 }
344
345
346 /* Reset the state of the object. */
347 void
348 GpgKeyEdit::reset (void)
349 {
350 cmd_sent = 0;
351 }
352
353
354 /* Return true if type has a non-zero value. */
355 bool
356 GpgKeyEdit::isValid (void)
357 {
358 return type != 0;
359 }
360
361
362 /* Return the GPGME key. */
363 gpgme_key_t
364 GpgKeyEdit::getKey (void)
365 {
366 return key;
367 }
368
369
370 /* Set the GPGME callback to @cb. The hook value can be
371 given in @cb_value. */
372 void
373 GpgKeyEdit::setCallback (gpgme_progress_cb_t cb, void *cb_value)
374 {
375 gpgme_set_progress_cb (ctx, cb, cb_value);
376 }
377
378 /* Set the passphrase to @pass. */
379 void
380 GpgKeyEdit::setPassphrase (const char *pass)
381 {
382 this->pass = pass;
383 }
384
385 /* Set the current key to @key. */
386 void
387 GpgKeyEdit::setKey (gpgme_key_t key)
388 {
389 this->key = key;
390 }
391
392 /* Set the keyid of the destination key to @keyid. */
393 void
394 GpgKeyEdit::setKeyID (const char *keyid)
395 {
396 if (!keyid)
397 return;
398 get_pubkey (keyid, &this->key);
399 }
400
401
402 /* Set the local user for the operation to @locusr. */
403 void
404 GpgKeyEdit::setLocalUser (gpgme_key_t locusr)
405 {
406 gpgme_signers_add (ctx, locusr);
407 }
408
409 /* Set the result of the operation to @val. */
410 void
411 GpgKeyEdit::setResultValue (int val)
412 {
413 resval |= val;
414 }
415
416
417 /* Return the result of the operation. */
418 int
419 GpgKeyEdit::getResultValue (void)
420 {
421 return resval;
422 }
423
424
425 /* Sign the key stored in the object with the
426 signing mode @mode and the signature class @sig_class.
427 Return value: 0 on success. */
428 gpgme_error_t
429 GpgKeyEdit::signKey (int mode, int sig_class, const char *exp_date)
430 {
431 if (!this->key || !this->pass)
432 return gpg_error (GPG_ERR_INV_OBJ);
433
434 type = mode;
435 this->exp_date = exp_date;
436 this->sig_class = sig_class;
437 return gpg_editkey (this->ctx, this->key, this);
438 }
439
440 /* Set the ownertrust of the key stored in the object
441 to the trust value @trust.
442 Return value: 0 on success. */
443 gpgme_error_t
444 GpgKeyEdit::setTrust (gpgme_validity_t trust)
445 {
446 if (!this->key)
447 return gpg_error (GPG_ERR_INV_OBJ);
448
449 type = GPG_EDITKEY_TRUST;
450 this->trust_id = (int)trust;
451 return gpg_editkey (this->ctx, this->key, this);
452 }
453
454 /* Add a user ID to the given key with the @name as the
455 name, @cmt as the comment (or NULL) and @email as the email.
456 Return value: 0 on success. */
457 gpgme_error_t
458 GpgKeyEdit::addUserid (const char *name, const char *cmt, const char *email)
459 {
460 if (!this->key || !this->pass)
461 return gpg_error (GPG_ERR_INV_OBJ);
462
463 type = GPG_EDITKEY_ADDUID;
464 free_if_alloc (this->name);
465 this->name = m_strdup (name);
466 free_if_alloc (this->cmt);
467 this->cmt = m_strdup (cmt);
468 free_if_alloc (this->email);
469 this->email = m_strdup (email);
470 if (!this->email || !this->name || !this->cmt)
471 BUG (NULL);
472 return gpg_editkey (this->ctx, this->key, this);
473 }
474
475 /* Delete the user-ID with the index @uid_index of the given key.
476 Return value: 0 on success. */
477 gpgme_error_t
478 GpgKeyEdit::delUserid (int uid_index)
479 {
480 if (!this->key)
481 return gpg_error (GPG_ERR_INV_OBJ);
482
483 type = GPG_EDITKEY_DELUID;
484 this->uid_index = uid_index;
485 return gpg_editkey (this->ctx, this->key, this);
486 }
487
488 /* Delete the subkey with the index @key_index.
489 Return value: 0 on success. */
490 gpgme_error_t
491 GpgKeyEdit::delKey (int key_index)
492 {
493 if (!this->key)
494 return gpg_error (GPG_ERR_INV_OBJ);
495
496 type = GPG_EDITKEY_DELKEY;
497 this->key_index = key_index;
498 return gpg_editkey (this->ctx, this->key, this);
499 }
500
501 /* Add a new subkey to the given key.
502 The new key will have @pubkey_algo as the algorithm
503 and a size of @pubkey_size bits. If valid > 0, the
504 key expires in @valid days.
505 Return value: 0 on success. */
506 gpgme_error_t
507 GpgKeyEdit::addSubkey (gpgme_pubkey_algo_t pubkey_algo, unsigned int pubkey_size,
508 long valid)
509 {
510 if (!this->key || !this->pass)
511 return gpg_error (GPG_ERR_INV_OBJ);
512
513 type = GPG_EDITKEY_ADDKEY;
514 this->pubkey_algo = pubkey_algo;
515 this->pubkey_size = pubkey_size;
516 this->valid = valid;
517 return gpg_editkey (this->ctx, this->key, this);
518 }
519
520 /* Change the passphrase of the given key to @new_pass.
521 If allow_empty != 0, it is allowed to provide an empty passphrase.
522 Return value: 0 on success. */
523 gpgme_error_t
524 GpgKeyEdit::changePassphrase (const char *new_pass, int allow_empty)
525 {
526 if (!this->key || !this->pass)
527 return gpg_error (GPG_ERR_INV_OBJ);
528
529 type = GPG_EDITKEY_PASSWD;
530 this->new_pass = new_pass;
531 this->flags = allow_empty? 1 : 0;
532 return gpg_editkey (this->ctx, this->key, this);
533 }
534
535 /* Set the primary user-ID of the given key to user-ID with
536 the index @uid_index.
537 Return value: 0 on success. */
538 gpgme_error_t
539 GpgKeyEdit::setPrimaryUserid (int uid_index)
540 {
541 if (!this->key || !this->pass)
542 return gpg_error (GPG_ERR_INV_OBJ);
543
544 type = GPG_EDITKEY_PRIMARY;
545 this->uid_index = uid_index;
546 return gpg_editkey (this->ctx, this->key, this);
547 }
548
549 /* Set the expire date of the subkey with the index @key_index.
550 @exp_timestamp is used to calculate the days the key is valid.
551 Return value: 0 on success. */
552 gpgme_error_t
553 GpgKeyEdit::setKeyExpireDate (int key_index, long exp_timestamp)
554 {
555 if (!this->key || !this->pass)
556 return gpg_error (GPG_ERR_INV_OBJ);
557 if (exp_timestamp > 0 && exp_timestamp < time (NULL))
558 return gpg_error (GPG_ERR_INV_ARG);
559
560 valid = 0;
561 if (exp_timestamp > 0) {
562 valid = exp_timestamp - time (NULL);
563 valid /= 86400;
564 type = GPG_EDITKEY_EXPIRE;
565 }
566 this->key_index = key_index;
567 return gpg_editkey (this->ctx, this->key, this);
568 }
569
570
571 /* Revoke a signature on the user-ID with the index @uid_index
572 and the signature index @sig_index.
573 Return value: 0 on success. */
574 gpgme_error_t
575 GpgKeyEdit::revokeSignature (int uid_index, int sig_index)
576 {
577 if (!this->key || !this->pass)
578 return gpg_error (GPG_ERR_INV_OBJ);
579
580 type = GPG_EDITKEY_REVSIG;
581 this->uid_index = uid_index;
582 this->sig_index = sig_index;
583 return gpg_editkey (this->ctx, this->key, this);
584 }
585
586
587 /* Revoke the subkey with the index @key_index. Optionally
588 a reason can be provided in @reason with a text to describe
589 more details in @cmt.
590 Return value: 0 on success. */
591 gpgme_error_t
592 GpgKeyEdit::revokeSubkey (int key_index, int reason, const char *cmt)
593 {
594 if (!this->key || !this->pass)
595 return gpg_error (GPG_ERR_INV_OBJ);
596
597 type = GPG_EDITKEY_REVKEY;
598 this->key_index = key_index;
599 this->reason = reason;
600 free_if_alloc (this->cmt);
601 this->cmt = m_strdup (cmt);
602 return gpg_editkey (this->ctx, this->key, this);
603 }
604
605
606 /* Revoke an entire key. With the reason given in @reason
607 and the description in @cmt.
608 Return value: 0 on success. */
609 gpgme_error_t
610 GpgKeyEdit::revokeKey (int reason, const char *cmt)
611 {
612 if (!this->key || !this->pass)
613 return gpg_error (GPG_ERR_INV_OBJ);
614
615 type = GPG_EDITKEY_REVOKE;
616 this->reason = reason;
617 free_if_alloc (this->cmt);
618 this->cmt = m_strdup (cmt);
619 return gpg_editkey (this->ctx, this->key, this);
620 }
621
622
623 /* Add a designated revoker to the key. @uid stores
624 the user-ID of the key who is allowed to be a
625 designated revoker.
626 Return value: 0 on success. */
627 gpgme_error_t
628 GpgKeyEdit::addDesignatedRevoker (const char *uid)
629 {
630 if (!this->key || !this->pass)
631 return gpg_error (GPG_ERR_INV_OBJ);
632
633 type = GPG_EDITKEY_ADDREV;
634 free_if_alloc (this->name);
635 this->name = m_strdup (uid);
636 return gpg_editkey (this->ctx, this->key, this);
637 }
638
639 /* Add a photo-ID to the key. The JPG image is given
640 in the file with the name @jpg_file.
641 Return value: 0 on success. */
642 gpgme_error_t
643 GpgKeyEdit::addPhotoid (const char *jpg_file)
644 {
645 if (!this->key || !this->pass)
646 return gpg_error (GPG_ERR_INV_OBJ);
647
648 type = GPG_EDITKEY_ADDPHOTO;
649 this->url = jpg_file;
650 return gpg_editkey (this->ctx, this->key, this);
651 }
652
653 /* Enable the given key. */
654 gpgme_error_t
655 GpgKeyEdit::enable (void)
656 {
657 if (!this->key)
658 return gpg_error (GPG_ERR_INV_OBJ);
659 type = GPG_EDITKEY_ENABLE;
660 return gpg_editkey (this->ctx, this->key, this);
661 }
662
663 /* Disable the given key. */
664 gpgme_error_t
665 GpgKeyEdit::disable (void)
666 {
667 if (!this->key)
668 return gpg_error (GPG_ERR_INV_OBJ);
669 type = GPG_EDITKEY_DISABLE;
670 return gpg_editkey (this->ctx, this->key, this);
671 }
672
673
674 /* Update the user-ID preferences of the user-ID with the
675 index @uid_index to the prefs given in @new_prefs.
676 Return value: 0 on success. */
677 gpgme_error_t
678 GpgKeyEdit::setUseridPreferences (int uid_index, const char *new_prefs)
679 {
680 if (!this->key || !this->pass)
681 return gpg_error (GPG_ERR_INV_OBJ);
682 return GPG_ERR_NO_ERROR;
683 }
684
685
686 /* Delete a signature from the user-ID with the index @uid_index.
687 The index of the signature is given in @sig_index.
688 Return value: 0 on success. */
689 gpgme_error_t
690 GpgKeyEdit::delUseridSignature (int uid_index, int sig_index)
691 {
692 if (!this->key)
693 return gpg_error (GPG_ERR_INV_OBJ);
694 type = GPG_EDITKEY_DELSIG;
695 this->uid_index = uid_index;
696 this->sig_index = sig_index;
697 return gpg_editkey (this->ctx, this->key, this);
698 }
699
700 /* Set the preferred keyserver for the given key to @url.
701 Return value: 0 on success. */
702 gpgme_error_t
703 GpgKeyEdit::setPreferredKeyserver (int uid_index, const char *url)
704 {
705 if (!this->key || !this->pass)
706 return gpg_error (GPG_ERR_INV_OBJ);
707 if (!url)
708 return gpg_error (GPG_ERR_INV_ARG);
709 type = GPG_EDITKEY_KEYSERV;
710 this->url = url;
711 this->uid_index = uid_index;
712 return gpg_editkey (this->ctx, this->key, this);
713 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26