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