chiark / gitweb /
Merge branch '2.4.x' into 2.5.x
[catacomb] / key / key-attr.c
1 /* -*-c-*-
2  *
3  * Key attribute manipulation
4  *
5  * (c) 1999 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of Catacomb.
11  *
12  * Catacomb is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU Library General Public License as
14  * published by the Free Software Foundation; either version 2 of the
15  * License, or (at your option) any later version.
16  *
17  * Catacomb is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License along with Catacomb; if not, write to the Free
24  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25  * MA 02111-1307, USA.
26  */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include <ctype.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <time.h>
35
36 #include <mLib/dstr.h>
37 #include <mLib/sym.h>
38
39 #include "key.h"
40
41 /*----- Main code ---------------------------------------------------------*/
42
43 /* --- @key_chkident@ --- *
44  *
45  * Arguments:   @const char *p@ = pointer to a type string
46  *
47  * Returns:     Zero if OK, -1 on error.
48  *
49  * Use:         Checks whether an identification component string is OK.
50  */
51
52 int key_chkident(const char *p)
53 {
54   if (!p || !*p || strlen(p) > 255)
55     return (-1);
56   while (*p) {
57     if (*p == ':' || *p == '.' || isspace((unsigned char)*p))
58       return (-1);
59     p++;
60   }
61   return (0);
62 }
63
64 /* --- @key_chkcomment@ --- *
65  *
66  * Arguments:   @const char *p@ = pointer to a comment string
67  *
68  * Returns:     Zero if OK, -1 on error.
69  *
70  * Use:         Checks whether a comment string is OK.
71  */
72
73 int key_chkcomment(const char *p)
74 {
75   if (!p)
76     return (0);
77   if (!*p)
78     return (-1);
79   while (*p) {
80     if (*p == '\n')
81       return (-1);
82     p++;
83   }
84   return (0);
85 }
86
87 /* --- @key_mkattriter@ --- *
88  *
89  * Arguments:   @key_attriter *i@ = pointer to attribute iterator
90  *              @key *k@ = pointer to key
91  *
92  * Returns:     ---
93  *
94  * Use:         Initializes an attribute iterator.  The attributes are
95  *              returned by @key_nextattr@.
96  */
97
98 void key_mkattriter(key_attriter *i, key *k)
99 {
100   sym_mkiter(&i->i, &k->a);
101 }
102
103 /* --- @key_nextattr@ --- *
104  *
105  * Arguments:   @key_attriter *i@ = pointer to attribute iterator
106  *              @const char **n, **v@ = pointers to name and value
107  *
108  * Returns:     Zero if no attribute available, or nonzero if returned OK.
109  *
110  * Use:         Returns the next attribute.
111  */
112
113 int key_nextattr(key_attriter *i, const char **n, const char **v)
114 {
115   key_attr *a = sym_next(&i->i);
116   if (!a)
117     return (0);
118   if (n) *n = SYM_NAME(a);
119   if (v) *v = a->p;
120   return (1);
121 }
122
123 /* --- @key_getattr@ --- *
124  *
125  * Arguments:   @key_file *f@ = pointer to file
126  *              @key *k@ = pointer to key
127  *              @const char *n@ = pointer to attribute name
128  *
129  * Returns:     Pointer to attribute value, or null if not found.
130  *
131  * Use:         Returns the value of a key attribute.
132  */
133
134 const char *key_getattr(key_file *f, key *k, const char *n)
135 {
136   key_attr *a;
137   if ((a = sym_find(&k->a, n, -1, 0, 0)) == 0)
138     return (0);
139   return (a->p);
140 }
141
142 /* --- @key_putattr@ --- *
143  *
144  * Arguments:   @key_file *f@ = pointer to file
145  *              @key *k@ = pointer to key
146  *              @const char *n@ = pointer to attribute name
147  *              @const char *v@ = pointer to attribute value or null
148  *
149  * Returns:     Error code (one of the @KERR@ constants).
150  *
151  * Use:         Inserts an attribute on a key.  If an attribute with the same
152  *              name already exists, it is deleted.  Setting a null value
153  *              removes the attribute.
154  */
155
156 int key_putattr(key_file *f, key *k, const char *n, const char *v)
157 {
158   key_attr *a;
159   unsigned found;
160
161   if (!(f->f & KF_WRITE))
162     return (KERR_READONLY);
163   if (strlen(n) > 255)
164     return (KERR_BADATTR);
165
166   if (v) {
167     a = sym_find(&k->a, n, -1, sizeof(*a), &found);
168     if (found)
169       xfree(a->p);
170     a->p = xstrdup(v);
171   } else if ((a = sym_find(&k->a, n, -1, 0, 0)) != 0) {
172     xfree(a->p);
173     sym_remove(&k->a, a);
174   }
175
176   f->f |= KF_MODIFIED;
177   return (0);
178 }
179
180 /* --- @key_setkeydata@ --- *
181  *
182  * Arguments:   @key_file *kf@ = pointer to key file
183  *              @key *k@ = pointer to key
184  *              @key_data *kd@ = new key data
185  *
186  * Returns:     Zero on success, or a @KERR_@ error code on failure.
187  *
188  * Use:         Sets the key data for a key.
189  */
190
191 int key_setkeydata(key_file *kf, key *k, key_data *kd)
192 {
193   if (!(kf->f & KF_WRITE))
194     return (KERR_READONLY);
195   key_incref(kd);
196   key_drop(k->k);
197   k->k = kd;
198   kf->f |= KF_MODIFIED;
199   return (0);
200 }
201
202 /* --- @key_setcomment@ --- *
203  *
204  * Arguments:   @key_file *f@ = pointer to key file block
205  *              @key *k@ = pointer to key block
206  *              @const char *c@ = pointer to comment to set, or zero
207  *
208  * Returns:     Error code (one of the @KERR@ constants).
209  *
210  * Use:         Replaces the key's current comment with a new one.
211  */
212
213 int key_setcomment(key_file *f, key *k, const char *c)
214 {
215   if (!(f->f & KF_WRITE))
216     return (KERR_READONLY);
217   if (key_chkcomment(c))
218     return (KERR_BADCOMMENT);
219   if (k->c)
220     xfree(k->c);
221   if (c)
222     k->c = xstrdup(c);
223   else
224     k->c = 0;
225   f->f |= KF_MODIFIED;
226   return (0);
227 }
228
229 /* --- @key_settag@ --- *
230  *
231  * Arguments:   @key_file *f@ = pointer to key file block
232  *              @key *k@ = pointer to key block
233  *              @const char *tag@ = pointer to comment to set, or zero
234  *
235  * Returns:     Error code (one of the @KERR@ constants).
236  *
237  * Use:         Replaces the key's current tag with a new one.
238  */
239
240 int key_settag(key_file *f, key *k, const char *tag)
241 {
242   key_ref *kr;
243   unsigned found;
244
245   if (!(f->f & KF_WRITE))
246     return (KERR_READONLY);
247
248   /* --- Make sure the tag is OK --- */
249
250   if (tag && key_chkident(tag))
251     return (KERR_BADTAG);
252
253   /* --- See if the new tag is the same as the old one --- */
254
255   if ((!tag && !k->tag) ||
256       (tag && k->tag && strcmp(tag, k->tag) == 0))
257     return (0);
258
259   /* --- Allocate an entry for the new tag --- */
260
261   if (tag) {
262     kr = sym_find(&f->bytag, tag, -1, sizeof(*kr), &found);
263     if (found && !KEY_EXPIRED(time(0), kr->k->del))
264       return (KERR_DUPTAG);
265     kr->k = k;
266   }
267
268   /* --- Remove any existing tag --- */
269
270   if (k->tag) {
271     kr = sym_find(&f->bytag, k->tag, -1, 0, 0);
272     assert(((void)"No bytag link", kr));
273     sym_remove(&f->bytag, kr);
274     xfree(k->tag);
275   }
276
277   /* --- Done --- */
278
279   f->f |= KF_MODIFIED;
280   if (tag)
281     k->tag = xstrdup(tag);
282   else
283     k->tag = 0;
284   return (0);
285 }
286
287 /* --- @key_fulltag@ --- *
288  *
289  * Arguments:   @key *k@ = pointer to key
290  *              @dstr *d@ = pointer to destination string
291  *
292  * Returns:     ---
293  *
294  * Use:         Emits the key's full tag, which has the form
295  *              `ID:TYPE[:TAG]'.  This is used in the textual file format,
296  *              and to identify passphrases for locked keys.
297  */
298
299 void key_fulltag(key *k, dstr *d)
300 {
301   dstr_putf(d, "%08lx:%s", (unsigned long)k->id, k->type);
302   if (k->tag)
303     dstr_putf(d, ":%s", k->tag);
304 }
305
306 /*----- That's all, folks -------------------------------------------------*/