]> git.sur5r.net Git - openldap/blob - contrib/slapd-modules/nssov/nss-pam-ldapd/nslcd-prot.h
1252158c6dab97f94657da8b3271017097e2f107
[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 COMMON__NSLCD_PROT_H
24 #define COMMON__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     tmpint32=(tmpint32-sizeof(buffer))+1; \
184     DEBUG_PRINT("READ       : buffer %d bytes too small",tmpint32); \
185     ERROR_OUT_BUFERROR(fp); \
186   } \
187   /* read string from the stream */ \
188   if (tmpint32>0) \
189     { READ(fp,buffer,(size_t)tmpint32); } \
190   /* null-terminate string in buffer */ \
191   buffer[tmpint32]='\0'; \
192   DEBUG_PRINT("READ_STRING: var="__STRING(buffer)" string=\"%s\"",buffer);
193
194
195 /* READ BUF macros that read data into a pre-allocated buffer.
196    these macros may require the availability of the following
197    variables:
198    int32_t tmpint32; - temporary variable
199    char *buffer;     - pointer to a buffer for reading strings
200    size_t buflen;    - the size of the buffer
201    size_t bufptr;    - the current position in the buffer
202    */
203
204 /* current position in the buffer */
205 #define BUF_CUR \
206   (buffer+bufptr)
207
208 /* check that the buffer has sz bytes left in it */
209 #define BUF_CHECK(fp,sz) \
210   if ((bufptr+(size_t)(sz))>buflen) \
211   { \
212     /* will not fit */ \
213     tmpint32=bufptr+(sz)-(buflen); \
214     DEBUG_PRINT("READ       : buffer %d bytes too small",tmpint32); \
215     ERROR_OUT_BUFERROR(fp); \
216   }
217
218 /* move the buffer pointer */
219 #define BUF_SKIP(sz) \
220   bufptr+=(size_t)(sz);
221
222 /* move BUF_CUR foreward so that it is aligned to the specified
223    type width */
224 #define BUF_ALIGN(fp,type) \
225   /* figure out number of bytes to skip foreward */ \
226   tmp2int32=(sizeof(type)-((BUF_CUR-(char *)NULL)%sizeof(type)))%sizeof(type); \
227   /* check and skip */ \
228   BUF_CHECK(fp,tmp2int32); \
229   BUF_SKIP(tmp2int32);
230
231 /* allocate a piece of the buffer to store an array in */
232 #define BUF_ALLOC(fp,ptr,type,num) \
233   /* align to the specified type width */ \
234   BUF_ALIGN(fp,type); \
235   /* check that we have enough room */ \
236   BUF_CHECK(fp,(size_t)(num)*sizeof(type)); \
237   /* store the pointer */ \
238   (ptr)=(type *)BUF_CUR; \
239   /* reserve the space */ \
240   BUF_SKIP((size_t)(num)*sizeof(type));
241
242 /* read a binary blob into the buffer */
243 #define READ_BUF(fp,ptr,sz) \
244   /* check that there is enough room and read */ \
245   BUF_CHECK(fp,sz); \
246   READ(fp,BUF_CUR,(size_t)sz); \
247   /* store pointer and skip */ \
248   (ptr)=BUF_CUR; \
249   BUF_SKIP(sz);
250
251 /* read string in the buffer (using buffer, buflen and bufptr)
252    and store the actual location of the string in field */
253 #define READ_BUF_STRING(fp,field) \
254   /* read the size of the string */ \
255   READ_TYPE(fp,tmpint32,int32_t); \
256   DEBUG_PRINT("READ_BUF_STRING: var="__STRING(field)" strlen=%d",tmpint32); \
257   /* check if read would fit */ \
258   BUF_CHECK(fp,tmpint32+1); \
259   /* read string from the stream */ \
260   if (tmpint32>0) \
261     { READ(fp,BUF_CUR,(size_t)tmpint32); } \
262   /* null-terminate string in buffer */ \
263   BUF_CUR[tmpint32]='\0'; \
264   DEBUG_PRINT("READ_BUF_STRING: var="__STRING(field)" string=\"%s\"",BUF_CUR); \
265   /* prepare result */ \
266   (field)=BUF_CUR; \
267   BUF_SKIP(tmpint32+1);
268
269 /* read an array from a stram and store it as a null-terminated
270    array list (size for the array is allocated) */
271 #define READ_BUF_STRINGLIST(fp,arr) \
272   /* read the number of entries */ \
273   READ_TYPE(fp,tmp3int32,int32_t); \
274   DEBUG_PRINT("READ_STRLST: var="__STRING(arr)" num=%d",(int)tmp3int32); \
275   /* allocate room for *char[num+1] */ \
276   BUF_ALLOC(fp,arr,char *,tmp3int32+1); \
277   /* read all entries */ \
278   for (tmp2int32=0;tmp2int32<tmp3int32;tmp2int32++) \
279   { \
280     READ_BUF_STRING(fp,(arr)[tmp2int32]); \
281   } \
282   /* set last entry to NULL */ \
283   (arr)[tmp2int32]=NULL;
284
285
286 /* SKIP macros for skipping over certain parts of the protocol stream. */
287
288 /* skip a number of bytes foreward */
289 #define SKIP(fp,sz) \
290   DEBUG_PRINT("READ       : skip %d bytes",(int)(sz)); \
291   /* read (skip) the specified number of bytes */ \
292   if (tio_skip(fp,sz)) \
293   { \
294     DEBUG_PRINT("READ       : skip error: %s",strerror(errno)); \
295     ERROR_OUT_READERROR(fp); \
296   }
297
298 /* read a string from the stream but don't do anything with the result */
299 #define SKIP_STRING(fp) \
300   /* read the size of the string */ \
301   READ_TYPE(fp,tmpint32,int32_t); \
302   DEBUG_PRINT("READ_STRING: skip %d bytes",(int)tmpint32); \
303   /* read (skip) the specified number of bytes */ \
304   SKIP(fp,tmpint32);
305
306 /* skip a list of strings */
307 #define SKIP_STRINGLIST(fp) \
308   /* read the number of entries */ \
309   READ_TYPE(fp,tmp3int32,int32_t); \
310   DEBUG_PRINT("READ_STRLST: skip %d strings",(int)tmp3int32); \
311   /* read all entries */ \
312   for (tmp2int32=0;tmp2int32<tmp3int32;tmp2int32++) \
313   { \
314     SKIP_STRING(fp); \
315   }
316
317
318 /* These are functions and macors for performing common operations in
319    the nslcd request/response protocol. */
320
321 /* returns a socket to the server or NULL on error (see errno),
322    socket should be closed with tio_close() */
323 TFILE *nslcd_client_open(void)
324   MUST_USE;
325
326 /* generic request code */
327 #define NSLCD_REQUEST(fp,action,writefn) \
328   /* open a client socket */ \
329   if ((fp=nslcd_client_open())==NULL) \
330     { ERROR_OUT_OPENERROR } \
331   /* write a request header with a request code */ \
332   WRITE_INT32(fp,(int32_t)NSLCD_VERSION) \
333   WRITE_INT32(fp,(int32_t)action) \
334   /* write the request parameters (if any) */ \
335   writefn; \
336   /* flush the stream */ \
337   if (tio_flush(fp)<0) \
338   { \
339     DEBUG_PRINT("WRITE_FLUSH : error: %s",strerror(errno)); \
340     ERROR_OUT_WRITEERROR(fp); \
341   } \
342   /* read and check response version number */ \
343   READ_TYPE(fp,tmpint32,int32_t); \
344   if (tmpint32!=(int32_t)NSLCD_VERSION) \
345     { ERROR_OUT_READERROR(fp) } \
346   /* read and check response request number */ \
347   READ_TYPE(fp,tmpint32,int32_t); \
348   if (tmpint32!=(int32_t)(action)) \
349     { ERROR_OUT_READERROR(fp) }
350
351 /* Read the response code (the result code of the query) from
352    the stream. */
353 #define READ_RESPONSE_CODE(fp) \
354   READ_TYPE(fp,tmpint32,int32_t); \
355   if (tmpint32!=(int32_t)NSLCD_RESULT_BEGIN) \
356     { ERROR_OUT_NOSUCCESS(fp) }
357
358 #endif /* not COMMON__NSLCD_PROT_H */