keys.c revision 263733
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 * $FreeBSD: stable/10/usr.sbin/ctld/keys.c 263733 2014-03-25 12:33:16Z trasz $ 30 */ 31 32#include <assert.h> 33#include <stdint.h> 34#include <stdio.h> 35#include <stdlib.h> 36#include <string.h> 37#include "ctld.h" 38 39struct keys * 40keys_new(void) 41{ 42 struct keys *keys; 43 44 keys = calloc(sizeof(*keys), 1); 45 if (keys == NULL) 46 log_err(1, "calloc"); 47 48 return (keys); 49} 50 51void 52keys_delete(struct keys *keys) 53{ 54 55 free(keys->keys_data); 56 free(keys); 57} 58 59void 60keys_load(struct keys *keys, const struct pdu *pdu) 61{ 62 int i; 63 char *pair; 64 size_t pair_len; 65 66 if (pdu->pdu_data_len == 0) 67 return; 68 69 if (pdu->pdu_data[pdu->pdu_data_len - 1] != '\0') 70 log_errx(1, "protocol error: key not NULL-terminated\n"); 71 72 assert(keys->keys_data == NULL); 73 keys->keys_data_len = pdu->pdu_data_len; 74 keys->keys_data = malloc(keys->keys_data_len); 75 if (keys->keys_data == NULL) 76 log_err(1, "malloc"); 77 memcpy(keys->keys_data, pdu->pdu_data, keys->keys_data_len); 78 79 /* 80 * XXX: Review this carefully. 81 */ 82 pair = keys->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 keys->keys_values[i] = pair; 90 keys->keys_names[i] = strsep(&keys->keys_values[i], "="); 91 if (keys->keys_names[i] == NULL || keys->keys_values[i] == NULL) 92 log_errx(1, "malformed keys"); 93 log_debugx("key received: \"%s=%s\"", 94 keys->keys_names[i], keys->keys_values[i]); 95 96 pair += pair_len + 1; /* +1 to skip the terminating '\0'. */ 97 if (pair == keys->keys_data + keys->keys_data_len) 98 break; 99 assert(pair < keys->keys_data + keys->keys_data_len); 100 } 101} 102 103void 104keys_save(struct keys *keys, struct pdu *pdu) 105{ 106 char *data; 107 size_t len; 108 int i; 109 110 /* 111 * XXX: Not particularly efficient. 112 */ 113 len = 0; 114 for (i = 0; i < KEYS_MAX; i++) { 115 if (keys->keys_names[i] == NULL) 116 break; 117 /* 118 * +1 for '=', +1 for '\0'. 119 */ 120 len += strlen(keys->keys_names[i]) + 121 strlen(keys->keys_values[i]) + 2; 122 } 123 124 if (len == 0) 125 return; 126 127 data = malloc(len); 128 if (data == NULL) 129 log_err(1, "malloc"); 130 131 pdu->pdu_data = data; 132 pdu->pdu_data_len = len; 133 134 for (i = 0; i < KEYS_MAX; i++) { 135 if (keys->keys_names[i] == NULL) 136 break; 137 data += sprintf(data, "%s=%s", 138 keys->keys_names[i], keys->keys_values[i]); 139 data += 1; /* for '\0'. */ 140 } 141} 142 143const char * 144keys_find(struct keys *keys, const char *name) 145{ 146 int i; 147 148 /* 149 * Note that we don't handle duplicated key names here, 150 * as they are not supposed to happen in requests, and if they do, 151 * it's an initiator error. 152 */ 153 for (i = 0; i < KEYS_MAX; i++) { 154 if (keys->keys_names[i] == NULL) 155 return (NULL); 156 if (strcmp(keys->keys_names[i], name) == 0) 157 return (keys->keys_values[i]); 158 } 159 return (NULL); 160} 161 162int 163keys_find_int(struct keys *keys, const char *name) 164{ 165 const char *str; 166 char *endptr; 167 int num; 168 169 str = keys_find(keys, name); 170 if (str == NULL) 171 return (-1); 172 173 num = strtoul(str, &endptr, 10); 174 if (*endptr != '\0') { 175 log_debugx("invalid numeric value \"%s\"", str); 176 return (-1); 177 } 178 179 return (num); 180} 181 182void 183keys_add(struct keys *keys, const char *name, const char *value) 184{ 185 int i; 186 187 log_debugx("key to send: \"%s=%s\"", name, value); 188 189 /* 190 * Note that we don't check for duplicates here, as they are perfectly 191 * fine in responses, e.g. the "TargetName" keys in discovery sesion 192 * response. 193 */ 194 for (i = 0; i < KEYS_MAX; i++) { 195 if (keys->keys_names[i] == NULL) { 196 keys->keys_names[i] = checked_strdup(name); 197 keys->keys_values[i] = checked_strdup(value); 198 return; 199 } 200 } 201 log_errx(1, "too many keys"); 202} 203 204void 205keys_add_int(struct keys *keys, const char *name, int value) 206{ 207 char *str; 208 int ret; 209 210 ret = asprintf(&str, "%d", value); 211 if (ret <= 0) 212 log_err(1, "asprintf"); 213 214 keys_add(keys, name, str); 215 free(str); 216} 217