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