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

Annotation of /trunk/Src/wptKeyEdit.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 23 - (hide annotations)
Fri Sep 30 10:10:16 2005 UTC (19 years, 5 months ago) by twoaday
File size: 16597 byte(s)
Almost finished phase 1 of the WinPT GPGME port.
Still need more cleanup, comments and tests.


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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26