163783933SJohn Baldwin /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
363783933SJohn Baldwin *
463783933SJohn Baldwin * Copyright (c) 2012 The FreeBSD Foundation
563783933SJohn Baldwin *
663783933SJohn Baldwin * This software was developed by Edward Tomasz Napierala under sponsorship
763783933SJohn Baldwin * from the FreeBSD Foundation.
863783933SJohn Baldwin *
963783933SJohn Baldwin * Redistribution and use in source and binary forms, with or without
1063783933SJohn Baldwin * modification, are permitted provided that the following conditions
1163783933SJohn Baldwin * are met:
1263783933SJohn Baldwin * 1. Redistributions of source code must retain the above copyright
1363783933SJohn Baldwin * notice, this list of conditions and the following disclaimer.
1463783933SJohn Baldwin * 2. Redistributions in binary form must reproduce the above copyright
1563783933SJohn Baldwin * notice, this list of conditions and the following disclaimer in the
1663783933SJohn Baldwin * documentation and/or other materials provided with the distribution.
1763783933SJohn Baldwin *
1863783933SJohn Baldwin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1963783933SJohn Baldwin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2063783933SJohn Baldwin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2163783933SJohn Baldwin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2263783933SJohn Baldwin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2363783933SJohn Baldwin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2463783933SJohn Baldwin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2563783933SJohn Baldwin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2663783933SJohn Baldwin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2763783933SJohn Baldwin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2863783933SJohn Baldwin * SUCH DAMAGE.
2963783933SJohn Baldwin */
3063783933SJohn Baldwin
3163783933SJohn Baldwin #include <assert.h>
3263783933SJohn Baldwin #include <stdio.h>
3363783933SJohn Baldwin #include <stdlib.h>
3463783933SJohn Baldwin #include <string.h>
3563783933SJohn Baldwin
3663783933SJohn Baldwin #include "libiscsiutil.h"
3763783933SJohn Baldwin
3863783933SJohn Baldwin struct keys *
keys_new(void)3963783933SJohn Baldwin keys_new(void)
4063783933SJohn Baldwin {
4163783933SJohn Baldwin struct keys *keys;
4263783933SJohn Baldwin
4363783933SJohn Baldwin keys = calloc(1, sizeof(*keys));
4463783933SJohn Baldwin if (keys == NULL)
4563783933SJohn Baldwin log_err(1, "calloc");
4663783933SJohn Baldwin
4763783933SJohn Baldwin return (keys);
4863783933SJohn Baldwin }
4963783933SJohn Baldwin
5063783933SJohn Baldwin void
keys_delete(struct keys * keys)5163783933SJohn Baldwin keys_delete(struct keys *keys)
5263783933SJohn Baldwin {
5363783933SJohn Baldwin
54fd99905bSJohn Baldwin for (int i = 0; i < KEYS_MAX; i++) {
55fd99905bSJohn Baldwin free(keys->keys_names[i]);
56fd99905bSJohn Baldwin free(keys->keys_values[i]);
57fd99905bSJohn Baldwin }
5863783933SJohn Baldwin free(keys);
5963783933SJohn Baldwin }
6063783933SJohn Baldwin
6163783933SJohn Baldwin void
keys_load(struct keys * keys,const char * data,size_t len)6225700db3SJohn Baldwin keys_load(struct keys *keys, const char *data, size_t len)
6363783933SJohn Baldwin {
6463783933SJohn Baldwin int i;
65fd99905bSJohn Baldwin char *keys_data, *name, *pair, *value;
6663783933SJohn Baldwin size_t pair_len;
6763783933SJohn Baldwin
6825700db3SJohn Baldwin if (len == 0)
6963783933SJohn Baldwin return;
7063783933SJohn Baldwin
7125700db3SJohn Baldwin if (data[len - 1] != '\0')
7263783933SJohn Baldwin log_errx(1, "protocol error: key not NULL-terminated\n");
7363783933SJohn Baldwin
7425700db3SJohn Baldwin keys_data = malloc(len);
75fd99905bSJohn Baldwin if (keys_data == NULL)
7663783933SJohn Baldwin log_err(1, "malloc");
7725700db3SJohn Baldwin memcpy(keys_data, data, len);
7863783933SJohn Baldwin
7963783933SJohn Baldwin /*
8063783933SJohn Baldwin * XXX: Review this carefully.
8163783933SJohn Baldwin */
82fd99905bSJohn Baldwin pair = keys_data;
8363783933SJohn Baldwin for (i = 0;; i++) {
8463783933SJohn Baldwin if (i >= KEYS_MAX)
8563783933SJohn Baldwin log_errx(1, "too many keys received");
8663783933SJohn Baldwin
8763783933SJohn Baldwin pair_len = strlen(pair);
8863783933SJohn Baldwin
89fd99905bSJohn Baldwin value = pair;
90fd99905bSJohn Baldwin name = strsep(&value, "=");
91fd99905bSJohn Baldwin if (name == NULL || value == NULL)
9263783933SJohn Baldwin log_errx(1, "malformed keys");
93fd99905bSJohn Baldwin keys->keys_names[i] = checked_strdup(name);
94fd99905bSJohn Baldwin keys->keys_values[i] = checked_strdup(value);
9563783933SJohn Baldwin log_debugx("key received: \"%s=%s\"",
9663783933SJohn Baldwin keys->keys_names[i], keys->keys_values[i]);
9763783933SJohn Baldwin
9863783933SJohn Baldwin pair += pair_len + 1; /* +1 to skip the terminating '\0'. */
9925700db3SJohn Baldwin if (pair == keys_data + len)
10063783933SJohn Baldwin break;
10125700db3SJohn Baldwin assert(pair < keys_data + len);
10263783933SJohn Baldwin }
103fd99905bSJohn Baldwin free(keys_data);
10463783933SJohn Baldwin }
10563783933SJohn Baldwin
10663783933SJohn Baldwin void
keys_save(struct keys * keys,char ** datap,size_t * lenp)10725700db3SJohn Baldwin keys_save(struct keys *keys, char **datap, size_t *lenp)
10863783933SJohn Baldwin {
1092ccb8fdeSJohn Baldwin FILE *fp;
11063783933SJohn Baldwin char *data;
11163783933SJohn Baldwin size_t len;
11263783933SJohn Baldwin int i;
11363783933SJohn Baldwin
1142ccb8fdeSJohn Baldwin fp = open_memstream(&data, &len);
1152ccb8fdeSJohn Baldwin if (fp == NULL)
1162ccb8fdeSJohn Baldwin log_err(1, "open_memstream");
11763783933SJohn Baldwin for (i = 0; i < KEYS_MAX; i++) {
11863783933SJohn Baldwin if (keys->keys_names[i] == NULL)
11963783933SJohn Baldwin break;
1202ccb8fdeSJohn Baldwin
1212ccb8fdeSJohn Baldwin fprintf(fp, "%s=%s", keys->keys_names[i], keys->keys_values[i]);
1222ccb8fdeSJohn Baldwin
1232ccb8fdeSJohn Baldwin /* Append a '\0' after each key pair. */
1242ccb8fdeSJohn Baldwin fputc('\0', fp);
12563783933SJohn Baldwin }
1262ccb8fdeSJohn Baldwin if (fclose(fp) != 0)
1272ccb8fdeSJohn Baldwin log_err(1, "fclose");
12863783933SJohn Baldwin
1292ccb8fdeSJohn Baldwin if (len == 0) {
1302ccb8fdeSJohn Baldwin free(data);
1312ccb8fdeSJohn Baldwin data = NULL;
1322ccb8fdeSJohn Baldwin }
13363783933SJohn Baldwin
13425700db3SJohn Baldwin *datap = data;
13525700db3SJohn Baldwin *lenp = len;
13663783933SJohn Baldwin }
13763783933SJohn Baldwin
13863783933SJohn Baldwin const char *
keys_find(struct keys * keys,const char * name)13963783933SJohn Baldwin keys_find(struct keys *keys, const char *name)
14063783933SJohn Baldwin {
14163783933SJohn Baldwin int i;
14263783933SJohn Baldwin
14363783933SJohn Baldwin /*
14463783933SJohn Baldwin * Note that we don't handle duplicated key names here,
14563783933SJohn Baldwin * as they are not supposed to happen in requests, and if they do,
14663783933SJohn Baldwin * it's an initiator error.
14763783933SJohn Baldwin */
14863783933SJohn Baldwin for (i = 0; i < KEYS_MAX; i++) {
14963783933SJohn Baldwin if (keys->keys_names[i] == NULL)
15063783933SJohn Baldwin return (NULL);
15163783933SJohn Baldwin if (strcmp(keys->keys_names[i], name) == 0)
15263783933SJohn Baldwin return (keys->keys_values[i]);
15363783933SJohn Baldwin }
15463783933SJohn Baldwin return (NULL);
15563783933SJohn Baldwin }
15663783933SJohn Baldwin
15763783933SJohn Baldwin void
keys_add(struct keys * keys,const char * name,const char * value)15863783933SJohn Baldwin keys_add(struct keys *keys, const char *name, const char *value)
15963783933SJohn Baldwin {
16063783933SJohn Baldwin int i;
16163783933SJohn Baldwin
16263783933SJohn Baldwin log_debugx("key to send: \"%s=%s\"", name, value);
16363783933SJohn Baldwin
16463783933SJohn Baldwin /*
16563783933SJohn Baldwin * Note that we don't check for duplicates here, as they are perfectly
16629b36af9SGordon Bergling * fine in responses, e.g. the "TargetName" keys in discovery session
16763783933SJohn Baldwin * response.
16863783933SJohn Baldwin */
16963783933SJohn Baldwin for (i = 0; i < KEYS_MAX; i++) {
17063783933SJohn Baldwin if (keys->keys_names[i] == NULL) {
17163783933SJohn Baldwin keys->keys_names[i] = checked_strdup(name);
17263783933SJohn Baldwin keys->keys_values[i] = checked_strdup(value);
17363783933SJohn Baldwin return;
17463783933SJohn Baldwin }
17563783933SJohn Baldwin }
17663783933SJohn Baldwin log_errx(1, "too many keys");
17763783933SJohn Baldwin }
17863783933SJohn Baldwin
17963783933SJohn Baldwin void
keys_add_int(struct keys * keys,const char * name,int value)18063783933SJohn Baldwin keys_add_int(struct keys *keys, const char *name, int value)
18163783933SJohn Baldwin {
18263783933SJohn Baldwin char *str;
18363783933SJohn Baldwin int ret;
18463783933SJohn Baldwin
18563783933SJohn Baldwin ret = asprintf(&str, "%d", value);
18663783933SJohn Baldwin if (ret <= 0)
18763783933SJohn Baldwin log_err(1, "asprintf");
18863783933SJohn Baldwin
18963783933SJohn Baldwin keys_add(keys, name, str);
19063783933SJohn Baldwin free(str);
19163783933SJohn Baldwin }
192