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

Contents of /trunk/Src/wptKeyEdit.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 48 - (show annotations)
Mon Oct 31 21:14:11 2005 UTC (19 years, 4 months ago) by werner
File size: 17615 byte(s)
More changes.  Compiles again but there are at least gettext issues with
w32-gettext.c.  I can't get a gpg-error build with ENABLE_NLS.

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

Properties

Name Value
svn:eol-style native

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26