]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/ctl.c
fixedpoint: fix buffer overflow in fixed point computations
[thirdparty/lldpd.git] / src / ctl.c
CommitLineData
4b292b55 1/* -*- mode: c; c-file-style: "openbsd" -*- */
43c02e7b
VB
2/*
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
4 *
51434125 5 * Permission to use, copy, modify, and/or distribute this software for any
43c02e7b
VB
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
4b292b55 18#include <stdlib.h>
43c02e7b 19#include <unistd.h>
f6d20631 20#include <fcntl.h>
43c02e7b
VB
21#include <errno.h>
22#include <sys/types.h>
23#include <sys/socket.h>
24#include <sys/un.h>
4e5f34c5 25#include <string.h>
43c02e7b 26
4b292b55
VB
27#include "ctl.h"
28#include "marshal.h"
29#include "log.h"
30#include "compat/compat.h"
31
4b292b55
VB
32/**
33 * Create a new listening Unix socket for control protocol.
34 *
35 * @param name The name of the Unix socket.
36 * @return The socket when successful, -1 otherwise.
37 */
43c02e7b 38int
0262adbb 39ctl_create(const char *name)
43c02e7b
VB
40{
41 int s;
42 struct sockaddr_un su;
43 int rc;
44
6f8925be
VB
45 log_debug("control", "create control socket %s", name);
46
43c02e7b
VB
47 if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
48 return -1;
9475dd4c
VB
49 if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) {
50 close(s);
51 return -1;
52 }
43c02e7b 53 su.sun_family = AF_UNIX;
f373225a 54 strlcpy(su.sun_path, name, sizeof(su.sun_path));
43c02e7b
VB
55 if (bind(s, (struct sockaddr *)&su, sizeof(struct sockaddr_un)) == -1) {
56 rc = errno; close(s); errno = rc;
57 return -1;
58 }
6f8925be
VB
59
60 log_debug("control", "listen to control socket %s", name);
43c02e7b
VB
61 if (listen(s, 5) == -1) {
62 rc = errno; close(s); errno = rc;
6f8925be 63 log_debug("control", "cannot listen to control socket %s", name);
43c02e7b
VB
64 return -1;
65 }
43c02e7b
VB
66 return s;
67}
68
4b292b55
VB
69/**
70 * Connect to the control Unix socket.
71 *
72 * @param name The name of the Unix socket.
73 * @return The socket when successful, -1 otherwise.
74 */
43c02e7b 75int
0262adbb 76ctl_connect(const char *name)
43c02e7b
VB
77{
78 int s;
79 struct sockaddr_un su;
80 int rc;
81
6f8925be
VB
82 log_debug("control", "connect to control socket %s", name);
83
43c02e7b
VB
84 if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
85 return -1;
86 su.sun_family = AF_UNIX;
fdabbf8e 87 strlcpy(su.sun_path, name, sizeof(su.sun_path));
43c02e7b
VB
88 if (connect(s, (struct sockaddr *)&su, sizeof(struct sockaddr_un)) == -1) {
89 rc = errno;
6f8925be 90 log_warn("control", "unable to connect to socket %s", name);
676b4970 91 close(s);
43c02e7b
VB
92 errno = rc; return -1;
93 }
94 return s;
95}
96
4b292b55
VB
97/**
98 * Remove the control Unix socket.
99 *
100 * @param name The name of the Unix socket.
101 */
102void
0262adbb 103ctl_cleanup(const char *name)
4b292b55 104{
6f8925be 105 log_debug("control", "cleanup control socket");
4b292b55 106 if (unlink(name) == -1)
6f8925be 107 log_warn("control", "unable to unlink %s", name);
4b292b55
VB
108}
109
4b292b55
VB
110/**
111 * Serialize and "send" a structure through the control protocol.
112 *
113 * This function does not really send the message but outputs it to a buffer.
114 *
115 * @param output_buffer A pointer to a buffer to which the message will be
116 * appended. Can be @c NULL. In this case, the buffer will
117 * be allocated.
b1eceab6 118 * @param[in,out] output_len The length of the provided buffer. Will be updated
4b292b55
VB
119 * with the new length
120 * @param type The type of message we want to send.
121 * @param t The structure to be serialized and sent.
122 * @param mi The appropriate marshal structure for serialization.
123 * @return -1 in case of failure, 0 in case of success.
e0478a46
VB
124 *
125 * Make sure this function logic matches the server-side one: @c levent_ctl_recv().
4b292b55 126 */
43c02e7b 127int
4b292b55 128ctl_msg_send_unserialized(uint8_t **output_buffer, size_t *output_len,
f6d20631 129 enum hmsg_type type,
4b292b55 130 void *t, struct marshal_info *mi)
f6d20631 131{
281a5cd4 132 ssize_t len = 0, newlen;
4b292b55
VB
133 void *buffer = NULL;
134
6f8925be 135 log_debug("control", "send a message through control socket");
4b292b55
VB
136 if (t) {
137 len = marshal_serialize_(mi, t, &buffer, 0, NULL, 0);
138 if (len <= 0) {
6f8925be 139 log_warnx("control", "unable to serialize data");
43c02e7b
VB
140 return -1;
141 }
142 }
4b292b55
VB
143
144 newlen = len + sizeof(struct hmsg_header);
145
146 if (*output_buffer == NULL) {
147 *output_len = 0;
148 if ((*output_buffer = malloc(newlen)) == NULL) {
6f8925be 149 log_warn("control", "no memory available");
4b292b55
VB
150 free(buffer);
151 return -1;
152 }
153 } else {
154 void *new = realloc(*output_buffer, *output_len + newlen);
155 if (new == NULL) {
6f8925be 156 log_warn("control", "no memory available");
4b292b55
VB
157 free(buffer);
158 return -1;
159 }
160 *output_buffer = new;
f6d20631 161 }
b0cb07f7 162
38d74e8a
VB
163 struct hmsg_header hdr;
164 memset(&hdr, 0, sizeof(struct hmsg_header));
165 hdr.type = type;
166 hdr.len = len;
4b292b55
VB
167 memcpy(*output_buffer + *output_len, &hdr, sizeof(struct hmsg_header));
168 if (t)
169 memcpy(*output_buffer + *output_len + sizeof(struct hmsg_header), buffer, len);
170 *output_len += newlen;
171 free(buffer);
172 return 0;
173}
174
175/**
176 * "Receive" and unserialize a structure through the control protocol.
177 *
178 * Like @c ctl_msg_send_unserialized(), this function uses buffer to receive the
179 * incoming message.
180 *
b1eceab6 181 * @param[in,out] input_buffer The buffer with the incoming message. Will be
4b292b55
VB
182 * updated once the message has been unserialized to
183 * point to the remaining of the message or will be
184 * freed if all the buffer has been consumed. Can be
185 * @c NULL.
b1eceab6 186 * @param[in,out] input_len The length of the provided buffer. Will be updated
4b292b55
VB
187 * to the length of remaining data once the message
188 * has been unserialized.
189 * @param expected_type The expected message type.
b1eceab6 190 * @param[out] t Will contain a pointer to the unserialized structure.
4b292b55
VB
191 * Can be @c NULL if we don't want to store the
192 * answer.
193 * @param mi The appropriate marshal structure for unserialization.
194 *
195 * @return -1 in case of error, 0 in case of success and the number of bytes we
196 * request to complete unserialization.
4e90a9e0
VB
197 *
198 * When requesting a notification, the input buffer is left untouched if we
199 * don't get one and we fail silently.
4b292b55
VB
200 */
201size_t
202ctl_msg_recv_unserialized(uint8_t **input_buffer, size_t *input_len,
203 enum hmsg_type expected_type,
204 void **t, struct marshal_info *mi)
205{
072f743c 206 struct hmsg_header hdr;
4b292b55
VB
207 int rc = -1;
208
209 if (*input_buffer == NULL ||
210 *input_len < sizeof(struct hmsg_header)) {
211 /* Not enough data. */
212 return sizeof(struct hmsg_header) - *input_len;
f6d20631 213 }
6f8925be
VB
214
215 log_debug("control", "receive a message through control socket");
072f743c
VB
216 memcpy(&hdr, *input_buffer, sizeof(struct hmsg_header));
217 if (hdr.len > HMSG_MAX_SIZE) {
6f8925be 218 log_warnx("control", "message received is too large");
4b292b55
VB
219 /* We discard the whole buffer */
220 free(*input_buffer);
221 *input_buffer = NULL;
222 *input_len = 0;
223 return -1;
224 }
072f743c 225 if (*input_len < sizeof(struct hmsg_header) + hdr.len) {
4b292b55 226 /* Not enough data. */
072f743c 227 return sizeof(struct hmsg_header) + hdr.len - *input_len;
4b292b55 228 }
072f743c 229 if (hdr.type != expected_type) {
4e90a9e0 230 if (expected_type == NOTIFICATION) return -1;
6f8925be 231 log_warnx("control", "incorrect received message type (expected: %d, received: %d)",
072f743c 232 expected_type, hdr.type);
4b292b55
VB
233 goto end;
234 }
235
072f743c 236 if (t && !hdr.len) {
6f8925be 237 log_warnx("control", "no payload available in answer");
4b292b55 238 goto end;
f6d20631 239 }
4b292b55
VB
240 if (t) {
241 /* We have data to unserialize. */
242 if (marshal_unserialize_(mi, *input_buffer + sizeof(struct hmsg_header),
072f743c 243 hdr.len, t, NULL, 0, 0) <= 0) {
6f8925be 244 log_warnx("control", "unable to deserialize received data");
4b292b55
VB
245 goto end;
246 }
f6d20631 247 }
43c02e7b 248
4b292b55
VB
249 rc = 0;
250end:
251 /* Discard input buffer */
072f743c 252 *input_len -= sizeof(struct hmsg_header) + hdr.len;
4b292b55
VB
253 if (*input_len == 0) {
254 free(*input_buffer);
255 *input_buffer = NULL;
256 } else
0f957f3a 257 memmove(*input_buffer,
072f743c 258 *input_buffer + sizeof(struct hmsg_header) + hdr.len,
4b292b55
VB
259 *input_len);
260 return rc;
43c02e7b 261}