]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/ctld/keys.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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  * $FreeBSD$
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
39 struct keys *
40 keys_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
51 void
52 keys_delete(struct keys *keys)
53 {
54
55         free(keys->keys_data);
56         free(keys);
57 }
58
59 void
60 keys_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                 log_errx(1, "protocol error: empty data segment");
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
103 void
104 keys_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
143 const char *
144 keys_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
162 int
163 keys_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
182 void
183 keys_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
204 void
205 keys_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 }