--- /dev/null
+/* -*-c-*-
+ *
+ * Key attribute manipulation
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <mLib/dstr.h>
+#include <mLib/sym.h>
+
+#include "key.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @key_chkident@ --- *
+ *
+ * Arguments: @const char *p@ = pointer to a type string
+ *
+ * Returns: Zero if OK, -1 on error.
+ *
+ * Use: Checks whether an identification component string is OK.
+ */
+
+int key_chkident(const char *p)
+{
+ if (!p || !*p || strlen(p) > 255)
+ return (-1);
+ while (*p) {
+ if (*p == ':' || *p == '.' || isspace((unsigned char)*p))
+ return (-1);
+ p++;
+ }
+ return (0);
+}
+
+/* --- @key_chkcomment@ --- *
+ *
+ * Arguments: @const char *p@ = pointer to a comment string
+ *
+ * Returns: Zero if OK, -1 on error.
+ *
+ * Use: Checks whether a comment string is OK.
+ */
+
+int key_chkcomment(const char *p)
+{
+ if (!p)
+ return (0);
+ if (!*p)
+ return (-1);
+ while (*p) {
+ if (*p == '\n')
+ return (-1);
+ p++;
+ }
+ return (0);
+}
+
+/* --- @key_mkattriter@ --- *
+ *
+ * Arguments: @key_attriter *i@ = pointer to attribute iterator
+ * @key *k@ = pointer to key
+ *
+ * Returns: ---
+ *
+ * Use: Initializes an attribute iterator. The attributes are
+ * returned by @key_nextattr@.
+ */
+
+void key_mkattriter(key_attriter *i, key *k)
+{
+ sym_mkiter(&i->i, &k->a);
+}
+
+/* --- @key_nextattr@ --- *
+ *
+ * Arguments: @key_attriter *i@ = pointer to attribute iterator
+ * @const char **n, **v@ = pointers to name and value
+ *
+ * Returns: Zero if no attribute available, or nonzero if returned OK.
+ *
+ * Use: Returns the next attribute.
+ */
+
+int key_nextattr(key_attriter *i, const char **n, const char **v)
+{
+ key_attr *a = sym_next(&i->i);
+ if (!a)
+ return (0);
+ if (n) *n = SYM_NAME(a);
+ if (v) *v = a->p;
+ return (1);
+}
+
+/* --- @key_getattr@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to file
+ * @key *k@ = pointer to key
+ * @const char *n@ = pointer to attribute name
+ *
+ * Returns: Pointer to attribute value, or null if not found.
+ *
+ * Use: Returns the value of a key attribute.
+ */
+
+const char *key_getattr(key_file *f, key *k, const char *n)
+{
+ key_attr *a;
+ if ((a = sym_find(&k->a, n, -1, 0, 0)) == 0)
+ return (0);
+ return (a->p);
+}
+
+/* --- @key_putattr@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to file
+ * @key *k@ = pointer to key
+ * @const char *n@ = pointer to attribute name
+ * @const char *v@ = pointer to attribute value or null
+ *
+ * Returns: Error code (one of the @KERR@ constants).
+ *
+ * Use: Inserts an attribute on a key. If an attribute with the same
+ * name already exists, it is deleted. Setting a null value
+ * removes the attribute.
+ */
+
+int key_putattr(key_file *f, key *k, const char *n, const char *v)
+{
+ key_attr *a;
+ unsigned found;
+
+ if (!(f->f & KF_WRITE))
+ return (KERR_READONLY);
+ if (strlen(n) > 255)
+ return (KERR_BADATTR);
+
+ if (v) {
+ a = sym_find(&k->a, n, -1, sizeof(*a), &found);
+ if (found)
+ xfree(a->p);
+ a->p = xstrdup(v);
+ } else if ((a = sym_find(&k->a, n, -1, 0, 0)) != 0) {
+ xfree(a->p);
+ sym_remove(&k->a, a);
+ }
+
+ f->f |= KF_MODIFIED;
+ return (0);
+}
+
+/* --- @key_setkeydata@ --- *
+ *
+ * Arguments: @key_file *kf@ = pointer to key file
+ * @key *k@ = pointer to key
+ * @key_data *kd@ = new key data
+ *
+ * Returns: Zero on success, or a @KERR_@ error code on failure.
+ *
+ * Use: Sets the key data for a key.
+ */
+
+int key_setkeydata(key_file *kf, key *k, key_data *kd)
+{
+ if (!(kf->f & KF_WRITE))
+ return (KERR_READONLY);
+ key_incref(kd);
+ key_drop(k->k);
+ k->k = kd;
+ kf->f |= KF_MODIFIED;
+ return (0);
+}
+
+/* --- @key_setcomment@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to key file block
+ * @key *k@ = pointer to key block
+ * @const char *c@ = pointer to comment to set, or zero
+ *
+ * Returns: Error code (one of the @KERR@ constants).
+ *
+ * Use: Replaces the key's current comment with a new one.
+ */
+
+int key_setcomment(key_file *f, key *k, const char *c)
+{
+ if (!(f->f & KF_WRITE))
+ return (KERR_READONLY);
+ if (key_chkcomment(c))
+ return (KERR_BADCOMMENT);
+ if (k->c)
+ xfree(k->c);
+ if (c)
+ k->c = xstrdup(c);
+ else
+ k->c = 0;
+ f->f |= KF_MODIFIED;
+ return (0);
+}
+
+/* --- @key_settag@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to key file block
+ * @key *k@ = pointer to key block
+ * @const char *tag@ = pointer to comment to set, or zero
+ *
+ * Returns: Error code (one of the @KERR@ constants).
+ *
+ * Use: Replaces the key's current tag with a new one.
+ */
+
+int key_settag(key_file *f, key *k, const char *tag)
+{
+ key_ref *kr;
+ unsigned found;
+
+ if (!(f->f & KF_WRITE))
+ return (KERR_READONLY);
+
+ /* --- Make sure the tag is OK --- */
+
+ if (tag && key_chkident(tag))
+ return (KERR_BADTAG);
+
+ /* --- See if the new tag is the same as the old one --- */
+
+ if ((!tag && !k->tag) ||
+ (tag && k->tag && strcmp(tag, k->tag) == 0))
+ return (0);
+
+ /* --- Allocate an entry for the new tag --- */
+
+ if (tag) {
+ kr = sym_find(&f->bytag, tag, -1, sizeof(*kr), &found);
+ if (found && !KEY_EXPIRED(time(0), kr->k->del))
+ return (KERR_DUPTAG);
+ kr->k = k;
+ }
+
+ /* --- Remove any existing tag --- */
+
+ if (k->tag) {
+ kr = sym_find(&f->bytag, k->tag, -1, 0, 0);
+ assert(((void)"No bytag link", kr));
+ sym_remove(&f->bytag, kr);
+ xfree(k->tag);
+ }
+
+ /* --- Done --- */
+
+ f->f |= KF_MODIFIED;
+ if (tag)
+ k->tag = xstrdup(tag);
+ else
+ k->tag = 0;
+ return (0);
+}
+
+/* --- @key_fulltag@ --- *
+ *
+ * Arguments: @key *k@ = pointer to key
+ * @dstr *d@ = pointer to destination string
+ *
+ * Returns: ---
+ *
+ * Use: Emits the key's full tag, which has the form
+ * `ID:TYPE[:TAG]'. This is used in the textual file format,
+ * and to identify passphrases for locked keys.
+ */
+
+void key_fulltag(key *k, dstr *d)
+{
+ dstr_putf(d, "%08lx:%s", (unsigned long)k->id, k->type);
+ if (k->tag)
+ dstr_putf(d, ":%s", k->tag);
+}
+
+/*----- That's all, folks -------------------------------------------------*/