1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2012 The FreeBSD Foundation 5 * 6 * This software was developed by Edward Tomasz Napierala under sponsorship 7 * from the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <assert.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 36 #include "libiscsiutil.h" 37 38 struct keys * 39 keys_new(void) 40 { 41 struct keys *keys; 42 43 keys = calloc(1, sizeof(*keys)); 44 if (keys == NULL) 45 log_err(1, "calloc"); 46 47 return (keys); 48 } 49 50 void 51 keys_delete(struct keys *keys) 52 { 53 54 for (int i = 0; i < KEYS_MAX; i++) { 55 free(keys->keys_names[i]); 56 free(keys->keys_values[i]); 57 } 58 free(keys); 59 } 60 61 void 62 keys_load(struct keys *keys, const char *data, size_t len) 63 { 64 int i; 65 char *keys_data, *name, *pair, *value; 66 size_t pair_len; 67 68 if (len == 0) 69 return; 70 71 if (data[len - 1] != '\0') 72 log_errx(1, "protocol error: key not NULL-terminated\n"); 73 74 keys_data = malloc(len); 75 if (keys_data == NULL) 76 log_err(1, "malloc"); 77 memcpy(keys_data, data, len); 78 79 /* 80 * XXX: Review this carefully. 81 */ 82 pair = keys_data; 83 for (i = 0;; i++) { 84 if (i >= KEYS_MAX) 85 log_errx(1, "too many keys received"); 86 87 pair_len = strlen(pair); 88 89 value = pair; 90 name = strsep(&value, "="); 91 if (name == NULL || value == NULL) 92 log_errx(1, "malformed keys"); 93 keys->keys_names[i] = checked_strdup(name); 94 keys->keys_values[i] = checked_strdup(value); 95 log_debugx("key received: \"%s=%s\"", 96 keys->keys_names[i], keys->keys_values[i]); 97 98 pair += pair_len + 1; /* +1 to skip the terminating '\0'. */ 99 if (pair == keys_data + len) 100 break; 101 assert(pair < keys_data + len); 102 } 103 free(keys_data); 104 } 105 106 void 107 keys_save(struct keys *keys, char **datap, size_t *lenp) 108 { 109 FILE *fp; 110 char *data; 111 size_t len; 112 int i; 113 114 fp = open_memstream(&data, &len); 115 if (fp == NULL) 116 log_err(1, "open_memstream"); 117 for (i = 0; i < KEYS_MAX; i++) { 118 if (keys->keys_names[i] == NULL) 119 break; 120 121 fprintf(fp, "%s=%s", keys->keys_names[i], keys->keys_values[i]); 122 123 /* Append a '\0' after each key pair. */ 124 fputc('\0', fp); 125 } 126 if (fclose(fp) != 0) 127 log_err(1, "fclose"); 128 129 if (len == 0) { 130 free(data); 131 data = NULL; 132 } 133 134 *datap = data; 135 *lenp = len; 136 } 137 138 const char * 139 keys_find(struct keys *keys, const char *name) 140 { 141 int i; 142 143 /* 144 * Note that we don't handle duplicated key names here, 145 * as they are not supposed to happen in requests, and if they do, 146 * it's an initiator error. 147 */ 148 for (i = 0; i < KEYS_MAX; i++) { 149 if (keys->keys_names[i] == NULL) 150 return (NULL); 151 if (strcmp(keys->keys_names[i], name) == 0) 152 return (keys->keys_values[i]); 153 } 154 return (NULL); 155 } 156 157 void 158 keys_add(struct keys *keys, const char *name, const char *value) 159 { 160 int i; 161 162 log_debugx("key to send: \"%s=%s\"", name, value); 163 164 /* 165 * Note that we don't check for duplicates here, as they are perfectly 166 * fine in responses, e.g. the "TargetName" keys in discovery session 167 * response. 168 */ 169 for (i = 0; i < KEYS_MAX; i++) { 170 if (keys->keys_names[i] == NULL) { 171 keys->keys_names[i] = checked_strdup(name); 172 keys->keys_values[i] = checked_strdup(value); 173 return; 174 } 175 } 176 log_errx(1, "too many keys"); 177 } 178 179 void 180 keys_add_int(struct keys *keys, const char *name, int value) 181 { 182 char *str; 183 int ret; 184 185 ret = asprintf(&str, "%d", value); 186 if (ret <= 0) 187 log_err(1, "asprintf"); 188 189 keys_add(keys, name, str); 190 free(str); 191 } 192