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