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