Branch data 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 : : #include "util/util.h"
28 : : #include "responder/common/responder_packet.h"
29 : :
30 : : #define SSSSRV_PACKET_MEM_SIZE 512
31 : :
32 : : struct sss_packet {
33 : : size_t memsize;
34 : : uint8_t *buffer;
35 : :
36 : : /* header */
37 : : uint32_t *len;
38 : : uint32_t *cmd;
39 : : uint32_t *status;
40 : : uint32_t *reserved;
41 : :
42 : : uint8_t *body;
43 : :
44 : : /* io pointer */
45 : : size_t iop;
46 : : };
47 : :
48 : : /*
49 : : * Allocate a new packet structure
50 : : *
51 : : * - if size is defined use it otherwise the default packet will be
52 : : * SSSSRV_PACKET_MEM_SIZE bytes.
53 : : */
54 : 0 : int sss_packet_new(TALLOC_CTX *mem_ctx, size_t size,
55 : : enum sss_cli_command cmd,
56 : : struct sss_packet **rpacket)
57 : : {
58 : : struct sss_packet *packet;
59 : :
60 : 0 : packet = talloc(mem_ctx, struct sss_packet);
61 [ # # ]: 0 : if (!packet) return ENOMEM;
62 : :
63 [ # # ]: 0 : if (size) {
64 : 0 : int n = (size + SSS_NSS_HEADER_SIZE) % SSSSRV_PACKET_MEM_SIZE;
65 : 0 : packet->memsize = (n + 1) * SSSSRV_PACKET_MEM_SIZE;
66 : : } else {
67 : 0 : packet->memsize = SSSSRV_PACKET_MEM_SIZE;
68 : : }
69 : :
70 : 0 : packet->buffer = talloc_size(packet, packet->memsize);
71 [ # # ]: 0 : if (!packet->buffer) {
72 : 0 : talloc_free(packet);
73 : 0 : return ENOMEM;
74 : : }
75 : 0 : memset(packet->buffer, 0, SSS_NSS_HEADER_SIZE);
76 : :
77 : 0 : packet->len = &((uint32_t *)packet->buffer)[0];
78 : 0 : packet->cmd = &((uint32_t *)packet->buffer)[1];
79 : 0 : packet->status = &((uint32_t *)packet->buffer)[2];
80 : 0 : packet->reserved = &((uint32_t *)packet->buffer)[3];
81 : 0 : packet->body = (uint8_t *)&((uint32_t *)packet->buffer)[4];
82 : :
83 : 0 : *(packet->len) = size + SSS_NSS_HEADER_SIZE;
84 : 0 : *(packet->cmd) = cmd;
85 : :
86 : 0 : packet->iop = 0;
87 : :
88 : 0 : *rpacket = packet;
89 : :
90 : 0 : return EOK;
91 : : }
92 : :
93 : : /* grows a packet size only in SSSSRV_PACKET_MEM_SIZE chunks */
94 : 0 : int sss_packet_grow(struct sss_packet *packet, size_t size)
95 : : {
96 : : size_t totlen, len;
97 : : uint8_t *newmem;
98 : :
99 [ # # ]: 0 : if (size == 0) {
100 : : return EOK;
101 : : }
102 : :
103 : 0 : totlen = packet->memsize;
104 : 0 : len = *packet->len + size;
105 : :
106 : : /* make sure we do not overflow */
107 [ # # ]: 0 : if (totlen < len) {
108 : 0 : int n = len % SSSSRV_PACKET_MEM_SIZE + 1;
109 : 0 : totlen += n * SSSSRV_PACKET_MEM_SIZE;
110 [ # # ]: 0 : if (totlen < len) {
111 : : return EINVAL;
112 : : }
113 : : }
114 : :
115 [ # # ]: 0 : if (totlen > packet->memsize) {
116 : 0 : newmem = talloc_realloc_size(packet, packet->buffer, totlen);
117 [ # # ]: 0 : if (!newmem) {
118 : : return ENOMEM;
119 : : }
120 : :
121 : 0 : packet->memsize = totlen;
122 : :
123 : : /* re-set pointers if realloc had to move memory */
124 [ # # ]: 0 : if (newmem != packet->buffer) {
125 : 0 : packet->buffer = newmem;
126 : 0 : packet->len = &((uint32_t *)packet->buffer)[0];
127 : 0 : packet->cmd = &((uint32_t *)packet->buffer)[1];
128 : 0 : packet->status = &((uint32_t *)packet->buffer)[2];
129 : 0 : packet->reserved = &((uint32_t *)packet->buffer)[3];
130 : 0 : packet->body = (uint8_t *)&((uint32_t *)packet->buffer)[4];
131 : : }
132 : : }
133 : :
134 : 0 : *(packet->len) += size;
135 : :
136 : 0 : return 0;
137 : : }
138 : :
139 : : /* reclaim backet previously resrved space in the packet
140 : : * usually done in functione recovering from not fatal erros */
141 : 0 : int sss_packet_shrink(struct sss_packet *packet, size_t size)
142 : : {
143 : : size_t newlen;
144 : :
145 [ # # ]: 0 : if (size > *(packet->len)) return EINVAL;
146 : :
147 : 0 : newlen = *(packet->len) - size;
148 [ # # ]: 0 : if (newlen < SSS_NSS_HEADER_SIZE) return EINVAL;
149 : :
150 : 0 : *(packet->len) = newlen;
151 : 0 : return 0;
152 : : }
153 : :
154 : 0 : int sss_packet_set_size(struct sss_packet *packet, size_t size)
155 : : {
156 : : size_t newlen;
157 : :
158 : 0 : newlen = SSS_NSS_HEADER_SIZE + size;
159 : :
160 : : /* make sure we do not overflow */
161 [ # # ]: 0 : if (packet->memsize < newlen) return EINVAL;
162 : :
163 : 0 : *(packet->len) = newlen;
164 : :
165 : 0 : return 0;
166 : : }
167 : :
168 : 0 : int sss_packet_recv(struct sss_packet *packet, int fd)
169 : : {
170 : : size_t rb;
171 : : size_t len;
172 : : void *buf;
173 : :
174 : 0 : buf = packet->buffer + packet->iop;
175 [ # # ]: 0 : if (packet->iop > 4) len = *packet->len - packet->iop;
176 : 0 : else len = packet->memsize - packet->iop;
177 : :
178 : : /* check for wrapping */
179 [ # # ]: 0 : if (len > packet->memsize) {
180 : : return EINVAL;
181 : : }
182 : :
183 : 0 : errno = 0;
184 : 0 : rb = recv(fd, buf, len, 0);
185 : :
186 [ # # ]: 0 : if (rb == -1) {
187 [ # # ]: 0 : if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
188 : : return EAGAIN;
189 : : } else {
190 : 0 : return errno;
191 : : }
192 : : }
193 : :
194 [ # # ]: 0 : if (rb == 0) {
195 : : return ENODATA;
196 : : }
197 : :
198 [ # # ]: 0 : if (*packet->len > packet->memsize) {
199 : : return EINVAL;
200 : : }
201 : :
202 : 0 : packet->iop += rb;
203 [ # # ]: 0 : if (packet->iop < 4) {
204 : : return EAGAIN;
205 : : }
206 : :
207 [ # # ]: 0 : if (packet->iop < *packet->len) {
208 : : return EAGAIN;
209 : : }
210 : :
211 : 0 : return EOK;
212 : : }
213 : :
214 : 0 : int sss_packet_send(struct sss_packet *packet, int fd)
215 : : {
216 : : size_t rb;
217 : : size_t len;
218 : : void *buf;
219 : :
220 [ # # ]: 0 : if (!packet) {
221 : : /* No packet object to write to? */
222 : : return EINVAL;
223 : : }
224 : :
225 : 0 : buf = packet->buffer + packet->iop;
226 : 0 : len = *packet->len - packet->iop;
227 : :
228 : 0 : errno = 0;
229 : 0 : rb = send(fd, buf, len, 0);
230 : :
231 [ # # ]: 0 : if (rb == -1) {
232 [ # # ]: 0 : if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
233 : : return EAGAIN;
234 : : } else {
235 : 0 : return errno;
236 : : }
237 : : }
238 : :
239 [ # # ]: 0 : if (rb == 0) {
240 : : return EIO;
241 : : }
242 : :
243 : 0 : packet->iop += rb;
244 : :
245 [ # # ]: 0 : if (packet->iop < *packet->len) {
246 : : return EAGAIN;
247 : : }
248 : :
249 : 0 : return EOK;
250 : : }
251 : :
252 : 0 : enum sss_cli_command sss_packet_get_cmd(struct sss_packet *packet)
253 : : {
254 : 0 : return (enum sss_cli_command)(*packet->cmd);
255 : : }
256 : :
257 : 0 : void sss_packet_get_body(struct sss_packet *packet, uint8_t **body, size_t *blen)
258 : : {
259 : 0 : *body = packet->body;
260 : 0 : *blen = *packet->len - SSS_NSS_HEADER_SIZE;
261 : 0 : }
262 : :
263 : 0 : void sss_packet_set_error(struct sss_packet *packet, int error)
264 : : {
265 : 0 : *(packet->status) = error;
266 : 0 : }
|