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 struct pdu *pdu) 63 { 64 int i; 65 char *keys_data, *name, *pair, *value; 66 size_t pair_len; 67 68 if (pdu->pdu_data_len == 0) 69 return; 70 71 if (pdu->pdu_data[pdu->pdu_data_len - 1] != '\0') 72 log_errx(1, "protocol error: key not NULL-terminated\n"); 73 74 keys_data = malloc(pdu->pdu_data_len); 75 if (keys_data == NULL) 76 log_err(1, "malloc"); 77 memcpy(keys_data, pdu->pdu_data, pdu->pdu_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 + pdu->pdu_data_len) 100 break; 101 assert(pair < keys_data + pdu->pdu_data_len); 102 } 103 free(keys_data); 104 } 105 106 void 107 keys_save(struct keys *keys, struct pdu *pdu) 108 { 109 char *data; 110 size_t len; 111 int i; 112 113 /* 114 * XXX: Not particularly efficient. 115 */ 116 len = 0; 117 for (i = 0; i < KEYS_MAX; i++) { 118 if (keys->keys_names[i] == NULL) 119 break; 120 /* 121 * +1 for '=', +1 for '\0'. 122 */ 123 len += strlen(keys->keys_names[i]) + 124 strlen(keys->keys_values[i]) + 2; 125 } 126 127 if (len == 0) 128 return; 129 130 data = malloc(len); 131 if (data == NULL) 132 log_err(1, "malloc"); 133 134 pdu->pdu_data = data; 135 pdu->pdu_data_len = len; 136 137 for (i = 0; i < KEYS_MAX; i++) { 138 if (keys->keys_names[i] == NULL) 139 break; 140 data += sprintf(data, "%s=%s", 141 keys->keys_names[i], keys->keys_values[i]); 142 data += 1; /* for '\0'. */ 143 } 144 } 145 146 const char * 147 keys_find(struct keys *keys, const char *name) 148 { 149 int i; 150 151 /* 152 * Note that we don't handle duplicated key names here, 153 * as they are not supposed to happen in requests, and if they do, 154 * it's an initiator error. 155 */ 156 for (i = 0; i < KEYS_MAX; i++) { 157 if (keys->keys_names[i] == NULL) 158 return (NULL); 159 if (strcmp(keys->keys_names[i], name) == 0) 160 return (keys->keys_values[i]); 161 } 162 return (NULL); 163 } 164 165 void 166 keys_add(struct keys *keys, const char *name, const char *value) 167 { 168 int i; 169 170 log_debugx("key to send: \"%s=%s\"", name, value); 171 172 /* 173 * Note that we don't check for duplicates here, as they are perfectly 174 * fine in responses, e.g. the "TargetName" keys in discovery sesion 175 * response. 176 */ 177 for (i = 0; i < KEYS_MAX; i++) { 178 if (keys->keys_names[i] == NULL) { 179 keys->keys_names[i] = checked_strdup(name); 180 keys->keys_values[i] = checked_strdup(value); 181 return; 182 } 183 } 184 log_errx(1, "too many keys"); 185 } 186 187 void 188 keys_add_int(struct keys *keys, const char *name, int value) 189 { 190 char *str; 191 int ret; 192 193 ret = asprintf(&str, "%d", value); 194 if (ret <= 0) 195 log_err(1, "asprintf"); 196 197 keys_add(keys, name, str); 198 free(str); 199 } 200