1*839d0755SJohn Baldwin /*-
2*839d0755SJohn Baldwin * SPDX-License-Identifier: BSD-2-Clause
3*839d0755SJohn Baldwin *
4*839d0755SJohn Baldwin * Copyright (c) 2014 Alexander Motin <mav@FreeBSD.org>
5*839d0755SJohn Baldwin * All rights reserved.
6*839d0755SJohn Baldwin *
7*839d0755SJohn Baldwin * Redistribution and use in source and binary forms, with or without
8*839d0755SJohn Baldwin * modification, are permitted provided that the following conditions
9*839d0755SJohn Baldwin * are met:
10*839d0755SJohn Baldwin * 1. Redistributions of source code must retain the above copyright
11*839d0755SJohn Baldwin * notice, this list of conditions and the following disclaimer.
12*839d0755SJohn Baldwin * 2. Redistributions in binary form must reproduce the above copyright
13*839d0755SJohn Baldwin * notice, this list of conditions and the following disclaimer in the
14*839d0755SJohn Baldwin * documentation and/or other materials provided with the distribution.
15*839d0755SJohn Baldwin *
16*839d0755SJohn Baldwin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*839d0755SJohn Baldwin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*839d0755SJohn Baldwin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*839d0755SJohn Baldwin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*839d0755SJohn Baldwin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*839d0755SJohn Baldwin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*839d0755SJohn Baldwin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*839d0755SJohn Baldwin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*839d0755SJohn Baldwin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*839d0755SJohn Baldwin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*839d0755SJohn Baldwin * SUCH DAMAGE.
27*839d0755SJohn Baldwin *
28*839d0755SJohn Baldwin */
29*839d0755SJohn Baldwin
30*839d0755SJohn Baldwin #include <sys/types.h>
31*839d0755SJohn Baldwin #include <sys/time.h>
32*839d0755SJohn Baldwin #include <sys/socket.h>
33*839d0755SJohn Baldwin #include <sys/wait.h>
34*839d0755SJohn Baldwin #include <sys/endian.h>
35*839d0755SJohn Baldwin #include <netinet/in.h>
36*839d0755SJohn Baldwin #include <arpa/inet.h>
37*839d0755SJohn Baldwin #include <netdb.h>
38*839d0755SJohn Baldwin #include <stdbool.h>
39*839d0755SJohn Baldwin #include <stdlib.h>
40*839d0755SJohn Baldwin #include <string.h>
41*839d0755SJohn Baldwin #include <unistd.h>
42*839d0755SJohn Baldwin
43*839d0755SJohn Baldwin #include "ctld.h"
44*839d0755SJohn Baldwin #include "isns.h"
45*839d0755SJohn Baldwin
46*839d0755SJohn Baldwin struct isns_req *
isns_req_alloc(void)47*839d0755SJohn Baldwin isns_req_alloc(void)
48*839d0755SJohn Baldwin {
49*839d0755SJohn Baldwin struct isns_req *req;
50*839d0755SJohn Baldwin
51*839d0755SJohn Baldwin req = reinterpret_cast<struct isns_req *>(calloc(1, sizeof(struct isns_req)));
52*839d0755SJohn Baldwin if (req == NULL) {
53*839d0755SJohn Baldwin log_err(1, "calloc");
54*839d0755SJohn Baldwin return (NULL);
55*839d0755SJohn Baldwin }
56*839d0755SJohn Baldwin req->ir_buflen = sizeof(struct isns_hdr);
57*839d0755SJohn Baldwin req->ir_usedlen = 0;
58*839d0755SJohn Baldwin req->ir_buf = reinterpret_cast<uint8_t *>(calloc(1, req->ir_buflen));
59*839d0755SJohn Baldwin if (req->ir_buf == NULL) {
60*839d0755SJohn Baldwin free(req);
61*839d0755SJohn Baldwin log_err(1, "calloc");
62*839d0755SJohn Baldwin return (NULL);
63*839d0755SJohn Baldwin }
64*839d0755SJohn Baldwin return (req);
65*839d0755SJohn Baldwin }
66*839d0755SJohn Baldwin
67*839d0755SJohn Baldwin struct isns_req *
isns_req_create(uint16_t func,uint16_t flags)68*839d0755SJohn Baldwin isns_req_create(uint16_t func, uint16_t flags)
69*839d0755SJohn Baldwin {
70*839d0755SJohn Baldwin struct isns_req *req;
71*839d0755SJohn Baldwin struct isns_hdr *hdr;
72*839d0755SJohn Baldwin
73*839d0755SJohn Baldwin req = isns_req_alloc();
74*839d0755SJohn Baldwin req->ir_usedlen = sizeof(struct isns_hdr);
75*839d0755SJohn Baldwin hdr = (struct isns_hdr *)req->ir_buf;
76*839d0755SJohn Baldwin be16enc(hdr->ih_version, ISNS_VERSION);
77*839d0755SJohn Baldwin be16enc(hdr->ih_function, func);
78*839d0755SJohn Baldwin be16enc(hdr->ih_flags, flags);
79*839d0755SJohn Baldwin return (req);
80*839d0755SJohn Baldwin }
81*839d0755SJohn Baldwin
82*839d0755SJohn Baldwin void
isns_req_free(struct isns_req * req)83*839d0755SJohn Baldwin isns_req_free(struct isns_req *req)
84*839d0755SJohn Baldwin {
85*839d0755SJohn Baldwin
86*839d0755SJohn Baldwin free(req->ir_buf);
87*839d0755SJohn Baldwin free(req);
88*839d0755SJohn Baldwin }
89*839d0755SJohn Baldwin
90*839d0755SJohn Baldwin static int
isns_req_getspace(struct isns_req * req,uint32_t len)91*839d0755SJohn Baldwin isns_req_getspace(struct isns_req *req, uint32_t len)
92*839d0755SJohn Baldwin {
93*839d0755SJohn Baldwin void *newbuf;
94*839d0755SJohn Baldwin int newlen;
95*839d0755SJohn Baldwin
96*839d0755SJohn Baldwin if (req->ir_usedlen + len <= req->ir_buflen)
97*839d0755SJohn Baldwin return (0);
98*839d0755SJohn Baldwin newlen = 1 << flsl(req->ir_usedlen + len);
99*839d0755SJohn Baldwin newbuf = realloc(req->ir_buf, newlen);
100*839d0755SJohn Baldwin if (newbuf == NULL) {
101*839d0755SJohn Baldwin log_err(1, "realloc");
102*839d0755SJohn Baldwin return (1);
103*839d0755SJohn Baldwin }
104*839d0755SJohn Baldwin req->ir_buf = reinterpret_cast<uint8_t *>(newbuf);
105*839d0755SJohn Baldwin req->ir_buflen = newlen;
106*839d0755SJohn Baldwin return (0);
107*839d0755SJohn Baldwin }
108*839d0755SJohn Baldwin
109*839d0755SJohn Baldwin void
isns_req_add(struct isns_req * req,uint32_t tag,uint32_t len,const void * value)110*839d0755SJohn Baldwin isns_req_add(struct isns_req *req, uint32_t tag, uint32_t len,
111*839d0755SJohn Baldwin const void *value)
112*839d0755SJohn Baldwin {
113*839d0755SJohn Baldwin struct isns_tlv *tlv;
114*839d0755SJohn Baldwin uint32_t vlen;
115*839d0755SJohn Baldwin
116*839d0755SJohn Baldwin vlen = len + ((len & 3) ? (4 - (len & 3)) : 0);
117*839d0755SJohn Baldwin isns_req_getspace(req, sizeof(*tlv) + vlen);
118*839d0755SJohn Baldwin tlv = (struct isns_tlv *)&req->ir_buf[req->ir_usedlen];
119*839d0755SJohn Baldwin be32enc(tlv->it_tag, tag);
120*839d0755SJohn Baldwin be32enc(tlv->it_length, vlen);
121*839d0755SJohn Baldwin memcpy(tlv->it_value, value, len);
122*839d0755SJohn Baldwin if (vlen != len)
123*839d0755SJohn Baldwin memset(&tlv->it_value[len], 0, vlen - len);
124*839d0755SJohn Baldwin req->ir_usedlen += sizeof(*tlv) + vlen;
125*839d0755SJohn Baldwin }
126*839d0755SJohn Baldwin
127*839d0755SJohn Baldwin void
isns_req_add_delim(struct isns_req * req)128*839d0755SJohn Baldwin isns_req_add_delim(struct isns_req *req)
129*839d0755SJohn Baldwin {
130*839d0755SJohn Baldwin
131*839d0755SJohn Baldwin isns_req_add(req, 0, 0, NULL);
132*839d0755SJohn Baldwin }
133*839d0755SJohn Baldwin
134*839d0755SJohn Baldwin void
isns_req_add_str(struct isns_req * req,uint32_t tag,const char * value)135*839d0755SJohn Baldwin isns_req_add_str(struct isns_req *req, uint32_t tag, const char *value)
136*839d0755SJohn Baldwin {
137*839d0755SJohn Baldwin
138*839d0755SJohn Baldwin isns_req_add(req, tag, strlen(value) + 1, value);
139*839d0755SJohn Baldwin }
140*839d0755SJohn Baldwin
141*839d0755SJohn Baldwin void
isns_req_add_32(struct isns_req * req,uint32_t tag,uint32_t value)142*839d0755SJohn Baldwin isns_req_add_32(struct isns_req *req, uint32_t tag, uint32_t value)
143*839d0755SJohn Baldwin {
144*839d0755SJohn Baldwin uint32_t beval;
145*839d0755SJohn Baldwin
146*839d0755SJohn Baldwin be32enc(&beval, value);
147*839d0755SJohn Baldwin isns_req_add(req, tag, sizeof(value), &beval);
148*839d0755SJohn Baldwin }
149*839d0755SJohn Baldwin
150*839d0755SJohn Baldwin void
isns_req_add_addr(struct isns_req * req,uint32_t tag,struct addrinfo * ai)151*839d0755SJohn Baldwin isns_req_add_addr(struct isns_req *req, uint32_t tag, struct addrinfo *ai)
152*839d0755SJohn Baldwin {
153*839d0755SJohn Baldwin struct sockaddr_in *in4;
154*839d0755SJohn Baldwin struct sockaddr_in6 *in6;
155*839d0755SJohn Baldwin uint8_t buf[16];
156*839d0755SJohn Baldwin
157*839d0755SJohn Baldwin switch (ai->ai_addr->sa_family) {
158*839d0755SJohn Baldwin case AF_INET:
159*839d0755SJohn Baldwin in4 = (struct sockaddr_in *)(void *)ai->ai_addr;
160*839d0755SJohn Baldwin memset(buf, 0, 10);
161*839d0755SJohn Baldwin buf[10] = 0xff;
162*839d0755SJohn Baldwin buf[11] = 0xff;
163*839d0755SJohn Baldwin memcpy(&buf[12], &in4->sin_addr, sizeof(in4->sin_addr));
164*839d0755SJohn Baldwin isns_req_add(req, tag, sizeof(buf), buf);
165*839d0755SJohn Baldwin break;
166*839d0755SJohn Baldwin case AF_INET6:
167*839d0755SJohn Baldwin in6 = (struct sockaddr_in6 *)(void *)ai->ai_addr;
168*839d0755SJohn Baldwin isns_req_add(req, tag, sizeof(in6->sin6_addr), &in6->sin6_addr);
169*839d0755SJohn Baldwin break;
170*839d0755SJohn Baldwin default:
171*839d0755SJohn Baldwin log_errx(1, "Unsupported address family %d",
172*839d0755SJohn Baldwin ai->ai_addr->sa_family);
173*839d0755SJohn Baldwin }
174*839d0755SJohn Baldwin }
175*839d0755SJohn Baldwin
176*839d0755SJohn Baldwin void
isns_req_add_port(struct isns_req * req,uint32_t tag,struct addrinfo * ai)177*839d0755SJohn Baldwin isns_req_add_port(struct isns_req *req, uint32_t tag, struct addrinfo *ai)
178*839d0755SJohn Baldwin {
179*839d0755SJohn Baldwin struct sockaddr_in *in4;
180*839d0755SJohn Baldwin struct sockaddr_in6 *in6;
181*839d0755SJohn Baldwin uint32_t buf;
182*839d0755SJohn Baldwin
183*839d0755SJohn Baldwin switch (ai->ai_addr->sa_family) {
184*839d0755SJohn Baldwin case AF_INET:
185*839d0755SJohn Baldwin in4 = (struct sockaddr_in *)(void *)ai->ai_addr;
186*839d0755SJohn Baldwin be32enc(&buf, ntohs(in4->sin_port));
187*839d0755SJohn Baldwin isns_req_add(req, tag, sizeof(buf), &buf);
188*839d0755SJohn Baldwin break;
189*839d0755SJohn Baldwin case AF_INET6:
190*839d0755SJohn Baldwin in6 = (struct sockaddr_in6 *)(void *)ai->ai_addr;
191*839d0755SJohn Baldwin be32enc(&buf, ntohs(in6->sin6_port));
192*839d0755SJohn Baldwin isns_req_add(req, tag, sizeof(buf), &buf);
193*839d0755SJohn Baldwin break;
194*839d0755SJohn Baldwin default:
195*839d0755SJohn Baldwin log_errx(1, "Unsupported address family %d",
196*839d0755SJohn Baldwin ai->ai_addr->sa_family);
197*839d0755SJohn Baldwin }
198*839d0755SJohn Baldwin }
199*839d0755SJohn Baldwin
200*839d0755SJohn Baldwin int
isns_req_send(int s,struct isns_req * req)201*839d0755SJohn Baldwin isns_req_send(int s, struct isns_req *req)
202*839d0755SJohn Baldwin {
203*839d0755SJohn Baldwin struct isns_hdr *hdr;
204*839d0755SJohn Baldwin int res;
205*839d0755SJohn Baldwin
206*839d0755SJohn Baldwin hdr = (struct isns_hdr *)req->ir_buf;
207*839d0755SJohn Baldwin be16enc(hdr->ih_length, req->ir_usedlen - sizeof(*hdr));
208*839d0755SJohn Baldwin be16enc(hdr->ih_flags, be16dec(hdr->ih_flags) |
209*839d0755SJohn Baldwin ISNS_FLAG_LAST | ISNS_FLAG_FIRST);
210*839d0755SJohn Baldwin be16enc(hdr->ih_transaction, 0);
211*839d0755SJohn Baldwin be16enc(hdr->ih_sequence, 0);
212*839d0755SJohn Baldwin
213*839d0755SJohn Baldwin res = write(s, req->ir_buf, req->ir_usedlen);
214*839d0755SJohn Baldwin return ((res < 0) ? -1 : 0);
215*839d0755SJohn Baldwin }
216*839d0755SJohn Baldwin
217*839d0755SJohn Baldwin int
isns_req_receive(int s,struct isns_req * req)218*839d0755SJohn Baldwin isns_req_receive(int s, struct isns_req *req)
219*839d0755SJohn Baldwin {
220*839d0755SJohn Baldwin struct isns_hdr *hdr;
221*839d0755SJohn Baldwin ssize_t res, len;
222*839d0755SJohn Baldwin
223*839d0755SJohn Baldwin req->ir_usedlen = 0;
224*839d0755SJohn Baldwin isns_req_getspace(req, sizeof(*hdr));
225*839d0755SJohn Baldwin res = read(s, req->ir_buf, sizeof(*hdr));
226*839d0755SJohn Baldwin if (res < (ssize_t)sizeof(*hdr))
227*839d0755SJohn Baldwin return (-1);
228*839d0755SJohn Baldwin req->ir_usedlen = sizeof(*hdr);
229*839d0755SJohn Baldwin hdr = (struct isns_hdr *)req->ir_buf;
230*839d0755SJohn Baldwin if (be16dec(hdr->ih_version) != ISNS_VERSION)
231*839d0755SJohn Baldwin return (-1);
232*839d0755SJohn Baldwin if ((be16dec(hdr->ih_flags) & (ISNS_FLAG_LAST | ISNS_FLAG_FIRST)) !=
233*839d0755SJohn Baldwin (ISNS_FLAG_LAST | ISNS_FLAG_FIRST))
234*839d0755SJohn Baldwin return (-1);
235*839d0755SJohn Baldwin len = be16dec(hdr->ih_length);
236*839d0755SJohn Baldwin isns_req_getspace(req, len);
237*839d0755SJohn Baldwin res = read(s, &req->ir_buf[req->ir_usedlen], len);
238*839d0755SJohn Baldwin if (res < len)
239*839d0755SJohn Baldwin return (-1);
240*839d0755SJohn Baldwin req->ir_usedlen += len;
241*839d0755SJohn Baldwin return (0);
242*839d0755SJohn Baldwin }
243*839d0755SJohn Baldwin
244*839d0755SJohn Baldwin uint32_t
isns_req_get_status(struct isns_req * req)245*839d0755SJohn Baldwin isns_req_get_status(struct isns_req *req)
246*839d0755SJohn Baldwin {
247*839d0755SJohn Baldwin
248*839d0755SJohn Baldwin if (req->ir_usedlen < sizeof(struct isns_hdr) + 4)
249*839d0755SJohn Baldwin return (-1);
250*839d0755SJohn Baldwin return (be32dec(&req->ir_buf[sizeof(struct isns_hdr)]));
251*839d0755SJohn Baldwin }
252