diff options
Diffstat (limited to 'contrib/slapd-modules/nssov/nss-pam-ldapd/nslcd-prot.h')
-rw-r--r-- | contrib/slapd-modules/nssov/nss-pam-ldapd/nslcd-prot.h | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/contrib/slapd-modules/nssov/nss-pam-ldapd/nslcd-prot.h b/contrib/slapd-modules/nssov/nss-pam-ldapd/nslcd-prot.h new file mode 100644 index 0000000..21ec7c2 --- /dev/null +++ b/contrib/slapd-modules/nssov/nss-pam-ldapd/nslcd-prot.h @@ -0,0 +1,391 @@ +/* + nslcd-prot.h - helper macros for reading and writing in protocol streams + + Copyright (C) 2006 West Consulting + Copyright (C) 2006-2014 Arthur de Jong + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA +*/ + +#ifndef COMMON__NSLCD_PROT_H +#define COMMON__NSLCD_PROT_H 1 + +#include <arpa/inet.h> +#include <netinet/in.h> + +#include "tio.h" + +/* If you use these macros you should define the following macros to + handle error conditions (these marcos should clean up and return from the + function): + ERROR_OUT_WRITEERROR(fp) + ERROR_OUT_READERROR(fp) + ERROR_OUT_BUFERROR(fp) + ERROR_OUT_NOSUCCESS(fp) */ + + +/* Debugging marcos that can be used to enable detailed protocol logging, + pass -DDEBUG_PROT to do overall protocol debugging, and -DDEBUG_PROT_DUMP + to dump the actual bytestream. */ + +#ifdef DEBUG_PROT +/* define a debugging macro to output logging */ +#include <string.h> +#include <errno.h> +#define DEBUG_PRINT(fmt, arg) \ + fprintf(stderr, "%s:%d:%s: " fmt "\n", __FILE__, __LINE__, \ + __PRETTY_FUNCTION__, arg); +#else /* DEBUG_PROT */ +/* define an empty debug macro to disable logging */ +#define DEBUG_PRINT(fmt, arg) +#endif /* not DEBUG_PROT */ + +#ifdef DEBUG_PROT_DUMP +/* define a debugging macro to output detailed logging */ +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif /* HAVE_STDINT_H */ +static void debug_dump(const void *ptr, size_t size) +{ + int i; + for (i = 0; i < size; i++) + fprintf(stderr, " %02x", ((const uint8_t *)ptr)[i]); + fprintf(stderr, "\n"); +} +#define DEBUG_DUMP(ptr, size) \ + fprintf(stderr, "%s:%d:%s:", __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + debug_dump(ptr, size); +#else /* DEBUG_PROT_DUMP */ +/* define an empty debug macro to disable logging */ +#define DEBUG_DUMP(ptr, size) +#endif /* not DEBUG_PROT_DUMP */ + + +/* WRITE marcos, used for writing data, on write error they will + call the ERROR_OUT_WRITEERROR macro + these macros may require the availability of the following + variables: + int32_t tmpint32; - temporary variable + */ + +#define WRITE(fp, ptr, size) \ + DEBUG_PRINT("WRITE : var="__STRING(ptr)" size=%d", (int)size); \ + DEBUG_DUMP(ptr, size); \ + if (tio_write(fp, ptr, (size_t)size)) \ + { \ + char ebuf[128]; \ + int saved_errno = errno; \ + DEBUG_PRINT("WRITE : var="__STRING(ptr)" error: %s", \ + AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf))); \ + ERROR_OUT_WRITEERROR(fp); \ + } + +#define WRITE_INT32(fp, i) \ + DEBUG_PRINT("WRITE_INT32 : var="__STRING(i)" int32=%08x", (int)i); \ + tmpint32 = htonl((int32_t)(i)); \ + WRITE(fp, &tmpint32, sizeof(int32_t)) + +#define WRITE_STRING(fp, str) \ + DEBUG_PRINT("WRITE_STRING: var="__STRING(str)" string=\"%s\"", (str)); \ + if ((str) == NULL) \ + { \ + WRITE_INT32(fp, 0); \ + } \ + else \ + { \ + WRITE_INT32(fp, strlen(str)); \ + tmpint32 = ntohl(tmpint32); \ + if (tmpint32 > 0) \ + { \ + WRITE(fp, (str), tmpint32); \ + } \ + } + +#define WRITE_STRINGLIST(fp, arr) \ + if ((arr) == NULL) \ + { \ + DEBUG_PRINT("WRITE_STRLST: var="__STRING(arr)" num=%d", 0); \ + WRITE_INT32(fp, 0); \ + } \ + else \ + { \ + /* first determine length of array */ \ + for (tmp3int32 = 0; (arr)[tmp3int32] != NULL; tmp3int32++) \ + /* noting */ ; \ + /* write number of strings */ \ + DEBUG_PRINT("WRITE_STRLST: var="__STRING(arr)" num=%d", (int)tmp3int32); \ + WRITE_INT32(fp, tmp3int32); \ + /* write strings */ \ + for (tmp2int32 = 0; tmp2int32 < tmp3int32; tmp2int32++) \ + { \ + WRITE_STRING(fp, (arr)[tmp2int32]); \ + } \ + } + +#define WRITE_STRINGLIST_EXCEPT(fp, arr, not) \ + /* first determine length of array */ \ + tmp3int32 = 0; \ + for (tmp2int32 = 0; (arr)[tmp2int32] != NULL; tmp2int32++) \ + if (strcmp((arr)[tmp2int32], (not)) != 0) \ + tmp3int32++; \ + /* write number of strings (mius one because we intend to skip one) */ \ + DEBUG_PRINT("WRITE_STRLST: var="__STRING(arr)" num=%d", (int)tmp3int32); \ + WRITE_INT32(fp, tmp3int32); \ + /* write strings */ \ + for (tmp2int32 = 0; (arr)[tmp2int32] != NULL; tmp2int32++) \ + { \ + if (strcmp((arr)[tmp2int32], (not)) != 0) \ + { \ + WRITE_STRING(fp, (arr)[tmp2int32]); \ + } \ + } + +/* READ macros, used for reading data, on read error they will + call the ERROR_OUT_READERROR or ERROR_OUT_BUFERROR macro + these macros may require the availability of the following + variables: + int32_t tmpint32; - temporary variable + */ + +#define READ(fp, ptr, size) \ + if (tio_read(fp, ptr, (size_t)size)) \ + { \ + char ebuf[128]; \ + int saved_errno = errno; \ + DEBUG_PRINT("READ : var="__STRING(ptr)" error: %s", \ + AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf))); \ + ERROR_OUT_READERROR(fp); \ + } \ + DEBUG_PRINT("READ : var="__STRING(ptr)" size=%d", (int)(size)); \ + DEBUG_DUMP(ptr, size); + +#define READ_INT32(fp, i) \ + READ(fp, &tmpint32, sizeof(int32_t)); \ + (i) = (int32_t)ntohl(tmpint32); \ + DEBUG_PRINT("READ_INT32 : var="__STRING(i)" int32==%08x", (int)(i)); + +/* read a string in a fixed-size "normal" buffer */ +#define READ_STRING(fp, buffer) \ + /* read the size of the string */ \ + READ(fp, &tmpint32, sizeof(int32_t)); \ + tmpint32 = ntohl(tmpint32); \ + DEBUG_PRINT("READ_STRING: var="__STRING(buffer)" strlen=%d", tmpint32); \ + /* check if read would fit */ \ + if (((size_t)tmpint32) >= sizeof(buffer)) \ + { \ + /* will not fit */ \ + tmpint32 = (tmpint32 - sizeof(buffer)) + 1; \ + DEBUG_PRINT("READ : buffer %d bytes too small", tmpint32); \ + ERROR_OUT_BUFERROR(fp); \ + } \ + /* read string from the stream */ \ + if (tmpint32 > 0) \ + { \ + READ(fp, buffer, (size_t)tmpint32); \ + } \ + /* null-terminate string in buffer */ \ + buffer[tmpint32] = '\0'; \ + DEBUG_PRINT("READ_STRING: var="__STRING(buffer)" string=\"%s\"", buffer); + + +/* READ BUF macros that read data into a pre-allocated buffer. + these macros may require the availability of the following + variables: + int32_t tmpint32; - temporary variable + char *buffer; - pointer to a buffer for reading strings + size_t buflen; - the size of the buffer + size_t bufptr; - the current position in the buffer + */ + +/* current position in the buffer */ +#define BUF_CUR \ + (buffer + bufptr) + +/* check that the buffer has sz bytes left in it */ +#define BUF_CHECK(fp, sz) \ + if ((bufptr + (size_t)(sz)) > buflen) \ + { \ + /* will not fit */ \ + tmpint32 = bufptr + (sz) - (buflen); \ + DEBUG_PRINT("READ : buffer %d bytes too small", tmpint32); \ + ERROR_OUT_BUFERROR(fp); \ + } + +/* move the buffer pointer */ +#define BUF_SKIP(sz) \ + bufptr += (size_t)(sz); + +/* move BUF_CUR forward so that it is aligned to the specified + type width */ +#define BUF_ALIGN(fp, type) \ + /* figure out number of bytes to skip forward */ \ + tmp2int32 = (sizeof(type) - ((BUF_CUR - (char *)NULL) % sizeof(type))) \ + % sizeof(type); \ + /* check and skip */ \ + BUF_CHECK(fp, tmp2int32); \ + BUF_SKIP(tmp2int32); + +/* allocate a piece of the buffer to store an array in */ +#define BUF_ALLOC(fp, ptr, type, num) \ + /* align to the specified type width */ \ + BUF_ALIGN(fp, type); \ + /* check that we have enough room */ \ + BUF_CHECK(fp, (size_t)(num) * sizeof(type)); \ + /* store the pointer */ \ + (ptr) = (type *)BUF_CUR; \ + /* reserve the space */ \ + BUF_SKIP((size_t)(num) * sizeof(type)); + +/* read a binary blob into the buffer */ +#define READ_BUF(fp, ptr, sz) \ + /* check that there is enough room and read */ \ + BUF_CHECK(fp, sz); \ + READ(fp, BUF_CUR, (size_t)sz); \ + /* store pointer and skip */ \ + (ptr) = BUF_CUR; \ + BUF_SKIP(sz); + +/* read string in the buffer (using buffer, buflen and bufptr) + and store the actual location of the string in field */ +#define READ_BUF_STRING(fp, field) \ + /* read the size of the string */ \ + READ(fp, &tmpint32, sizeof(int32_t)); \ + tmpint32 = ntohl(tmpint32); \ + DEBUG_PRINT("READ_BUF_STRING: var="__STRING(field)" strlen=%d", tmpint32); \ + /* check if read would fit */ \ + BUF_CHECK(fp, tmpint32 + 1); \ + /* read string from the stream */ \ + if (tmpint32 > 0) \ + { \ + READ(fp, BUF_CUR, (size_t)tmpint32); \ + } \ + /* null-terminate string in buffer */ \ + BUF_CUR[tmpint32] = '\0'; \ + DEBUG_PRINT("READ_BUF_STRING: var="__STRING(field)" string=\"%s\"", BUF_CUR); \ + /* prepare result */ \ + (field) = BUF_CUR; \ + BUF_SKIP(tmpint32 + 1); + +/* read an array from a stream and store it as a null-terminated + array list (size for the array is allocated) */ +#define READ_BUF_STRINGLIST(fp, arr) \ + /* read the number of entries */ \ + READ(fp, &tmp3int32, sizeof(int32_t)); \ + tmp3int32 = ntohl(tmp3int32); \ + DEBUG_PRINT("READ_STRLST: var="__STRING(arr)" num=%d", (int)tmp3int32); \ + /* allocate room for *char[num + 1] */ \ + BUF_ALLOC(fp, arr, char *, tmp3int32 + 1); \ + /* read all entries */ \ + for (tmp2int32 = 0; tmp2int32 < tmp3int32; tmp2int32++) \ + { \ + READ_BUF_STRING(fp, (arr)[tmp2int32]); \ + } \ + /* set last entry to NULL */ \ + (arr)[tmp2int32] = NULL; + + +/* SKIP macros for skipping over certain parts of the protocol stream. */ + +/* skip a number of bytes forward */ +#define SKIP(fp, sz) \ + DEBUG_PRINT("READ : skip %d bytes", (int)(sz)); \ + /* read (skip) the specified number of bytes */ \ + if (tio_skip(fp, sz)) \ + { \ + char ebuf[128]; \ + int saved_errno = errno; \ + DEBUG_PRINT("READ : skip error: %s", \ + AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf))); \ + ERROR_OUT_READERROR(fp); \ + } + +/* read a string from the stream but don't do anything with the result */ +#define SKIP_STRING(fp) \ + /* read the size of the string */ \ + READ(fp, &tmpint32, sizeof(int32_t)); \ + tmpint32 = ntohl(tmpint32); \ + DEBUG_PRINT("READ_STRING: skip %d bytes", (int)tmpint32); \ + /* read (skip) the specified number of bytes */ \ + SKIP(fp, tmpint32); + +/* skip a list of strings */ +#define SKIP_STRINGLIST(fp) \ + /* read the number of entries */ \ + READ(fp, &tmp3int32, sizeof(int32_t)); \ + tmp3int32 = ntohl(tmp3int32); \ + DEBUG_PRINT("READ_STRLST: skip %d strings", (int)tmp3int32); \ + /* read all entries */ \ + for (tmp2int32 = 0; tmp2int32 < tmp3int32; tmp2int32++) \ + { \ + SKIP_STRING(fp); \ + } + + +/* These are functions and macros for performing common operations in + the nslcd request/response protocol. */ + +/* returns a socket to the server or NULL on error (see errno), + socket should be closed with tio_close() */ +TFILE *nslcd_client_open(void) + MUST_USE; + +/* generic request code */ +#define NSLCD_REQUEST(fp, action, writefn) \ + /* open a client socket */ \ + if ((fp = nslcd_client_open()) == NULL) \ + { \ + ERROR_OUT_OPENERROR; \ + } \ + /* write a request header with a request code */ \ + WRITE_INT32(fp, (int32_t)NSLCD_VERSION) \ + WRITE_INT32(fp, (int32_t)action) \ + /* write the request parameters (if any) */ \ + writefn; \ + /* flush the stream */ \ + if (tio_flush(fp) < 0) \ + { \ + char ebuf[128]; \ + int saved_errno = errno; \ + DEBUG_PRINT("WRITE_FLUSH : error: %s", \ + AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf))); \ + ERROR_OUT_WRITEERROR(fp); \ + } \ + /* read and check response version number */ \ + READ(fp, &tmpint32, sizeof(int32_t)); \ + tmpint32 = ntohl(tmpint32); \ + if (tmpint32 != (int32_t)NSLCD_VERSION) \ + { \ + ERROR_OUT_READERROR(fp); \ + } \ + /* read and check response request number */ \ + READ(fp, &tmpint32, sizeof(int32_t)); \ + tmpint32 = ntohl(tmpint32); \ + if (tmpint32 != (int32_t)(action)) \ + { \ + ERROR_OUT_READERROR(fp); \ + } + +/* Read the response code (the result code of the query) from + the stream. */ +#define READ_RESPONSE_CODE(fp) \ + READ(fp, &tmpint32, sizeof(int32_t)); \ + tmpint32 = ntohl(tmpint32); \ + if (tmpint32 != (int32_t)NSLCD_RESULT_BEGIN) \ + { \ + ERROR_OUT_NOSUCCESS(fp); \ + } + +#endif /* not COMMON__NSLCD_PROT_H */ |