]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - usr.sbin/ctld/keys.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / usr.sbin / ctld / 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 #include "ctld.h"
40
41 struct keys *
42 keys_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
53 void
54 keys_delete(struct keys *keys)
55 {
56
57         free(keys->keys_data);
58         free(keys);
59 }
60
61 void
62 keys_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
105 void
106 keys_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
145 const char *
146 keys_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
164 int
165 keys_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
184 void
185 keys_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
206 void
207 keys_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 }