1 /* -*- mode: c; c-file-style: "openbsd" -*- */
2 /*
3  * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
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 
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <fcntl.h>
21 #include <errno.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <sys/un.h>
25 #include <string.h>
26 
27 #include "ctl.h"
28 #include "marshal.h"
29 #include "log.h"
30 #include "compat/compat.h"
31 
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  */
38 int
ctl_create(const char * name)39 ctl_create(const char *name)
40 {
41 	int s;
42 	struct sockaddr_un su;
43 	int rc;
44 
45 	log_debug("control", "create control socket %s", name);
46 
47 	if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
48 		return -1;
49 	if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) {
50 		close(s);
51 		return -1;
52 	}
53 	su.sun_family = AF_UNIX;
54 	strlcpy(su.sun_path, name, sizeof(su.sun_path));
55 	if (bind(s, (struct sockaddr *)&su, sizeof(struct sockaddr_un)) == -1) {
56 		rc = errno; close(s); errno = rc;
57 		return -1;
58 	}
59 
60 	log_debug("control", "listen to control socket %s", name);
61 	if (listen(s, 5) == -1) {
62 		rc = errno; close(s); errno = rc;
63 		log_debug("control", "cannot listen to control socket %s", name);
64 		return -1;
65 	}
66 	return s;
67 }
68 
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  */
75 int
ctl_connect(const char * name)76 ctl_connect(const char *name)
77 {
78 	int s;
79 	struct sockaddr_un su;
80 	int rc;
81 
82 	log_debug("control", "connect to control socket %s", name);
83 
84 	if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
85 		return -1;
86 	su.sun_family = AF_UNIX;
87 	strlcpy(su.sun_path, name, sizeof(su.sun_path));
88 	if (connect(s, (struct sockaddr *)&su, sizeof(struct sockaddr_un)) == -1) {
89 		rc = errno;
90 		log_warn("control", "unable to connect to socket %s", name);
91 		close(s);
92 		errno = rc; return -1;
93 	}
94 	return s;
95 }
96 
97 /**
98  * Remove the control Unix socket.
99  *
100  * @param name The name of the Unix socket.
101  */
102 void
ctl_cleanup(const char * name)103 ctl_cleanup(const char *name)
104 {
105 	log_debug("control", "cleanup control socket");
106 	if (unlink(name) == -1)
107 		log_warn("control", "unable to unlink %s", name);
108 }
109 
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.
118  * @param[in,out] output_len The length of the provided buffer. Will be updated
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.
124  *
125  * Make sure this function logic matches the server-side one: @c levent_ctl_recv().
126  */
127 int
ctl_msg_send_unserialized(uint8_t ** output_buffer,size_t * output_len,enum hmsg_type type,void * t,struct marshal_info * mi)128 ctl_msg_send_unserialized(uint8_t **output_buffer, size_t *output_len,
129     enum hmsg_type type,
130     void *t, struct marshal_info *mi)
131 {
132 	ssize_t len = 0, newlen;
133 	void *buffer = NULL;
134 
135 	log_debug("control", "send a message through control socket");
136 	if (t) {
137 		len = marshal_serialize_(mi, t, &buffer, 0, NULL, 0);
138 		if (len <= 0) {
139 			log_warnx("control", "unable to serialize data");
140 			return -1;
141 		}
142 	}
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) {
149 			log_warn("control", "no memory available");
150 			free(buffer);
151 			return -1;
152 		}
153 	} else {
154 		void *new = realloc(*output_buffer, *output_len + newlen);
155 		if (new == NULL) {
156 			log_warn("control", "no memory available");
157 			free(buffer);
158 			return -1;
159 		}
160 		*output_buffer = new;
161 	}
162 
163 	struct hmsg_header hdr;
164 	memset(&hdr, 0, sizeof(struct hmsg_header));
165 	hdr.type = type;
166 	hdr.len = len;
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  *
181  * @param[in,out] input_buffer The buffer with the incoming message. Will be
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.
186  * @param[in,out] input_len    The length of the provided buffer. Will be updated
187  *                             to the length of remaining data once the message
188  *                             has been unserialized.
189  * @param expected_type        The expected message type.
190  * @param[out] t               Will contain a pointer to the unserialized structure.
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.
197  *
198  * When requesting a notification, the input buffer is left untouched if we
199  * don't get one and we fail silently.
200  */
201 size_t
ctl_msg_recv_unserialized(uint8_t ** input_buffer,size_t * input_len,enum hmsg_type expected_type,void ** t,struct marshal_info * mi)202 ctl_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 {
206 	struct hmsg_header hdr;
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;
213 	}
214 
215 	log_debug("control", "receive a message through control socket");
216 	memcpy(&hdr, *input_buffer, sizeof(struct hmsg_header));
217 	if (hdr.len > HMSG_MAX_SIZE) {
218 		log_warnx("control", "message received is too large");
219 		/* We discard the whole buffer */
220 		free(*input_buffer);
221 		*input_buffer = NULL;
222 		*input_len = 0;
223 		return -1;
224 	}
225 	if (*input_len < sizeof(struct hmsg_header) + hdr.len) {
226 		/* Not enough data. */
227 		return sizeof(struct hmsg_header) + hdr.len - *input_len;
228 	}
229 	if (hdr.type != expected_type) {
230 		if (expected_type == NOTIFICATION) return -1;
231 		log_warnx("control", "incorrect received message type (expected: %d, received: %d)",
232 		    expected_type, hdr.type);
233 		goto end;
234 	}
235 
236 	if (t && !hdr.len) {
237 		log_warnx("control", "no payload available in answer");
238 		goto end;
239 	}
240 	if (t) {
241 		/* We have data to unserialize. */
242 		if (marshal_unserialize_(mi, *input_buffer + sizeof(struct hmsg_header),
243 			hdr.len, t, NULL, 0, 0) <= 0) {
244 			log_warnx("control", "unable to deserialize received data");
245 			goto end;
246 		}
247 	}
248 
249 	rc = 0;
250 end:
251 	/* Discard input buffer */
252 	*input_len -= sizeof(struct hmsg_header) + hdr.len;
253 	if (*input_len == 0) {
254 		free(*input_buffer);
255 		*input_buffer = NULL;
256 	} else
257 		memmove(*input_buffer,
258 		    *input_buffer + sizeof(struct hmsg_header) + hdr.len,
259 		    *input_len);
260 	return rc;
261 }
262