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