Line data Source code
1 : /*
2 : SSSD
3 :
4 : SSS Client Responder, command parser
5 :
6 : Copyright (C) Simo Sorce <ssorce@redhat.com> 2008
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include <sys/types.h>
23 : #include <sys/socket.h>
24 : #include <string.h>
25 : #include <errno.h>
26 : #include <talloc.h>
27 :
28 : #include "util/util.h"
29 : #include "responder/common/responder_packet.h"
30 :
31 : #define SSSSRV_PACKET_MEM_SIZE 512
32 :
33 : struct sss_packet {
34 : size_t memsize;
35 :
36 : /* Structure of the buffer:
37 : * Bytes Content
38 : * ---------------------------------
39 : * 0-15 packet header
40 : * 0-3 packet length (uint32_t)
41 : * 4-7 command type (uint32_t)
42 : * 8-11 status (uint32_t)
43 : * 12-15 reserved
44 : * 16+ packet body */
45 : uint8_t *buffer;
46 :
47 : /* io pointer */
48 : size_t iop;
49 : };
50 :
51 : /* Offsets to data in sss_packet's buffer */
52 : #define SSS_PACKET_LEN_OFFSET 0
53 : #define SSS_PACKET_CMD_OFFSET sizeof(uint32_t)
54 : #define SSS_PACKET_ERR_OFFSET (2*(sizeof(uint32_t)))
55 : #define SSS_PACKET_BODY_OFFSET (4*(sizeof(uint32_t)))
56 :
57 : static void sss_packet_set_len(struct sss_packet *packet, uint32_t len);
58 : static void sss_packet_set_cmd(struct sss_packet *packet,
59 : enum sss_cli_command cmd);
60 : static uint32_t sss_packet_get_len(struct sss_packet *packet);
61 :
62 : /*
63 : * Allocate a new packet structure
64 : *
65 : * - if size is defined use it otherwise the default packet will be
66 : * SSSSRV_PACKET_MEM_SIZE bytes.
67 : */
68 82 : int sss_packet_new(TALLOC_CTX *mem_ctx, size_t size,
69 : enum sss_cli_command cmd,
70 : struct sss_packet **rpacket)
71 : {
72 : struct sss_packet *packet;
73 :
74 82 : packet = talloc(mem_ctx, struct sss_packet);
75 82 : if (!packet) return ENOMEM;
76 :
77 82 : if (size) {
78 6 : int n = (size + SSS_NSS_HEADER_SIZE) % SSSSRV_PACKET_MEM_SIZE;
79 6 : packet->memsize = (n + 1) * SSSSRV_PACKET_MEM_SIZE;
80 : } else {
81 76 : packet->memsize = SSSSRV_PACKET_MEM_SIZE;
82 : }
83 :
84 82 : packet->buffer = talloc_size(packet, packet->memsize);
85 82 : if (!packet->buffer) {
86 0 : talloc_free(packet);
87 0 : return ENOMEM;
88 : }
89 82 : memset(packet->buffer, 0, SSS_NSS_HEADER_SIZE);
90 :
91 82 : sss_packet_set_len(packet, size + SSS_NSS_HEADER_SIZE);
92 82 : sss_packet_set_cmd(packet, cmd);
93 :
94 82 : packet->iop = 0;
95 :
96 82 : *rpacket = packet;
97 :
98 82 : return EOK;
99 : }
100 :
101 : /* grows a packet size only in SSSSRV_PACKET_MEM_SIZE chunks */
102 108 : int sss_packet_grow(struct sss_packet *packet, size_t size)
103 : {
104 : size_t totlen, len;
105 : uint8_t *newmem;
106 : uint32_t packet_len;
107 :
108 108 : if (size == 0) {
109 0 : return EOK;
110 : }
111 :
112 108 : totlen = packet->memsize;
113 108 : packet_len = sss_packet_get_len(packet);
114 :
115 108 : len = packet_len + size;
116 :
117 : /* make sure we do not overflow */
118 108 : if (totlen < len) {
119 0 : int n = len / SSSSRV_PACKET_MEM_SIZE + 1;
120 0 : totlen += n * SSSSRV_PACKET_MEM_SIZE;
121 0 : if (totlen < len) {
122 0 : return EINVAL;
123 : }
124 : }
125 :
126 108 : if (totlen > packet->memsize) {
127 0 : newmem = talloc_realloc_size(packet, packet->buffer, totlen);
128 0 : if (!newmem) {
129 0 : return ENOMEM;
130 : }
131 :
132 0 : packet->memsize = totlen;
133 :
134 : /* re-set pointers if realloc had to move memory */
135 0 : if (newmem != packet->buffer) {
136 0 : packet->buffer = newmem;
137 : }
138 : }
139 :
140 108 : packet_len += size;
141 108 : sss_packet_set_len(packet, packet_len);
142 :
143 :
144 108 : return 0;
145 : }
146 :
147 : /* reclaim backet previously resrved space in the packet
148 : * usually done in functione recovering from not fatal erros */
149 0 : int sss_packet_shrink(struct sss_packet *packet, size_t size)
150 : {
151 : size_t newlen;
152 0 : size_t oldlen = sss_packet_get_len(packet);
153 :
154 0 : if (size > oldlen) return EINVAL;
155 :
156 0 : newlen = oldlen - size;
157 0 : if (newlen < SSS_NSS_HEADER_SIZE) return EINVAL;
158 :
159 0 : sss_packet_set_len(packet, newlen);
160 0 : return 0;
161 : }
162 :
163 5 : int sss_packet_set_size(struct sss_packet *packet, size_t size)
164 : {
165 : size_t newlen;
166 :
167 5 : newlen = SSS_NSS_HEADER_SIZE + size;
168 :
169 : /* make sure we do not overflow */
170 5 : if (packet->memsize < newlen) return EINVAL;
171 :
172 5 : sss_packet_set_len(packet, newlen);
173 :
174 5 : return 0;
175 : }
176 :
177 0 : int sss_packet_recv(struct sss_packet *packet, int fd)
178 : {
179 : size_t rb;
180 : size_t len;
181 : void *buf;
182 :
183 0 : buf = (uint8_t *)packet->buffer + packet->iop;
184 0 : if (packet->iop > 4) len = sss_packet_get_len(packet) - packet->iop;
185 0 : else len = packet->memsize - packet->iop;
186 :
187 : /* check for wrapping */
188 0 : if (len > packet->memsize) {
189 0 : return EINVAL;
190 : }
191 :
192 0 : errno = 0;
193 0 : rb = recv(fd, buf, len, 0);
194 :
195 0 : if (rb == -1) {
196 0 : if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
197 0 : return EAGAIN;
198 : } else {
199 0 : return errno;
200 : }
201 : }
202 :
203 0 : if (rb == 0) {
204 0 : return ENODATA;
205 : }
206 :
207 0 : if (sss_packet_get_len(packet) > packet->memsize) {
208 0 : return EINVAL;
209 : }
210 :
211 0 : packet->iop += rb;
212 0 : if (packet->iop < 4) {
213 0 : return EAGAIN;
214 : }
215 :
216 0 : if (packet->iop < sss_packet_get_len(packet)) {
217 0 : return EAGAIN;
218 : }
219 :
220 0 : return EOK;
221 : }
222 :
223 0 : int sss_packet_send(struct sss_packet *packet, int fd)
224 : {
225 : size_t rb;
226 : size_t len;
227 : void *buf;
228 :
229 0 : if (!packet) {
230 : /* No packet object to write to? */
231 0 : return EINVAL;
232 : }
233 :
234 0 : buf = packet->buffer + packet->iop;
235 0 : len = sss_packet_get_len(packet) - packet->iop;
236 :
237 0 : errno = 0;
238 0 : rb = send(fd, buf, len, 0);
239 :
240 0 : if (rb == -1) {
241 0 : if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
242 0 : return EAGAIN;
243 : } else {
244 0 : return errno;
245 : }
246 : }
247 :
248 0 : if (rb == 0) {
249 0 : return EIO;
250 : }
251 :
252 0 : packet->iop += rb;
253 :
254 0 : if (packet->iop < sss_packet_get_len(packet)) {
255 0 : return EAGAIN;
256 : }
257 :
258 0 : return EOK;
259 : }
260 :
261 0 : enum sss_cli_command sss_packet_get_cmd(struct sss_packet *packet)
262 : {
263 : uint32_t cmd;
264 :
265 0 : SAFEALIGN_COPY_UINT32(&cmd, packet->buffer + SSS_PACKET_CMD_OFFSET, NULL);
266 0 : return (enum sss_cli_command)cmd;
267 : }
268 :
269 82 : uint32_t sss_packet_get_status(struct sss_packet *packet)
270 : {
271 : uint32_t status;
272 :
273 82 : SAFEALIGN_COPY_UINT32(&status, packet->buffer + SSS_PACKET_ERR_OFFSET,
274 : NULL);
275 82 : return status;
276 : }
277 :
278 208 : void sss_packet_get_body(struct sss_packet *packet, uint8_t **body, size_t *blen)
279 : {
280 208 : *body = packet->buffer + SSS_PACKET_BODY_OFFSET;
281 208 : *blen = sss_packet_get_len(packet) - SSS_NSS_HEADER_SIZE;
282 208 : }
283 :
284 42 : void sss_packet_set_error(struct sss_packet *packet, int error)
285 : {
286 42 : SAFEALIGN_SETMEM_UINT32(packet->buffer + SSS_PACKET_ERR_OFFSET, error,
287 : NULL);
288 42 : }
289 :
290 195 : static void sss_packet_set_len(struct sss_packet *packet, uint32_t len)
291 : {
292 195 : SAFEALIGN_SETMEM_UINT32(packet->buffer + SSS_PACKET_LEN_OFFSET, len, NULL);
293 195 : }
294 :
295 82 : static void sss_packet_set_cmd(struct sss_packet *packet,
296 : enum sss_cli_command cmd)
297 : {
298 82 : SAFEALIGN_SETMEM_UINT32(packet->buffer + SSS_PACKET_CMD_OFFSET, cmd, NULL);
299 82 : }
300 :
301 316 : static uint32_t sss_packet_get_len(struct sss_packet *packet)
302 : {
303 : uint32_t len;
304 :
305 316 : SAFEALIGN_COPY_UINT32(&len, packet->buffer + SSS_PACKET_LEN_OFFSET, NULL);
306 316 : return len;
307 : }
|