ITS#8097 nssov: update nss-pam-ldapd files to 0.9.4

This commit is contained in:
Ryan Tandy 2015-01-07 07:45:23 -08:00 committed by Howard Chu
parent 25bbf116ad
commit 6a28f3dc20
6 changed files with 569 additions and 520 deletions

View file

@ -1,4 +1,4 @@
These files were pulled from the nss-pam-ldapd project version 0.8.12.
These files were pulled from the nss-pam-ldapd project version 0.9.4.
Copyright notices are in the individual files.
This is not the full distribution of nss-pam-ldapd, and does not
@ -10,6 +10,6 @@ If your system already has the nss-pam-ldapd stub libraries
installed, make sure the versions match the version number
shown above. Otherwise, there may be incompatible differences in
the protocols being used. Currently nssov requires at least
version 0.8.11. If your system's version is older, you will need
version 0.9.0. If your system's version is older, you will need
to install the client-side stubs from source.

View file

@ -1,7 +1,7 @@
/*
attrs.h - wrapper macros for the gcc __attribute__(()) directive
Copyright (C) 2007, 2008 Arthur de Jong
Copyright (C) 2007, 2008, 2012 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
@ -23,7 +23,7 @@
#define COMPAT__ATTRS_H 1
/* macro for testing the version of GCC */
#define GCC_VERSION(major,minor) \
#define GCC_VERSION(major, minor) \
((__GNUC__ > (major)) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))
/* These are macros to use some gcc-specific flags in case the're available
@ -34,7 +34,7 @@
/* this is used to flag function parameters that are not used in the function
body. */
#if GCC_VERSION(3,0)
#if GCC_VERSION(3, 0)
#define UNUSED(x) x __attribute__((__unused__))
#else
#define UNUSED(x) x
@ -42,16 +42,16 @@
/* this is used to add extra format checking to the function calls as if this
was a printf()-like function */
#if GCC_VERSION(3,0)
#define LIKE_PRINTF(format_idx,arg_idx) \
__attribute__((__format__(__printf__,format_idx,arg_idx)))
#if GCC_VERSION(3, 0)
#define LIKE_PRINTF(format_idx, arg_idx) \
__attribute__((__format__(__printf__, format_idx, arg_idx)))
#else
#define LIKE_PRINTF(format_idx,arg_idx) /* no attribute */
#define LIKE_PRINTF(format_idx, arg_idx) /* no attribute */
#endif
/* indicates that the function is "pure": it's result is purely based on
/* indicates that the function is "pure": its result is purely based on
the parameters and has no side effects or used static data */
#if GCC_VERSION(3,0)
#if GCC_VERSION(3, 0)
#define PURE __attribute__((__pure__))
#else
#define PURE /* no attribute */
@ -59,21 +59,21 @@
/* the function returns a new data structure that has been freshly
allocated */
#if GCC_VERSION(3,0)
#if GCC_VERSION(3, 0)
#define LIKE_MALLOC __attribute__((__malloc__))
#else
#define LIKE_MALLOC /* no attribute */
#endif
/* the function's return value should be used by the caller */
#if GCC_VERSION(3,4)
#if GCC_VERSION(3, 4)
#define MUST_USE __attribute__((__warn_unused_result__))
#else
#define MUST_USE /* no attribute */
#endif
/* the function's return value should be used by the caller */
#if GCC_VERSION(2,5)
#if GCC_VERSION(2, 5)
#define NORETURN __attribute__((__noreturn__))
#else
#define NORETURN /* no attribute */

View file

@ -2,7 +2,7 @@
nslcd-prot.h - helper macros for reading and writing in protocol streams
Copyright (C) 2006 West Consulting
Copyright (C) 2006, 2007, 2009 Arthur de Jong
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
@ -23,6 +23,9 @@
#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
@ -42,11 +45,12 @@
/* 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);
#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)
#define DEBUG_PRINT(fmt, arg)
#endif /* not DEBUG_PROT */
#ifdef DEBUG_PROT_DUMP
@ -54,19 +58,19 @@
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif /* HAVE_STDINT_H */
static void debug_dump(const void *ptr,size_t size)
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");
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);
#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)
#define DEBUG_DUMP(ptr, size)
#endif /* not DEBUG_PROT_DUMP */
@ -77,76 +81,76 @@ static void debug_dump(const void *ptr,size_t size)
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)) \
{ \
DEBUG_PRINT("WRITE : var="__STRING(ptr)" error: %s",strerror(errno)); \
ERROR_OUT_WRITEERROR(fp); \
#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)) \
{ \
DEBUG_PRINT("WRITE : var="__STRING(ptr)" error: %s", \
strerror(errno)); \
ERROR_OUT_WRITEERROR(fp); \
}
#define WRITE_TYPE(fp,field,type) \
WRITE(fp,&(field),sizeof(type))
#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_INT32(fp,i) \
DEBUG_PRINT("WRITE_INT32 : var="__STRING(i)" int32=%d",(int)i); \
tmpint32=(int32_t)(i); \
WRITE_TYPE(fp,tmpint32,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)); \
if (tmpint32>0) \
{ WRITE(fp,(str),tmpint32); } \
#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 determin 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_TYPE(fp,tmp3int32,int32_t); \
/* write strings */ \
for (tmp2int32=0;tmp2int32<tmp3int32;tmp2int32++) \
{ \
WRITE_STRING(fp,(arr)[tmp2int32]); \
} \
#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 determin 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_TYPE(fp,tmp3int32,int32_t); \
/* write strings */ \
for (tmp2int32=0;(arr)[tmp2int32]!=NULL;tmp2int32++) \
{ \
if (strcmp((arr)[tmp2int32],(not))!=0) \
{ \
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
@ -154,42 +158,43 @@ static void debug_dump(const void *ptr,size_t size)
int32_t tmpint32; - temporary variable
*/
#define READ(fp,ptr,size) \
if (tio_read(fp,ptr,(size_t)size)) \
{ \
DEBUG_PRINT("READ : var="__STRING(ptr)" error: %s",strerror(errno)); \
ERROR_OUT_READERROR(fp); \
} \
DEBUG_PRINT("READ : var="__STRING(ptr)" size=%d",(int)size); \
DEBUG_DUMP(ptr,size);
#define READ(fp, ptr, size) \
if (tio_read(fp, ptr, (size_t)size)) \
{ \
DEBUG_PRINT("READ : var="__STRING(ptr)" error: %s", \
strerror(errno)); \
ERROR_OUT_READERROR(fp); \
} \
DEBUG_PRINT("READ : var="__STRING(ptr)" size=%d", (int)(size)); \
DEBUG_DUMP(ptr, size);
#define READ_TYPE(fp,field,type) \
READ(fp,&(field),sizeof(type))
#define READ_INT32(fp,i) \
READ_TYPE(fp,tmpint32,int32_t); \
i=tmpint32; \
DEBUG_PRINT("READ_INT32 : var="__STRING(i)" int32=%d",(int)i);
#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_TYPE(fp,tmpint32,int32_t); \
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);
#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.
@ -202,116 +207,123 @@ static void debug_dump(const void *ptr,size_t size)
*/
/* current position in the buffer */
#define BUF_CUR \
(buffer+bufptr)
#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); \
#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);
#define BUF_SKIP(sz) \
bufptr += (size_t)(sz);
/* move BUF_CUR foreward so that it is aligned to the specified
type width */
#define BUF_ALIGN(fp,type) \
/* figure out number of bytes to skip foreward */ \
tmp2int32=(sizeof(type)-((BUF_CUR-(char *)NULL)%sizeof(type)))%sizeof(type); \
/* check and skip */ \
BUF_CHECK(fp,tmp2int32); \
#define BUF_ALIGN(fp, type) \
/* figure out number of bytes to skip foreward */ \
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));
#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; \
#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_TYPE(fp,tmpint32,int32_t); \
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);
#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 stram 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_TYPE(fp,tmp3int32,int32_t); \
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;
#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 foreward */
#define SKIP(fp,sz) \
DEBUG_PRINT("READ : skip %d bytes",(int)(sz)); \
/* read (skip) the specified number of bytes */ \
if (tio_skip(fp,sz)) \
{ \
DEBUG_PRINT("READ : skip error: %s",strerror(errno)); \
ERROR_OUT_READERROR(fp); \
#define SKIP(fp, sz) \
DEBUG_PRINT("READ : skip %d bytes", (int)(sz)); \
/* read (skip) the specified number of bytes */ \
if (tio_skip(fp, sz)) \
{ \
DEBUG_PRINT("READ : skip error: %s", strerror(errno)); \
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_TYPE(fp,tmpint32,int32_t); \
DEBUG_PRINT("READ_STRING: skip %d bytes",(int)tmpint32); \
/* read (skip) the specified number of bytes */ \
SKIP(fp,tmpint32);
#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_TYPE(fp,tmp3int32,int32_t); \
DEBUG_PRINT("READ_STRLST: skip %d strings",(int)tmp3int32); \
/* read all entries */ \
for (tmp2int32=0;tmp2int32<tmp3int32;tmp2int32++) \
{ \
SKIP_STRING(fp); \
#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); \
}
@ -324,35 +336,46 @@ 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) \
{ \
DEBUG_PRINT("WRITE_FLUSH : error: %s",strerror(errno)); \
ERROR_OUT_WRITEERROR(fp); \
} \
/* read and check response version number */ \
READ_TYPE(fp,tmpint32,int32_t); \
if (tmpint32!=(int32_t)NSLCD_VERSION) \
{ ERROR_OUT_READERROR(fp) } \
/* read and check response request number */ \
READ_TYPE(fp,tmpint32,int32_t); \
if (tmpint32!=(int32_t)(action)) \
{ ERROR_OUT_READERROR(fp) }
#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) \
{ \
DEBUG_PRINT("WRITE_FLUSH : error: %s", strerror(errno)); \
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_TYPE(fp,tmpint32,int32_t); \
if (tmpint32!=(int32_t)NSLCD_RESULT_BEGIN) \
{ ERROR_OUT_NOSUCCESS(fp) }
#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 */

View file

@ -2,7 +2,7 @@
nslcd.h - file describing client/server protocol
Copyright (C) 2006 West Consulting
Copyright (C) 2006, 2007, 2009, 2010, 2011, 2012 Arthur de Jong
Copyright (C) 2006, 2007, 2009, 2010, 2011, 2012, 2013 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
@ -59,122 +59,130 @@
Furthermore the ADDRESS compound data type is defined as:
INT32 type of address: e.g. AF_INET or AF_INET6
INT32 lenght of address
RAW the address itself in network byte order
RAW the address itself
With the ADDRESSLIST using the same construct as with STRINGLIST.
The protocol uses host-byte order for all types (except in the raw
address above).
The protocol uses network byte order for all types.
*/
/* The current version of the protocol. Note that version 1
is experimental and this version will be used until a
1.0 release of nss-pam-ldapd is made. */
#define NSLCD_VERSION 1
/* The current version of the protocol. This protocol should only be
updated with major backwards-incompatible changes. */
#define NSLCD_VERSION 0x00000002
/* Get a NSLCD configuration option. There is one request parameter:
INT32 NSLCD_CONFIG_*
the result value is:
STRING value, interpretation depending on request */
#define NSLCD_ACTION_CONFIG_GET 20006
#define NSLCD_ACTION_CONFIG_GET 0x00010001
/* return the message, if any, that is presented to the user when password
modification through PAM is prohibited */
#define NSLCD_CONFIG_PAM_PASSWORD_PROHIBIT_MESSAGE 852
#define NSLCD_CONFIG_PAM_PASSWORD_PROHIBIT_MESSAGE 1
/* Email alias (/etc/aliases) NSS requests. The result values for a
single entry are:
STRING alias name
STRINGLIST alias rcpts */
#define NSLCD_ACTION_ALIAS_BYNAME 4001
#define NSLCD_ACTION_ALIAS_ALL 4002
#define NSLCD_ACTION_ALIAS_BYNAME 0x00020001
#define NSLCD_ACTION_ALIAS_ALL 0x00020008
/* Ethernet address/name mapping NSS requests. The result values for a
single entry are:
STRING ether name
TYPE(uint8_t[6]) ether address */
#define NSLCD_ACTION_ETHER_BYNAME 3001
#define NSLCD_ACTION_ETHER_BYETHER 3002
#define NSLCD_ACTION_ETHER_ALL 3005
#define NSLCD_ACTION_ETHER_BYNAME 0x00030001
#define NSLCD_ACTION_ETHER_BYETHER 0x00030002
#define NSLCD_ACTION_ETHER_ALL 0x00030008
/* Group and group membership related NSS requests. The result values
for a single entry are:
STRING group name
STRING group password
TYPE(gid_t) group id
INT32 group id
STRINGLIST members (usernames) of the group
(not that the BYMEMER call returns an emtpy members list) */
#define NSLCD_ACTION_GROUP_BYNAME 5001
#define NSLCD_ACTION_GROUP_BYGID 5002
#define NSLCD_ACTION_GROUP_BYMEMBER 5003
#define NSLCD_ACTION_GROUP_ALL 5004
#define NSLCD_ACTION_GROUP_BYNAME 0x00040001
#define NSLCD_ACTION_GROUP_BYGID 0x00040002
#define NSLCD_ACTION_GROUP_BYMEMBER 0x00040006
#define NSLCD_ACTION_GROUP_ALL 0x00040008
/* Hostname (/etc/hosts) lookup NSS requests. The result values
for an entry are:
STRING host name
STRINGLIST host aliases
ADDRESSLIST host addresses */
#define NSLCD_ACTION_HOST_BYNAME 6001
#define NSLCD_ACTION_HOST_BYADDR 6002
#define NSLCD_ACTION_HOST_ALL 6005
#define NSLCD_ACTION_HOST_BYNAME 0x00050001
#define NSLCD_ACTION_HOST_BYADDR 0x00050002
#define NSLCD_ACTION_HOST_ALL 0x00050008
/* Netgroup NSS request return a number of results. Result values
can be either a reference to another netgroup:
/* Netgroup NSS result entries contain a number of parts. A result entry
starts with:
STRING netgroup name
followed by zero or more references to other netgroups or netgroup
triples. A reference to another netgroup looks like:
INT32 NSLCD_NETGROUP_TYPE_NETGROUP
STRING other netgroup name
or a netgroup triple:
A a netgroup triple looks like:
INT32 NSLCD_NETGROUP_TYPE_TRIPLE
STRING host
STRING user
STRING domain */
#define NSLCD_ACTION_NETGROUP_BYNAME 12001
#define NSLCD_NETGROUP_TYPE_NETGROUP 123
#define NSLCD_NETGROUP_TYPE_TRIPLE 456
STRING domain
A netgroup result entry is terminated by:
INT32 NSLCD_NETGROUP_TYPE_END
*/
#define NSLCD_ACTION_NETGROUP_BYNAME 0x00060001
#define NSLCD_ACTION_NETGROUP_ALL 0x00060008
#define NSLCD_NETGROUP_TYPE_NETGROUP 1
#define NSLCD_NETGROUP_TYPE_TRIPLE 2
#define NSLCD_NETGROUP_TYPE_END 3
/* Network name (/etc/networks) NSS requests. Result values for a single
entry are:
STRING network name
STRINGLIST network aliases
ADDRESSLIST network addresses */
#define NSLCD_ACTION_NETWORK_BYNAME 8001
#define NSLCD_ACTION_NETWORK_BYADDR 8002
#define NSLCD_ACTION_NETWORK_ALL 8005
#define NSLCD_ACTION_NETWORK_BYNAME 0x00070001
#define NSLCD_ACTION_NETWORK_BYADDR 0x00070002
#define NSLCD_ACTION_NETWORK_ALL 0x00070008
/* User account (/etc/passwd) NSS requests. Result values are:
STRING user name
STRING user password
TYPE(uid_t) user id
TYPE(gid_t) group id
INT32 user id
INT32 group id
STRING gecos information
STRING home directory
STRING login shell */
#define NSLCD_ACTION_PASSWD_BYNAME 1001
#define NSLCD_ACTION_PASSWD_BYUID 1002
#define NSLCD_ACTION_PASSWD_ALL 1004
#define NSLCD_ACTION_PASSWD_BYNAME 0x00080001
#define NSLCD_ACTION_PASSWD_BYUID 0x00080002
#define NSLCD_ACTION_PASSWD_ALL 0x00080008
/* Protocol information requests. Result values are:
STRING protocol name
STRINGLIST protocol aliases
INT32 protocol number */
#define NSLCD_ACTION_PROTOCOL_BYNAME 9001
#define NSLCD_ACTION_PROTOCOL_BYNUMBER 9002
#define NSLCD_ACTION_PROTOCOL_ALL 9003
#define NSLCD_ACTION_PROTOCOL_BYNAME 0x00090001
#define NSLCD_ACTION_PROTOCOL_BYNUMBER 0x00090002
#define NSLCD_ACTION_PROTOCOL_ALL 0x00090008
/* RPC information requests. Result values are:
STRING rpc name
STRINGLIST rpc aliases
INT32 rpc number */
#define NSLCD_ACTION_RPC_BYNAME 10001
#define NSLCD_ACTION_RPC_BYNUMBER 10002
#define NSLCD_ACTION_RPC_ALL 10003
#define NSLCD_ACTION_RPC_BYNAME 0x000a0001
#define NSLCD_ACTION_RPC_BYNUMBER 0x000a0002
#define NSLCD_ACTION_RPC_ALL 0x000a0008
/* Service (/etc/services) information requests. Result values are:
/* Service (/etc/services) information requests. The BYNAME and BYNUMBER
requests contain an extra protocol string in the request which, if not
blank, will filter the services by this protocol. Result values are:
STRING service name
STRINGLIST service aliases
INT32 service (port) number
STRING service protocol */
#define NSLCD_ACTION_SERVICE_BYNAME 11001
#define NSLCD_ACTION_SERVICE_BYNUMBER 11002
#define NSLCD_ACTION_SERVICE_ALL 11005
#define NSLCD_ACTION_SERVICE_BYNAME 0x000b0001
#define NSLCD_ACTION_SERVICE_BYNUMBER 0x000b0002
#define NSLCD_ACTION_SERVICE_ALL 0x000b0008
/* Extended user account (/etc/shadow) information requests. Result
values for a single entry are:
@ -187,69 +195,95 @@
INT32 inact
INT32 expire
INT32 flag */
#define NSLCD_ACTION_SHADOW_BYNAME 2001
#define NSLCD_ACTION_SHADOW_ALL 2005
#define NSLCD_ACTION_SHADOW_BYNAME 0x000c0001
#define NSLCD_ACTION_SHADOW_ALL 0x000c0008
/* PAM-related requests. The request parameters for all these requests
begin with:
STRING user name
STRING DN (if value is known already, otherwise empty)
STRING service name
all requests, except the SESSION requests start the result value with:
STRING user name (cannonical name)
STRING DN (can be used to speed up requests)
Some functions may return an authorisation message. This message, if
supplied will be used by the PAM module instead of a message that is
generated by the PAM module itself. */
STRING ruser
STRING rhost
STRING tty
If the user is not known in LDAP no result may be returned (immediately
return NSLCD_RESULT_END instead of a PAM error code). */
/* PAM authentication check request. The extra request values are:
STRING password
and the result value ends with:
and the result value consists of:
INT32 authc NSLCD_PAM_* result code
STRING user name (the cannonical user name)
INT32 authz NSLCD_PAM_* result code
STRING authorisation error message
If the username is empty in this request an attempt is made to
authenticate as the administrator (set using rootpwmoddn). The returned DN
is that of the administrator. */
#define NSLCD_ACTION_PAM_AUTHC 20001
authenticate as the administrator (set using rootpwmoddn).
Some authorisation checks are already done during authentication so the
response also includes authorisation information. */
#define NSLCD_ACTION_PAM_AUTHC 0x000d0001
/* PAM authorisation check request. The extra request values are:
STRING ruser
STRING rhost
STRING tty
and the result value ends with:
/* PAM authorisation check request. The result value consists of:
INT32 authz NSLCD_PAM_* result code
STRING authorisation error message */
#define NSLCD_ACTION_PAM_AUTHZ 20002
STRING authorisation error message
The authentication check may have already returned some authorisation
information. The authorisation error message, if supplied, will be used
by the PAM module instead of a message that is generated by the PAM
module itself. */
#define NSLCD_ACTION_PAM_AUTHZ 0x000d0002
/* PAM session open and close requests. These requests have the following
extra request values:
STRING tty
STRING rhost
STRING ruser
INT32 session id (ignored for SESS_O)
and these calls only return the session ID:
INT32 session id
The SESS_C must contain the ID that is retured by SESS_O to close the
correct session. */
#define NSLCD_ACTION_PAM_SESS_O 20003
#define NSLCD_ACTION_PAM_SESS_C 20004
/* PAM session open request. The result value consists of:
STRING session id
This session id may be used to close this session with. */
#define NSLCD_ACTION_PAM_SESS_O 0x000d0003
/* PAM session close request. This request has the following
extra request value:
STRING session id
and this calls only returns an empty response value. */
#define NSLCD_ACTION_PAM_SESS_C 0x000d0004
/* PAM password modification request. This requests has the following extra
request values:
STRING old password
STRING new password
INT32 asroot: 0=oldpasswd is user passwd, 1=oldpasswd is root passwd
STRING old password
STRING new password
and returns there extra result values:
INT32 authz NSLCD_PAM_* result code
STRING authorisation error message
In this request the DN may be set to the administrator's DN. In this
case old password should be the administrator's password. This allows
the administrator to change any user's password. */
#define NSLCD_ACTION_PAM_PWMOD 20005
INT32 NSLCD_PAM_* result code
STRING error message */
#define NSLCD_ACTION_PAM_PWMOD 0x000d0005
/* User information change request. This request allows one to change
their full name and other information. The request parameters for this
request are:
STRING user name
INT32 asroot: 0=passwd is user passwd, 1=passwd is root passwd
STRING password
followed by one or more of the below, terminated by NSLCD_USERMOD_END
INT32 NSLCD_USERMOD_*
STRING new value
the response consists of one or more of the entries below, terminated
by NSLCD_USERMOD_END:
INT32 NSLCD_USERMOD_*
STRING response
(if the response is blank, the change went OK, otherwise the string
contains an error message)
*/
#define NSLCD_ACTION_USERMOD 0x000e0001
/* These are the possible values for the NSLCD_ACTION_USERMOD operation
above. */
#define NSLCD_USERMOD_END 0 /* end of change values */
#define NSLCD_USERMOD_RESULT 1 /* global result value */
#define NSLCD_USERMOD_FULLNAME 2 /* full name */
#define NSLCD_USERMOD_ROOMNUMBER 3 /* room number */
#define NSLCD_USERMOD_WORKPHONE 4 /* office phone number */
#define NSLCD_USERMOD_HOMEPHONE 5 /* home phone number */
#define NSLCD_USERMOD_OTHER 6 /* other info */
#define NSLCD_USERMOD_HOMEDIR 7 /* home directory */
#define NSLCD_USERMOD_SHELL 8 /* login shell */
/* Request result codes. */
#define NSLCD_RESULT_BEGIN 0
#define NSLCD_RESULT_END 3
#define NSLCD_RESULT_BEGIN 1
#define NSLCD_RESULT_END 2
/* Partial list of PAM result codes. */
#define NSLCD_PAM_SUCCESS 0 /* everything ok */

View file

@ -2,7 +2,7 @@
tio.c - timed io functions
This file is part of the nss-pam-ldapd library.
Copyright (C) 2007, 2008, 2010, 2011, 2012 Arthur de Jong
Copyright (C) 2007-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
@ -20,7 +20,6 @@
02110-1301 USA
*/
//#include "config.h"
#include "portable.h"
#ifdef HAVE_STDINT_H
@ -37,6 +36,7 @@
#include <stdio.h>
#include <limits.h>
#include <poll.h>
#include <time.h>
#include "tio.h"
@ -76,124 +76,117 @@ struct tio_fileinfo {
#endif /* DEBUG_TIO_STATS */
};
/* build a timeval for comparison to when the operation should be finished */
static inline void tio_get_deadline(struct timeval *deadline,int timeout)
{
if (gettimeofday(deadline,NULL))
{
/* just blank it in case of errors */
deadline->tv_sec=0;
deadline->tv_usec=0;
return;
}
deadline->tv_sec+=timeout/1000;
deadline->tv_sec+=(timeout%1000)*1000;
}
/* some older versions of Solaris don't provide CLOCK_MONOTONIC but do have
a CLOCK_HIGHRES that has the same properties we need */
#ifndef CLOCK_MONOTONIC
#ifdef CLOCK_HIGHRES
#define CLOCK_MONOTONIC CLOCK_HIGHRES
#endif /* CLOCK_HIGHRES */
#endif /* not CLOCK_MONOTONIC */
/* update the timeout to the value that is remaining before deadline
returns non-zero if there is no more time before the deadline */
static inline int tio_time_remaining(const struct timeval *deadline)
/* update the timeout to the value that is remaining before the deadline
returns the number of milliseconds before the deadline (or a negative
value of the deadline has expired) */
static inline int tio_time_remaining(struct timespec *deadline, int timeout)
{
struct timeval tv;
/* get the current time */
if (gettimeofday(&tv,NULL))
struct timespec tv;
/* if this is the first call, set the deadline and return the full time */
if ((deadline->tv_sec == 0) && (deadline->tv_nsec == 0))
{
/* 1 second default if gettimeofday() is broken */
return 1000;
if (clock_gettime(CLOCK_MONOTONIC, deadline) == 0)
{
deadline->tv_sec += timeout / 1000;
deadline->tv_nsec += (timeout % 1000) * 1000000;
}
return timeout;
}
/* calculate time remaining in miliseconds */
return (deadline->tv_sec-tv.tv_sec)*1000 + (deadline->tv_usec-tv.tv_usec)/1000;
/* get the current time (fall back to full time on error) */
if (clock_gettime(CLOCK_MONOTONIC, &tv))
return timeout;
/* calculate time remaining in milliseconds */
return (deadline->tv_sec - tv.tv_sec) * 1000 +
(deadline->tv_nsec - tv.tv_nsec) / 1000000;
}
/* open a new TFILE based on the file descriptor */
TFILE *tio_fdopen(int fd,int readtimeout,int writetimeout,
size_t initreadsize,size_t maxreadsize,
size_t initwritesize,size_t maxwritesize)
TFILE *tio_fdopen(int fd, int readtimeout, int writetimeout,
size_t initreadsize, size_t maxreadsize,
size_t initwritesize, size_t maxwritesize)
{
struct tio_fileinfo *fp;
fp=(struct tio_fileinfo *)malloc(sizeof(struct tio_fileinfo));
if (fp==NULL)
fp = (struct tio_fileinfo *)malloc(sizeof(struct tio_fileinfo));
if (fp == NULL)
return NULL;
fp->fd=fd;
fp->fd = fd;
/* initialize read buffer */
fp->readbuffer.buffer=(uint8_t *)malloc(initreadsize);
if (fp->readbuffer.buffer==NULL)
fp->readbuffer.buffer = (uint8_t *)malloc(initreadsize);
if (fp->readbuffer.buffer == NULL)
{
free(fp);
return NULL;
}
fp->readbuffer.size=initreadsize;
fp->readbuffer.maxsize=maxreadsize;
fp->readbuffer.start=0;
fp->readbuffer.len=0;
fp->readbuffer.size = initreadsize;
fp->readbuffer.maxsize = maxreadsize;
fp->readbuffer.start = 0;
fp->readbuffer.len = 0;
/* initialize write buffer */
fp->writebuffer.buffer=(uint8_t *)malloc(initwritesize);
if (fp->writebuffer.buffer==NULL)
fp->writebuffer.buffer = (uint8_t *)malloc(initwritesize);
if (fp->writebuffer.buffer == NULL)
{
free(fp->readbuffer.buffer);
free(fp);
return NULL;
}
fp->writebuffer.size=initwritesize;
fp->writebuffer.maxsize=maxwritesize;
fp->writebuffer.start=0;
fp->writebuffer.len=0;
fp->writebuffer.size = initwritesize;
fp->writebuffer.maxsize = maxwritesize;
fp->writebuffer.start = 0;
fp->writebuffer.len = 0;
/* initialize other attributes */
fp->readtimeout=readtimeout;
fp->writetimeout=writetimeout;
fp->read_resettable=0;
fp->readtimeout = readtimeout;
fp->writetimeout = writetimeout;
fp->read_resettable = 0;
#ifdef DEBUG_TIO_STATS
fp->byteswritten=0;
fp->bytesread=0;
fp->byteswritten = 0;
fp->bytesread = 0;
#endif /* DEBUG_TIO_STATS */
return fp;
}
/* wait for any activity on the specified file descriptor using
the specified deadline */
static int tio_wait(TFILE *fp,int readfd,const struct timeval *deadline)
static int tio_wait(int fd, short events, int timeout,
struct timespec *deadline)
{
int timeout;
int t;
struct pollfd fds[1];
int rv;
while (1)
{
fds[0].fd = fd;
fds[0].events = events;
/* figure out the time we need to wait */
if ((timeout=tio_time_remaining(deadline))<0)
if ((t = tio_time_remaining(deadline, timeout)) < 0)
{
errno=ETIME;
errno = ETIME;
return -1;
}
/* sanitiy check for moving clock */
if (t > timeout)
t = timeout;
/* wait for activity */
if (readfd)
{
fds[0].fd=fp->fd;
fds[0].events=POLLIN;
/* santiy check for moving clock */
if (timeout>fp->readtimeout)
timeout=fp->readtimeout;
}
else
{
fds[0].fd=fp->fd;
fds[0].events=POLLOUT;
/* santiy check for moving clock */
if (timeout>fp->writetimeout)
timeout=fp->writetimeout;
}
rv=poll(fds,1,timeout);
if (rv>0)
rv = poll(fds, 1, t);
if (rv > 0)
return 0; /* we have activity */
else if (rv==0)
else if (rv == 0)
{
/* no file descriptors were available within the specified time */
errno=ETIME;
errno = ETIME;
return -1;
}
else if (errno!=EINTR)
else if ((errno != EINTR) && (errno != EAGAIN))
/* some error ocurred */
return -1;
/* we just try again on EINTR */
/* we just try again on EINTR or EAGAIN */
}
}
@ -201,93 +194,92 @@ static int tio_wait(TFILE *fp,int readfd,const struct timeval *deadline)
if no data was read in the specified time an error is returned */
int tio_read(TFILE *fp, void *buf, size_t count)
{
struct timeval deadline;
struct timespec deadline = {0, 0};
int rv;
uint8_t *tmp;
size_t newsz;
size_t len;
/* have a more convenient storage type for the buffer */
uint8_t *ptr=(uint8_t *)buf;
/* build a time by which we should be finished */
tio_get_deadline(&deadline,fp->readtimeout);
uint8_t *ptr = (uint8_t *)buf;
/* loop until we have returned all the needed data */
while (1)
{
/* check if we have enough data in the buffer */
if (fp->readbuffer.len >= count)
{
if (count>0)
if (count > 0)
{
if (ptr!=NULL)
memcpy(ptr,fp->readbuffer.buffer+fp->readbuffer.start,count);
if (ptr != NULL)
memcpy(ptr, fp->readbuffer.buffer + fp->readbuffer.start, count);
/* adjust buffer position */
fp->readbuffer.start+=count;
fp->readbuffer.len-=count;
fp->readbuffer.start += count;
fp->readbuffer.len -= count;
}
return 0;
}
/* empty what we have and continue from there */
if (fp->readbuffer.len>0)
if (fp->readbuffer.len > 0)
{
if (ptr!=NULL)
if (ptr != NULL)
{
memcpy(ptr,fp->readbuffer.buffer+fp->readbuffer.start,fp->readbuffer.len);
ptr+=fp->readbuffer.len;
memcpy(ptr, fp->readbuffer.buffer + fp->readbuffer.start,
fp->readbuffer.len);
ptr += fp->readbuffer.len;
}
count-=fp->readbuffer.len;
fp->readbuffer.start+=fp->readbuffer.len;
fp->readbuffer.len=0;
count -= fp->readbuffer.len;
fp->readbuffer.start += fp->readbuffer.len;
fp->readbuffer.len = 0;
}
/* after this point until the read fp->readbuffer.len is 0 */
if (!fp->read_resettable)
{
/* the stream is not resettable, re-use the buffer */
fp->readbuffer.start=0;
fp->readbuffer.start = 0;
}
else if (fp->readbuffer.start>=(fp->readbuffer.size-4))
else if (fp->readbuffer.start >= (fp->readbuffer.size - 4))
{
/* buffer is running empty, try to grow buffer */
if (fp->readbuffer.size<fp->readbuffer.maxsize)
if (fp->readbuffer.size < fp->readbuffer.maxsize)
{
newsz=fp->readbuffer.size*2;
if (newsz>fp->readbuffer.maxsize)
newsz=fp->readbuffer.maxsize;
tmp=realloc(fp->readbuffer.buffer,newsz);
if (tmp!=NULL)
newsz = fp->readbuffer.size * 2;
if (newsz > fp->readbuffer.maxsize)
newsz = fp->readbuffer.maxsize;
tmp = realloc(fp->readbuffer.buffer, newsz);
if (tmp != NULL)
{
fp->readbuffer.buffer=tmp;
fp->readbuffer.size=newsz;
fp->readbuffer.buffer = tmp;
fp->readbuffer.size = newsz;
}
}
/* if buffer still does not contain enough room, clear resettable */
if (fp->readbuffer.start>=(fp->readbuffer.size-4))
if (fp->readbuffer.start >= (fp->readbuffer.size - 4))
{
fp->readbuffer.start=0;
fp->read_resettable=0;
fp->readbuffer.start = 0;
fp->read_resettable = 0;
}
}
/* wait until we have input */
if (tio_wait(fp,1,&deadline))
if (tio_wait(fp->fd, POLLIN, fp->readtimeout, &deadline))
return -1;
/* read the input in the buffer */
len=fp->readbuffer.size-fp->readbuffer.start;
len = fp->readbuffer.size - fp->readbuffer.start;
#ifdef SSIZE_MAX
if (len>SSIZE_MAX)
len=SSIZE_MAX;
if (len > SSIZE_MAX)
len = SSIZE_MAX;
#endif /* SSIZE_MAX */
rv=read(fp->fd,fp->readbuffer.buffer+fp->readbuffer.start,len);
rv = read(fp->fd, fp->readbuffer.buffer + fp->readbuffer.start, len);
/* check for errors */
if (rv==0)
if (rv == 0)
{
errno=ECONNRESET;
errno = ECONNRESET;
return -1;
}
else if ((rv<0)&&(errno!=EINTR)&&(errno!=EAGAIN))
return -1; /* something went wrong with the read */
/* skip the read part in the buffer */
fp->readbuffer.len=rv;
else if ((rv < 0) && (errno != EINTR) && (errno != EAGAIN))
return -1; /* something went wrong with the read */
else if (rv > 0)
fp->readbuffer.len = rv; /* skip the read part in the buffer */
#ifdef DEBUG_TIO_STATS
fp->bytesread+=rv;
fp->bytesread += rv;
#endif /* DEBUG_TIO_STATS */
}
}
@ -295,45 +287,37 @@ int tio_read(TFILE *fp, void *buf, size_t count)
/* Read and discard the specified number of bytes from the stream. */
int tio_skip(TFILE *fp, size_t count)
{
return tio_read(fp,NULL,count);
return tio_read(fp, NULL, count);
}
/* Read all available data from the stream and empty the read buffer. */
int tio_skipall(TFILE *fp)
int tio_skipall(TFILE *fp, int timeout)
{
struct pollfd fds[1];
struct timespec deadline = {0, 0};
int rv;
size_t len;
/* clear the read buffer */
fp->readbuffer.start=0;
fp->readbuffer.len=0;
fp->read_resettable=0;
fp->readbuffer.start = 0;
fp->readbuffer.len = 0;
fp->read_resettable = 0;
/* read until we can't read no more */
len=fp->readbuffer.size;
len = fp->readbuffer.size;
#ifdef SSIZE_MAX
if (len>SSIZE_MAX)
len=SSIZE_MAX;
if (len > SSIZE_MAX)
len = SSIZE_MAX;
#endif /* SSIZE_MAX */
while (1)
{
/* see if any data is available */
fds[0].fd=fp->fd;
fds[0].events=POLLIN;
rv=poll(fds,1,0);
/* check the poll() result */
if (rv==0)
return 0; /* no file descriptor ready */
if ((rv<0)&&((errno==EINTR)||(errno==EAGAIN)))
continue; /* interrupted, try again */
if (rv<0)
return -1; /* something went wrong */
/* wait until we have input */
if (tio_wait(fp->fd, POLLIN, timeout, &deadline))
return -1;
/* read data from the stream */
rv=read(fp->fd,fp->readbuffer.buffer,len);
if (rv==0)
rv = read(fp->fd, fp->readbuffer.buffer, len);
if (rv == 0)
return 0; /* end-of-file */
if ((rv<0)&&(errno==EWOULDBLOCK))
if ((rv < 0) && (errno == EWOULDBLOCK))
return 0; /* we've ready everything we can without blocking */
if ((rv<0)&&(errno!=EINTR)&&(errno!=EAGAIN))
if ((rv < 0) && (errno != EINTR) && (errno != EAGAIN))
return -1; /* something went wrong with the read */
}
}
@ -345,46 +329,50 @@ static int tio_writebuf(TFILE *fp)
int rv;
/* write the buffer */
#ifdef MSG_NOSIGNAL
rv=send(fp->fd,fp->writebuffer.buffer+fp->writebuffer.start,fp->writebuffer.len,MSG_NOSIGNAL);
rv = send(fp->fd, fp->writebuffer.buffer + fp->writebuffer.start,
fp->writebuffer.len, MSG_NOSIGNAL);
#else /* not MSG_NOSIGNAL */
/* on platforms that cannot use send() with masked signals, we change the
signal mask and change it back after the write (note that there is a
race condition here) */
struct sigaction act,oldact;
struct sigaction act, oldact;
/* set up sigaction */
memset(&act,0,sizeof(struct sigaction));
act.sa_sigaction=NULL;
act.sa_handler=SIG_IGN;
memset(&act, 0, sizeof(struct sigaction));
act.sa_sigaction = NULL;
act.sa_handler = SIG_IGN;
sigemptyset(&act.sa_mask);
act.sa_flags=SA_RESTART;
act.sa_flags = SA_RESTART;
/* ignore SIGPIPE */
if (sigaction(SIGPIPE,&act,&oldact)!=0)
if (sigaction(SIGPIPE, &act, &oldact) != 0)
return -1; /* error setting signal handler */
/* write the buffer */
rv=write(fp->fd,fp->writebuffer.buffer+fp->writebuffer.start,fp->writebuffer.len);
rv = write(fp->fd, fp->writebuffer.buffer + fp->writebuffer.start,
fp->writebuffer.len);
/* restore the old handler for SIGPIPE */
if (sigaction(SIGPIPE,&oldact,NULL)!=0)
if (sigaction(SIGPIPE, &oldact, NULL) != 0)
return -1; /* error restoring signal handler */
#endif
/* check for errors */
if ((rv==0)||((rv<0)&&(errno!=EINTR)&&(errno!=EAGAIN)))
if ((rv == 0) || ((rv < 0) && (errno != EINTR) && (errno != EAGAIN)))
return -1; /* something went wrong with the write */
/* skip the written part in the buffer */
if (rv>0)
if (rv > 0)
{
fp->writebuffer.start+=rv;
fp->writebuffer.len-=rv;
fp->writebuffer.start += rv;
fp->writebuffer.len -= rv;
#ifdef DEBUG_TIO_STATS
fp->byteswritten+=rv;
fp->byteswritten += rv;
#endif /* DEBUG_TIO_STATS */
/* reset start if len is 0 */
if (fp->writebuffer.len==0)
fp->writebuffer.start=0;
if (fp->writebuffer.len == 0)
fp->writebuffer.start = 0;
/* move contents of the buffer to the front if it will save enough room */
if (fp->writebuffer.start>=(fp->writebuffer.size/4))
if (fp->writebuffer.start >= (fp->writebuffer.size / 4))
{
memmove(fp->writebuffer.buffer,fp->writebuffer.buffer+fp->writebuffer.start,fp->writebuffer.len);
fp->writebuffer.start=0;
memmove(fp->writebuffer.buffer,
fp->writebuffer.buffer + fp->writebuffer.start,
fp->writebuffer.len);
fp->writebuffer.start = 0;
}
}
return 0;
@ -393,14 +381,12 @@ static int tio_writebuf(TFILE *fp)
/* write all the data in the buffer to the stream */
int tio_flush(TFILE *fp)
{
struct timeval deadline;
/* build a time by which we should be finished */
tio_get_deadline(&deadline,fp->writetimeout);
struct timespec deadline = {0, 0};
/* loop until we have written our buffer */
while (fp->writebuffer.len > 0)
{
/* wait until we can write */
if (tio_wait(fp,0,&deadline))
if (tio_wait(fp->fd, POLLOUT, fp->writetimeout, &deadline))
return -1;
/* write one block */
if (tio_writebuf(fp))
@ -415,16 +401,16 @@ static int tio_flush_nonblock(TFILE *fp)
{
struct pollfd fds[1];
int rv;
/* wait for activity */
fds[0].fd=fp->fd;
fds[0].events=POLLOUT;
rv=poll(fds,1,0);
/* see if we can write without blocking */
fds[0].fd = fp->fd;
fds[0].events = POLLOUT;
rv = poll(fds, 1, 0);
/* check if any file descriptors were ready (timeout) or we were
interrupted */
if ((rv==0)||((rv<0)&&(errno==EINTR)))
if ((rv == 0) || ((rv < 0) && ((errno == EINTR) || (errno == EAGAIN))))
return 0;
/* any other errors? */
if (rv<0)
if (rv < 0)
return -1;
/* so file descriptor will accept writes */
return tio_writebuf(fp);
@ -435,44 +421,46 @@ int tio_write(TFILE *fp, const void *buf, size_t count)
size_t fr;
uint8_t *tmp;
size_t newsz;
const uint8_t *ptr=(const uint8_t *)buf;
const uint8_t *ptr = (const uint8_t *)buf;
/* keep filling the buffer until we have bufferred everything */
while (count>0)
while (count > 0)
{
/* figure out free size in buffer */
fr=fp->writebuffer.size-(fp->writebuffer.start+fp->writebuffer.len);
fr = fp->writebuffer.size - (fp->writebuffer.start + fp->writebuffer.len);
if (count <= fr)
{
/* the data fits in the buffer */
memcpy(fp->writebuffer.buffer+fp->writebuffer.start+fp->writebuffer.len,ptr,count);
fp->writebuffer.len+=count;
memcpy(fp->writebuffer.buffer + fp->writebuffer.start +
fp->writebuffer.len, ptr, count);
fp->writebuffer.len += count;
return 0;
}
else if (fr > 0)
{
/* fill the buffer with data that will fit */
memcpy(fp->writebuffer.buffer+fp->writebuffer.start+fp->writebuffer.len,ptr,fr);
fp->writebuffer.len+=fr;
ptr+=fr;
count-=fr;
memcpy(fp->writebuffer.buffer + fp->writebuffer.start +
fp->writebuffer.len, ptr, fr);
fp->writebuffer.len += fr;
ptr += fr;
count -= fr;
}
/* try to flush some of the data that is in the buffer */
if (tio_flush_nonblock(fp))
return -1;
/* if we have room now, try again */
if (fp->writebuffer.size>(fp->writebuffer.start+fp->writebuffer.len))
if (fp->writebuffer.size > (fp->writebuffer.start + fp->writebuffer.len))
continue;
/* try to grow the buffer */
if (fp->writebuffer.size<fp->writebuffer.maxsize)
if (fp->writebuffer.size < fp->writebuffer.maxsize)
{
newsz=fp->writebuffer.size*2;
if (newsz>fp->writebuffer.maxsize)
newsz=fp->writebuffer.maxsize;
tmp=realloc(fp->writebuffer.buffer,newsz);
if (tmp!=NULL)
newsz = fp->writebuffer.size * 2;
if (newsz > fp->writebuffer.maxsize)
newsz = fp->writebuffer.maxsize;
tmp = realloc(fp->writebuffer.buffer, newsz);
if (tmp != NULL)
{
fp->writebuffer.buffer=tmp;
fp->writebuffer.size=newsz;
fp->writebuffer.buffer = tmp;
fp->writebuffer.size = newsz;
continue; /* try again */
}
}
@ -487,15 +475,18 @@ int tio_close(TFILE *fp)
{
int retv;
/* write any buffered data */
retv=tio_flush(fp);
retv = tio_flush(fp);
#ifdef DEBUG_TIO_STATS
/* dump statistics to stderr */
fprintf(stderr,"DEBUG_TIO_STATS READ=%d WRITTEN=%d\n",fp->bytesread,fp->byteswritten);
fprintf(stderr, "DEBUG_TIO_STATS READ=%d WRITTEN=%d\n", fp->bytesread,
fp->byteswritten);
#endif /* DEBUG_TIO_STATS */
/* close file descriptor */
if (close(fp->fd))
retv=-1;
retv = -1;
/* free any allocated buffers */
memset(fp->readbuffer.buffer, 0, fp->readbuffer.size);
memset(fp->writebuffer.buffer, 0, fp->writebuffer.size);
free(fp->readbuffer.buffer);
free(fp->writebuffer.buffer);
/* free the tio struct itself */
@ -507,13 +498,14 @@ int tio_close(TFILE *fp)
void tio_mark(TFILE *fp)
{
/* move any data in the buffer to the start of the buffer */
if ((fp->readbuffer.start>0)&&(fp->readbuffer.len>0))
if ((fp->readbuffer.start > 0) && (fp->readbuffer.len > 0))
{
memmove(fp->readbuffer.buffer,fp->readbuffer.buffer+fp->readbuffer.start,fp->readbuffer.len);
fp->readbuffer.start=0;
memmove(fp->readbuffer.buffer,
fp->readbuffer.buffer + fp->readbuffer.start, fp->readbuffer.len);
fp->readbuffer.start = 0;
}
/* mark the stream as resettable */
fp->read_resettable=1;
fp->read_resettable = 1;
}
int tio_reset(TFILE *fp)
@ -522,7 +514,7 @@ int tio_reset(TFILE *fp)
if (!fp->read_resettable)
return -1;
/* reset the buffer */
fp->readbuffer.len+=fp->readbuffer.start;
fp->readbuffer.start=0;
fp->readbuffer.len += fp->readbuffer.start;
fp->readbuffer.start = 0;
return 0;
}

View file

@ -2,7 +2,7 @@
tio.h - timed io functions
This file is part of the nss-pam-ldapd library.
Copyright (C) 2007, 2008, 2010, 2012 Arthur de Jong
Copyright (C) 2007, 2008, 2010, 2012, 2013 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
@ -47,22 +47,22 @@ typedef struct tio_fileinfo TFILE;
/* Open a new TFILE based on the file descriptor. The timeout is set for any
operation (value in milliseconds). */
TFILE *tio_fdopen(int fd,int readtimeout,int writetimeout,
size_t initreadsize,size_t maxreadsize,
size_t initwritesize,size_t maxwritesize)
TFILE *tio_fdopen(int fd, int readtimeout, int writetimeout,
size_t initreadsize, size_t maxreadsize,
size_t initwritesize, size_t maxwritesize)
LIKE_MALLOC MUST_USE;
/* Read the specified number of bytes from the stream. */
int tio_read(TFILE *fp,void *buf,size_t count);
int tio_read(TFILE *fp, void *buf, size_t count);
/* Read and discard the specified number of bytes from the stream. */
int tio_skip(TFILE *fp,size_t count);
int tio_skip(TFILE *fp, size_t count);
/* Read all available data from the stream and empty the read buffer. */
int tio_skipall(TFILE *fp);
int tio_skipall(TFILE *fp, int timeout);
/* Write the specified buffer to the stream. */
int tio_write(TFILE *fp,const void *buf,size_t count);
int tio_write(TFILE *fp, const void *buf, size_t count);
/* Write out all buffered data to the stream. */
int tio_flush(TFILE *fp);