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

Annotation of /trunk/Src/wptKeyEdit.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 24 - (hide 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 twoaday 23 /* wptKeyEdit.cpp - GPG key edit abstraction
2     * Copyright (C) 2005 Timo Schulz
3 twoaday 24 * Copyright (C) 2005 g10 Code GmbH
4 twoaday 23 *
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 twoaday 24 #include "wptErrors.h"
32 twoaday 23
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 twoaday 24 if (!line || strlen (line) < 3)
44 twoaday 23 return gpg_error (GPG_ERR_EOF);
45 twoaday 24 if (strncmp (line, "rvk", 3))
46     return 0; /* skip this line. */
47 twoaday 23
48 twoaday 24 log_debug ("rev_key: line=%s\r\n", line);
49    
50 twoaday 23 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 twoaday 24 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 twoaday 23 }
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 twoaday 24 gpg_decode_c_string (pend, &i->name, strlen (pend)+ 1);
123 twoaday 23 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 twoaday 24 /* 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 twoaday 23 /* 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 twoaday 24 int n;
241 twoaday 23
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 twoaday 24 err = gpgme_op_edit (ctx, key, list_handler, NULL, out);
250 twoaday 23 if (err)
251     goto leave;
252 twoaday 24
253     gpgme_data_rewind (out);
254     while ((n=gpg_data_readline (out, buf, 199)) > 0)
255 twoaday 23 rev_key_colon_handler (&rev, buf);
256     *r_rev = rev;
257 twoaday 24 /* XXX: each revoker is twice in the list. */
258 twoaday 23
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 twoaday 24 cnt = 0;
317     cmd_sent = 0;
318     resval = 0;
319 twoaday 23 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 twoaday 24 cmd_sent = 0;
332     resval = 0;
333 twoaday 23 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 twoaday 24 /* Reset the state of the object. */
347     void
348     GpgKeyEdit::reset (void)
349     {
350     cmd_sent = 0;
351     }
352    
353    
354 twoaday 23 /* 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 twoaday 24 /* Set the keyid of the destination key to @keyid. */
393 twoaday 23 void
394     GpgKeyEdit::setKeyID (const char *keyid)
395     {
396     if (!keyid)
397     return;
398     get_pubkey (keyid, &this->key);
399     }
400    
401    
402 twoaday 24 /* Set the local user for the operation to @locusr. */
403 twoaday 23 void
404     GpgKeyEdit::setLocalUser (gpgme_key_t locusr)
405     {
406     gpgme_signers_add (ctx, locusr);
407     }
408    
409 twoaday 24 /* Set the result of the operation to @val. */
410     void
411     GpgKeyEdit::setResultValue (int val)
412     {
413     resval |= val;
414     }
415 twoaday 23
416 twoaday 24
417     /* Return the result of the operation. */
418     int
419     GpgKeyEdit::getResultValue (void)
420     {
421     return resval;
422     }
423    
424    
425 twoaday 23 /* 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 twoaday 24 GpgKeyEdit::delUseridSignature (int uid_index, int sig_index)
691 twoaday 23 {
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