]> git.sur5r.net Git - openldap/blob - contrib/slapd-modules/nssov/nss-pam-ldapd/nslcd-prot.h
ITS#8605 - spelling fixes
[openldap] / contrib / slapd-modules / nssov / nss-pam-ldapd / nslcd-prot.h
1 /*
2    nslcd-prot.h - helper macros for reading and writing in protocol streams
3
4    Copyright (C) 2006 West Consulting
5    Copyright (C) 2006-2014 Arthur de Jong
6
7    This library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Lesser General Public
9    License as published by the Free Software Foundation; either
10    version 2.1 of the License, or (at your option) any later version.
11
12    This library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16
17    You should have received a copy of the GNU Lesser General Public
18    License along with this library; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20    02110-1301 USA
21 */
22
23 #ifndef COMMON__NSLCD_PROT_H
24 #define COMMON__NSLCD_PROT_H 1
25
26 #include <arpa/inet.h>
27 #include <netinet/in.h>
28
29 #include "tio.h"
30
31 /* If you use these macros you should define the following macros to
32    handle error conditions (these marcos should clean up and return from the
33    function):
34      ERROR_OUT_WRITEERROR(fp)
35      ERROR_OUT_READERROR(fp)
36      ERROR_OUT_BUFERROR(fp)
37      ERROR_OUT_NOSUCCESS(fp) */
38
39
40 /* Debugging marcos that can be used to enable detailed protocol logging,
41    pass -DDEBUG_PROT to do overall protocol debugging, and -DDEBUG_PROT_DUMP
42    to dump the actual bytestream. */
43
44 #ifdef DEBUG_PROT
45 /* define a debugging macro to output logging */
46 #include <string.h>
47 #include <errno.h>
48 #define DEBUG_PRINT(fmt, arg)                                               \
49   fprintf(stderr, "%s:%d:%s: " fmt "\n", __FILE__, __LINE__,                \
50           __PRETTY_FUNCTION__, arg);
51 #else /* DEBUG_PROT */
52 /* define an empty debug macro to disable logging */
53 #define DEBUG_PRINT(fmt, arg)
54 #endif /* not DEBUG_PROT */
55
56 #ifdef DEBUG_PROT_DUMP
57 /* define a debugging macro to output detailed logging */
58 #ifdef HAVE_STDINT_H
59 #include <stdint.h>
60 #endif /* HAVE_STDINT_H */
61 static void debug_dump(const void *ptr, size_t size)
62 {
63   int i;
64   for (i = 0; i < size; i++)
65     fprintf(stderr, " %02x", ((const uint8_t *)ptr)[i]);
66   fprintf(stderr, "\n");
67 }
68 #define DEBUG_DUMP(ptr, size)                                               \
69   fprintf(stderr, "%s:%d:%s:", __FILE__, __LINE__, __PRETTY_FUNCTION__);    \
70   debug_dump(ptr, size);
71 #else /* DEBUG_PROT_DUMP */
72 /* define an empty debug macro to disable logging */
73 #define DEBUG_DUMP(ptr, size)
74 #endif /* not DEBUG_PROT_DUMP */
75
76
77 /* WRITE marcos, used for writing data, on write error they will
78    call the ERROR_OUT_WRITEERROR macro
79    these macros may require the availability of the following
80    variables:
81    int32_t tmpint32; - temporary variable
82    */
83
84 #define WRITE(fp, ptr, size)                                                \
85   DEBUG_PRINT("WRITE       : var="__STRING(ptr)" size=%d", (int)size);      \
86   DEBUG_DUMP(ptr, size);                                                    \
87   if (tio_write(fp, ptr, (size_t)size))                                     \
88   {                                                                         \
89     DEBUG_PRINT("WRITE       : var="__STRING(ptr)" error: %s",              \
90                 strerror(errno));                                           \
91     ERROR_OUT_WRITEERROR(fp);                                               \
92   }
93
94 #define WRITE_INT32(fp, i)                                                  \
95   DEBUG_PRINT("WRITE_INT32 : var="__STRING(i)" int32=%08x", (int)i);        \
96   tmpint32 = htonl((int32_t)(i));                                           \
97   WRITE(fp, &tmpint32, sizeof(int32_t))
98
99 #define WRITE_STRING(fp, str)                                               \
100   DEBUG_PRINT("WRITE_STRING: var="__STRING(str)" string=\"%s\"", (str));    \
101   if ((str) == NULL)                                                        \
102   {                                                                         \
103     WRITE_INT32(fp, 0);                                                     \
104   }                                                                         \
105   else                                                                      \
106   {                                                                         \
107     WRITE_INT32(fp, strlen(str));                                           \
108     tmpint32 = ntohl(tmpint32);                                             \
109     if (tmpint32 > 0)                                                       \
110     {                                                                       \
111       WRITE(fp, (str), tmpint32);                                           \
112     }                                                                       \
113   }
114
115 #define WRITE_STRINGLIST(fp, arr)                                           \
116   if ((arr) == NULL)                                                        \
117   {                                                                         \
118     DEBUG_PRINT("WRITE_STRLST: var="__STRING(arr)" num=%d", 0);             \
119     WRITE_INT32(fp, 0);                                                     \
120   }                                                                         \
121   else                                                                      \
122   {                                                                         \
123     /* first determine length of array */                                   \
124     for (tmp3int32 = 0; (arr)[tmp3int32] != NULL; tmp3int32++)              \
125       /* noting */ ;                                                        \
126     /* write number of strings */                                           \
127     DEBUG_PRINT("WRITE_STRLST: var="__STRING(arr)" num=%d", (int)tmp3int32); \
128     WRITE_INT32(fp, tmp3int32);                                             \
129     /* write strings */                                                     \
130     for (tmp2int32 = 0; tmp2int32 < tmp3int32; tmp2int32++)                 \
131     {                                                                       \
132       WRITE_STRING(fp, (arr)[tmp2int32]);                                   \
133     }                                                                       \
134   }
135
136 #define WRITE_STRINGLIST_EXCEPT(fp, arr, not)                               \
137   /* first determine length of array */                                     \
138   tmp3int32 = 0;                                                            \
139   for (tmp2int32 = 0; (arr)[tmp2int32] != NULL; tmp2int32++)                \
140     if (strcmp((arr)[tmp2int32], (not)) != 0)                               \
141       tmp3int32++;                                                          \
142   /* write number of strings (mius one because we intend to skip one) */    \
143   DEBUG_PRINT("WRITE_STRLST: var="__STRING(arr)" num=%d", (int)tmp3int32);  \
144   WRITE_INT32(fp, tmp3int32);                                               \
145   /* write strings */                                                       \
146   for (tmp2int32 = 0; (arr)[tmp2int32] != NULL; tmp2int32++)                \
147   {                                                                         \
148     if (strcmp((arr)[tmp2int32], (not)) != 0)                               \
149     {                                                                       \
150       WRITE_STRING(fp, (arr)[tmp2int32]);                                   \
151     }                                                                       \
152   }
153
154 /* READ macros, used for reading data, on read error they will
155    call the ERROR_OUT_READERROR or ERROR_OUT_BUFERROR macro
156    these macros may require the availability of the following
157    variables:
158    int32_t tmpint32; - temporary variable
159    */
160
161 #define READ(fp, ptr, size)                                                 \
162   if (tio_read(fp, ptr, (size_t)size))                                      \
163   {                                                                         \
164     DEBUG_PRINT("READ       : var="__STRING(ptr)" error: %s",               \
165                 strerror(errno));                                           \
166     ERROR_OUT_READERROR(fp);                                                \
167   }                                                                         \
168   DEBUG_PRINT("READ       : var="__STRING(ptr)" size=%d", (int)(size));     \
169   DEBUG_DUMP(ptr, size);
170
171 #define READ_INT32(fp, i)                                                   \
172   READ(fp, &tmpint32, sizeof(int32_t));                                     \
173   (i) = (int32_t)ntohl(tmpint32);                                           \
174   DEBUG_PRINT("READ_INT32 : var="__STRING(i)" int32==%08x", (int)(i));
175
176 /* read a string in a fixed-size "normal" buffer */
177 #define READ_STRING(fp, buffer)                                             \
178   /* read the size of the string */                                         \
179   READ(fp, &tmpint32, sizeof(int32_t));                                     \
180   tmpint32 = ntohl(tmpint32);                                               \
181   DEBUG_PRINT("READ_STRING: var="__STRING(buffer)" strlen=%d", tmpint32);   \
182   /* check if read would fit */                                             \
183   if (((size_t)tmpint32) >= sizeof(buffer))                                 \
184   {                                                                         \
185     /* will not fit */                                                      \
186     tmpint32 = (tmpint32 - sizeof(buffer)) + 1;                             \
187     DEBUG_PRINT("READ       : buffer %d bytes too small", tmpint32);        \
188     ERROR_OUT_BUFERROR(fp);                                                 \
189   }                                                                         \
190   /* read string from the stream */                                         \
191   if (tmpint32 > 0)                                                         \
192   {                                                                         \
193     READ(fp, buffer, (size_t)tmpint32);                                     \
194   }                                                                         \
195   /* null-terminate string in buffer */                                     \
196   buffer[tmpint32] = '\0';                                                  \
197   DEBUG_PRINT("READ_STRING: var="__STRING(buffer)" string=\"%s\"", buffer);
198
199
200 /* READ BUF macros that read data into a pre-allocated buffer.
201    these macros may require the availability of the following
202    variables:
203    int32_t tmpint32; - temporary variable
204    char *buffer;     - pointer to a buffer for reading strings
205    size_t buflen;    - the size of the buffer
206    size_t bufptr;    - the current position in the buffer
207    */
208
209 /* current position in the buffer */
210 #define BUF_CUR                                                             \
211   (buffer + bufptr)
212
213 /* check that the buffer has sz bytes left in it */
214 #define BUF_CHECK(fp, sz)                                                   \
215   if ((bufptr + (size_t)(sz)) > buflen)                                     \
216   {                                                                         \
217     /* will not fit */                                                      \
218     tmpint32 = bufptr + (sz) - (buflen);                                    \
219     DEBUG_PRINT("READ       : buffer %d bytes too small", tmpint32);        \
220     ERROR_OUT_BUFERROR(fp);                                                 \
221   }
222
223 /* move the buffer pointer */
224 #define BUF_SKIP(sz)                                                        \
225   bufptr += (size_t)(sz);
226
227 /* move BUF_CUR foreward so that it is aligned to the specified
228    type width */
229 #define BUF_ALIGN(fp, type)                                                 \
230   /* figure out number of bytes to skip foreward */                         \
231   tmp2int32 = (sizeof(type) - ((BUF_CUR - (char *)NULL) % sizeof(type)))    \
232               % sizeof(type);                                               \
233   /* check and skip */                                                      \
234   BUF_CHECK(fp, tmp2int32);                                                 \
235   BUF_SKIP(tmp2int32);
236
237 /* allocate a piece of the buffer to store an array in */
238 #define BUF_ALLOC(fp, ptr, type, num)                                       \
239   /* align to the specified type width */                                   \
240   BUF_ALIGN(fp, type);                                                      \
241   /* check that we have enough room */                                      \
242   BUF_CHECK(fp, (size_t)(num) * sizeof(type));                              \
243   /* store the pointer */                                                   \
244   (ptr) = (type *)BUF_CUR;                                                  \
245   /* reserve the space */                                                   \
246   BUF_SKIP((size_t)(num) * sizeof(type));
247
248 /* read a binary blob into the buffer */
249 #define READ_BUF(fp, ptr, sz)                                               \
250   /* check that there is enough room and read */                            \
251   BUF_CHECK(fp, sz);                                                        \
252   READ(fp, BUF_CUR, (size_t)sz);                                            \
253   /* store pointer and skip */                                              \
254   (ptr) = BUF_CUR;                                                          \
255   BUF_SKIP(sz);
256
257 /* read string in the buffer (using buffer, buflen and bufptr)
258    and store the actual location of the string in field */
259 #define READ_BUF_STRING(fp, field)                                          \
260   /* read the size of the string */                                         \
261   READ(fp, &tmpint32, sizeof(int32_t));                                     \
262   tmpint32 = ntohl(tmpint32);                                               \
263   DEBUG_PRINT("READ_BUF_STRING: var="__STRING(field)" strlen=%d", tmpint32); \
264   /* check if read would fit */                                             \
265   BUF_CHECK(fp, tmpint32 + 1);                                              \
266   /* read string from the stream */                                         \
267   if (tmpint32 > 0)                                                         \
268   {                                                                         \
269     READ(fp, BUF_CUR, (size_t)tmpint32);                                    \
270   }                                                                         \
271   /* null-terminate string in buffer */                                     \
272   BUF_CUR[tmpint32] = '\0';                                                 \
273   DEBUG_PRINT("READ_BUF_STRING: var="__STRING(field)" string=\"%s\"", BUF_CUR); \
274   /* prepare result */                                                      \
275   (field) = BUF_CUR;                                                        \
276   BUF_SKIP(tmpint32 + 1);
277
278 /* read an array from a stram and store it as a null-terminated
279    array list (size for the array is allocated) */
280 #define READ_BUF_STRINGLIST(fp, arr)                                        \
281   /* read the number of entries */                                          \
282   READ(fp, &tmp3int32, sizeof(int32_t));                                    \
283   tmp3int32 = ntohl(tmp3int32);                                             \
284   DEBUG_PRINT("READ_STRLST: var="__STRING(arr)" num=%d", (int)tmp3int32);   \
285   /* allocate room for *char[num + 1] */                                      \
286   BUF_ALLOC(fp, arr, char *, tmp3int32 + 1);                                \
287   /* read all entries */                                                    \
288   for (tmp2int32 = 0; tmp2int32 < tmp3int32; tmp2int32++)                   \
289   {                                                                         \
290     READ_BUF_STRING(fp, (arr)[tmp2int32]);                                  \
291   }                                                                         \
292   /* set last entry to NULL */                                              \
293   (arr)[tmp2int32] = NULL;
294
295
296 /* SKIP macros for skipping over certain parts of the protocol stream. */
297
298 /* skip a number of bytes foreward */
299 #define SKIP(fp, sz)                                                        \
300   DEBUG_PRINT("READ       : skip %d bytes", (int)(sz));                     \
301   /* read (skip) the specified number of bytes */                           \
302   if (tio_skip(fp, sz))                                                     \
303   {                                                                         \
304     DEBUG_PRINT("READ       : skip error: %s", strerror(errno));            \
305     ERROR_OUT_READERROR(fp);                                                \
306   }
307
308 /* read a string from the stream but don't do anything with the result */
309 #define SKIP_STRING(fp)                                                     \
310   /* read the size of the string */                                         \
311   READ(fp, &tmpint32, sizeof(int32_t));                                     \
312   tmpint32 = ntohl(tmpint32);                                               \
313   DEBUG_PRINT("READ_STRING: skip %d bytes", (int)tmpint32);                 \
314   /* read (skip) the specified number of bytes */                           \
315   SKIP(fp, tmpint32);
316
317 /* skip a list of strings */
318 #define SKIP_STRINGLIST(fp)                                                 \
319   /* read the number of entries */                                          \
320   READ(fp, &tmp3int32, sizeof(int32_t));                                    \
321   tmp3int32 = ntohl(tmp3int32);                                             \
322   DEBUG_PRINT("READ_STRLST: skip %d strings", (int)tmp3int32);              \
323   /* read all entries */                                                    \
324   for (tmp2int32 = 0; tmp2int32 < tmp3int32; tmp2int32++)                   \
325   {                                                                         \
326     SKIP_STRING(fp);                                                        \
327   }
328
329
330 /* These are functions and macros for performing common operations in
331    the nslcd request/response protocol. */
332
333 /* returns a socket to the server or NULL on error (see errno),
334    socket should be closed with tio_close() */
335 TFILE *nslcd_client_open(void)
336   MUST_USE;
337
338 /* generic request code */
339 #define NSLCD_REQUEST(fp, action, writefn)                                  \
340   /* open a client socket */                                                \
341   if ((fp = nslcd_client_open()) == NULL)                                   \
342   {                                                                         \
343     ERROR_OUT_OPENERROR;                                                    \
344   }                                                                         \
345   /* write a request header with a request code */                          \
346   WRITE_INT32(fp, (int32_t)NSLCD_VERSION)                                   \
347   WRITE_INT32(fp, (int32_t)action)                                          \
348   /* write the request parameters (if any) */                               \
349   writefn;                                                                  \
350   /* flush the stream */                                                    \
351   if (tio_flush(fp) < 0)                                                    \
352   {                                                                         \
353     DEBUG_PRINT("WRITE_FLUSH : error: %s", strerror(errno));                \
354     ERROR_OUT_WRITEERROR(fp);                                               \
355   }                                                                         \
356   /* read and check response version number */                              \
357   READ(fp, &tmpint32, sizeof(int32_t));                                     \
358   tmpint32 = ntohl(tmpint32);                                               \
359   if (tmpint32 != (int32_t)NSLCD_VERSION)                                   \
360   {                                                                         \
361     ERROR_OUT_READERROR(fp);                                                \
362   }                                                                         \
363   /* read and check response request number */                              \
364   READ(fp, &tmpint32, sizeof(int32_t));                                     \
365   tmpint32 = ntohl(tmpint32);                                               \
366   if (tmpint32 != (int32_t)(action))                                        \
367   {                                                                         \
368     ERROR_OUT_READERROR(fp);                                                \
369   }
370
371 /* Read the response code (the result code of the query) from
372    the stream. */
373 #define READ_RESPONSE_CODE(fp)                                              \
374   READ(fp, &tmpint32, sizeof(int32_t));                                     \
375   tmpint32 = ntohl(tmpint32);                                               \
376   if (tmpint32 != (int32_t)NSLCD_RESULT_BEGIN)                              \
377   {                                                                         \
378     ERROR_OUT_NOSUCCESS(fp);                                                \
379   }
380
381 #endif /* not COMMON__NSLCD_PROT_H */