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