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