]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - usr.sbin/iscsid/keys.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / usr.sbin / iscsid / keys.c
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$");
33
34 #include <assert.h>
35 #include <stdint.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include "iscsid.h"
41
42 struct keys *
43 keys_new(void)
44 {
45         struct keys *keys;
46
47         keys = calloc(sizeof(*keys), 1);
48         if (keys == NULL)
49                 log_err(1, "calloc");
50
51         return (keys);
52 }
53
54 void
55 keys_delete(struct keys *keys)
56 {
57
58         free(keys->keys_data);
59         free(keys);
60 }
61
62 void
63 keys_load(struct keys *keys, const struct pdu *pdu)
64 {
65         int i;
66         char *pair;
67         size_t pair_len;
68
69         if (pdu->pdu_data_len == 0)
70                 return;
71
72         if (pdu->pdu_data[pdu->pdu_data_len - 1] != '\0')
73                 log_errx(1, "protocol error: key not NULL-terminated\n");
74
75         assert(keys->keys_data == NULL);
76         keys->keys_data_len = pdu->pdu_data_len;
77         keys->keys_data = malloc(keys->keys_data_len);
78         if (keys->keys_data == NULL)
79                 log_err(1, "malloc");
80         memcpy(keys->keys_data, pdu->pdu_data, keys->keys_data_len);
81
82         /*
83          * XXX: Review this carefully.
84          */
85         pair = keys->keys_data;
86         for (i = 0;; i++) {
87                 if (i >= KEYS_MAX)
88                         log_errx(1, "too many keys received");
89
90                 pair_len = strlen(pair);
91
92                 keys->keys_values[i] = pair;
93                 keys->keys_names[i] = strsep(&keys->keys_values[i], "=");
94                 if (keys->keys_names[i] == NULL || keys->keys_values[i] == NULL)
95                         log_errx(1, "malformed keys");
96                 log_debugx("key received: \"%s=%s\"",
97                     keys->keys_names[i], keys->keys_values[i]);
98
99                 pair += pair_len + 1; /* +1 to skip the terminating '\0'. */
100                 if (pair == keys->keys_data + keys->keys_data_len)
101                         break;
102                 assert(pair < keys->keys_data + keys->keys_data_len);
103         }
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 int
166 keys_find_int(struct keys *keys, const char *name)
167 {
168         const char *str;
169         char *endptr;
170         int num;
171
172         str = keys_find(keys, name);
173         if (str == NULL)
174                 return (-1);
175
176         num = strtoul(str, &endptr, 10);
177         if (*endptr != '\0') {
178                 log_debugx("invalid numeric value \"%s\"", str);
179                 return (-1);
180         }
181
182         return (num);
183 }
184
185 void
186 keys_add(struct keys *keys, const char *name, const char *value)
187 {
188         int i;
189
190         log_debugx("key to send: \"%s=%s\"", name, value);
191
192         /*
193          * Note that we don't check for duplicates here, as they are perfectly
194          * fine in responses, e.g. the "TargetName" keys in discovery sesion
195          * response.
196          */
197         for (i = 0; i < KEYS_MAX; i++) {
198                 if (keys->keys_names[i] == NULL) {
199                         keys->keys_names[i] = checked_strdup(name);
200                         keys->keys_values[i] = checked_strdup(value);
201                         return;
202                 }
203         }
204         log_errx(1, "too many keys");
205 }
206
207 void
208 keys_add_int(struct keys *keys, const char *name, int value)
209 {
210         char *str;
211         int ret;
212
213         ret = asprintf(&str, "%d", value);
214         if (ret <= 0)
215                 log_err(1, "asprintf");
216
217         keys_add(keys, name, str);
218         free(str);
219 }