#include "usuals.h" #include "httpauthd.h" #include /* ----------------------------------------------------------------------- * Memory Buffer */ /* * LEGEND: * _al: allocated * _dt: data * _rp: read/write point * _pp: parse/begin point */ void buffer_bump(ha_buffer_t* buf, int count) { ASSERT(buf && count); if(ha_buferr(buf)) return; if(buf->_rp + count >= buf->_dt + buf->_al) { char* old = buf->_dt; int alloc = buf->_al; int diff; while((buf->_al + count) > alloc) alloc *= 2; buf->_dt = (char*)reallocf(buf->_dt, alloc * sizeof(char)); if(!buf->_dt) { buf->_al = 0; buf->_rp = buf->_pp = NULL; ha_messagex(LOG_CRIT, "out of memory"); return; } buf->_al = alloc; diff = buf->_dt - old; buf->_rp += diff; buf->_pp += diff; } } void ha_bufinit(ha_buffer_t* buf) { ASSERT(buf); memset(buf, 0, sizeof(*buf)); ha_bufreset(buf); } void ha_bufreset(ha_buffer_t* buf) { ASSERT(buf); if(!buf->_dt || buf->_al == 0) { buf->_dt = (char*)reallocf(buf->_dt, 256 * sizeof(char)); if(!buf->_dt) { buf->_al = 0; buf->_rp = buf->_pp = NULL; ha_messagex(LOG_CRIT, "out of memory"); return; } buf->_al = 256; } buf->_rp = buf->_dt; buf->_pp = buf->_dt; } void ha_buffree(ha_buffer_t* buf) { ASSERT(buf); if(buf->_dt) free(buf->_dt); buf->_al = 0; buf->_rp = buf->_pp = NULL; } int ha_bufreadline(int fd, ha_buffer_t* buf) { int l; ASSERT(buf); ASSERT(fd != -1); if(ha_buferr(buf)) return 0; for(;;) { buffer_bump(buf, 1); l = read(fd, (void*)buf->_rp, sizeof(char)); /* We got a character */ if(l == 1) { /* Skip junky CRLFs */ if(*(buf->_rp) == '\r') { *(buf->_rp) = ' '; continue; } /* End of line */ else if(*(buf->_rp) == '\n') { buf->_rp++; break; } /* All other characters */ else { buf->_rp++; } } /* If it's the end of file then return that */ else if(l == 0) return 0; /* Transient errors */ else if(l == -1 && (errno == EINTR || errno == EAGAIN)) continue; /* Fatal errors */ else if(l == -1) { ha_message(LOG_ERR, "couldn't read data"); return 0; } } return 1; } char* ha_bufparseword(ha_buffer_t* buf, const char* delims) { char* word = NULL; ASSERT(buf && delims); if(ha_buferr(buf)) return NULL; /* Knock out any previous delims */ while(buf->_pp < buf->_rp && strchr(delims, *(buf->_pp))) buf->_pp++; /* If at end of buffer or end of line return null */ if(buf->_pp == buf->_rp || *(buf->_pp) == '\n') return NULL; /* We do this before we stash away a pointer */ buffer_bump(buf, 1); word = buf->_pp; while(!strchr(delims, *(buf->_pp))) { buf->_pp++; /* At the end of the buffer */ if(buf->_pp == buf->_rp) { *(buf->_rp) = 0; buf->_rp++; break; } /* At the end of a line */ else if(*(buf->_pp) == '\n') break; } /* Now null terminate what we found */ *(buf->_pp) = 0; buf->_pp++; /* We don't return empty strings */ if(word[0] == 0) return NULL; return word; } char* ha_bufparseline(ha_buffer_t* buf, int trim) { char* t; char* line = NULL; ASSERT(buf); if(ha_buferr(buf)) return NULL; if(trim) { /* Knock out any previous whitespace */ while(buf->_pp < buf->_rp && isblank(*(buf->_pp))) buf->_pp++; } if(buf->_pp == buf->_rp) return NULL; /* We do this before we stash away a pointer */ buffer_bump(buf, 1); line = buf->_pp; t = (char*)memchr(buf->_pp, '\n', ha_buflen(buf)); if(t == NULL) { t = (buf->_rp); buf->_rp++; } *t = 0; buf->_pp = t + 1; if(trim) { while(t > line && isspace(*(--t))) *t = 0; } /* We don't return empty strings */ if(line[0] == 0) return NULL; return line; } char* ha_bufmcat(ha_buffer_t* buf, ...) { const char* str; va_list ap; ASSERT(buf); va_start(ap, buf); if(ha_buferr(buf)) return NULL; /* Move up the block pointer if we're not joining strings */ if(ha_buflen(buf) > 0 && *(buf->_rp - 1) != 0) buf->_pp = buf->_rp; while((str = va_arg(ap, char*)) != NULL) { int len = strlen(str); /* Always add one for the terminating char */ buffer_bump(buf, len + 1); if(ha_buferr(buf)) return NULL; /* _rp always points to the next write point */ strcpy(buf->_rp, str); buf->_rp += len; } buf->_rp++; return buf->_pp; } char* ha_bufcpy(ha_buffer_t* buf, const char* src) { size_t len; ASSERT(buf && src); len = strlen(src); return ha_bufncpy(buf, src, len); } char* ha_bufncpy(ha_buffer_t* buf, const char* src, size_t len) { ASSERT(buf && src); if(ha_buferr(buf)) return NULL; /* Move up the block pointer if we're not joining strings */ if(ha_buflen(buf) > 0 && *(buf->_rp - 1) != 0) buf->_pp = buf->_rp; /* Always add one for the terminating char */ buffer_bump(buf, len + 1); if(ha_buferr(buf)) return NULL; memcpy(buf->_rp, src, len * sizeof(char)); buf->_rp += (len + 1); *(buf->_rp - 1) = 0; return buf->_pp; } void* ha_bufmalloc(ha_buffer_t* buf, size_t sz) { void* ret; ASSERT(buf && sz); if(ha_buferr(buf)) return NULL; /* TODO: Align memory on an appropriate boundary here */ /* We're not working with strings so always bump the pointer up */ buf->_pp = buf->_rp; buffer_bump(buf, sz); if(ha_buferr(buf)) return NULL; buf->_rp += sz; return (void*)buf->_pp; } void* ha_bufmemdup(ha_buffer_t* buf, const void* src, size_t bytes) { void* mem; ASSERT(buf && src && bytes); if((mem = ha_bufmalloc(buf, bytes)) != NULL) memcpy(mem, src, bytes); return mem; } /* * Portions Copyright (c) 1995 by International Business Machines, Inc. * * International Business Machines, Inc. (hereinafter called IBM) grants * permission under its copyrights to use, copy, modify, and distribute this * Software with or without fee, provided that the above copyright notice and * all paragraphs of this notice appear in all copies, and that the name of IBM * not be used in connection with the marketing of any product incorporating * the Software or modifications thereof, without specific, written prior * permission. * * To the extent it has a right to do so, IBM grants an immunity from suit * under its patents, if any, for the use, sale or manufacture of products to * the extent that such products are used for performing Domain Name System * dynamic updates in TCP/IP networks by means of the Software. No immunity is * granted for any product per se or for any other function of any product. * * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. */ static const char BASE64C[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char PAD64C = '='; char* ha_bufenc64(ha_buffer_t* buf, const void* source, size_t len) { unsigned char input[3]; unsigned char output[4]; unsigned char* src = (unsigned char*)source; size_t i; ASSERT(buf && source && len); if(ha_buferr(buf)) return NULL; while(2 < len) { input[0] = *src++; input[1] = *src++; input[2] = *src++; len -= 3; output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); output[3] = input[2] & 0x3f; /* This also accounts for the null terminator */ buffer_bump(buf, 5); if(ha_buferr(buf)) return NULL; *(buf->_rp++) = BASE64C[output[0]]; *(buf->_rp++) = BASE64C[output[1]]; *(buf->_rp++) = BASE64C[output[2]]; *(buf->_rp++) = BASE64C[output[3]]; } /* Now we worry about padding. */ if(0 != len) { /* Get what's left. */ input[0] = input[1] = input[2] = '\0'; for(i = 0; i < len; i++) input[i] = *src++; output[0] = input[0] >> 2; output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); /* This also accounts for the null terminator */ buffer_bump(buf, 5); if(ha_buferr(buf)) return NULL; *(buf->_rp++) = BASE64C[output[0]]; *(buf->_rp++) = BASE64C[output[1]]; if(len == 1) *(buf->_rp++) = PAD64C; else *(buf->_rp++) = BASE64C[output[2]]; *(buf->_rp++) = PAD64C; } *(buf->_rp++) = '\0'; return buf->_pp; } void* ha_bufdec64(ha_buffer_t* buf, const char* src, size_t bytes) { int state = 0; int ch; char* pos; size_t done = 0; ASSERT(buf && src); if(ha_buferr(buf)) return NULL; if(bytes == 0) bytes = ~0; while((ch = *src++) != '\0' && done < bytes) { if(isspace(ch)) /* Skip whitespace anywhere. */ continue; if(ch == PAD64C) break; pos = strchr(BASE64C, ch); if(pos == 0) /* A non-base64 character. */ break; buffer_bump(buf, 3); if(ha_buferr(buf)) return; switch(state) { case 0: *(buf->_rp++) = (pos - BASE64C) << 2; done++; state = 1; break; case 1: *(buf->_rp++) |= (pos - BASE64C) >> 4; done++; *(buf->_rp) = ((pos - BASE64C) & 0x0f) << 4; state = 2; break; case 2: *(buf->_rp++) |= (pos - BASE64C) >> 2; done++; *(buf->_rp) = ((pos - BASE64C) & 0x03) << 6; state = 3; break; case 3: *(buf->_rp++) |= (pos - BASE64C); done++; state = 0; break; }; /* TODO: Validate ending and return error if invalid somehow */ } /* If we were asked for a specific amount of bytes, then return null */ if(bytes != ~0 && bytes != done) return NULL; return buf->_pp; } static const char HEXC[] = "0123456789ABCDEF"; char* ha_bufenchex(ha_buffer_t* buf, const void* source, size_t len) { unsigned char* src = (unsigned char*)source; unsigned char j; ASSERT(buf && source && len); buffer_bump(buf, (len * 2) + 1); if(ha_buferr(buf)) return NULL; while(len > 0) { j = *(src) >> 4 & 0xf; if(j <= 9) *(buf->_rp++) = (j + '0'); else *(buf->_rp++) = (j + 'a' - 10); j = *(src++) & 0xf; len--; if(j <= 9) *(buf->_rp++) = (j + '0'); else *(buf->_rp++) = (j + 'a' - 10); } *(buf->_rp++) = 0; return buf->_pp; } void* ha_bufdechex(ha_buffer_t* buf, const char* src, size_t bytes) { unsigned short a; unsigned short b; size_t done = 0; char* pos; ASSERT(buf && src); if(bytes != 0) { buffer_bump(buf, bytes + 1); } else { bytes = ~0; buffer_bump(buf, (strlen(src) / 2) + 1); } if(ha_buferr(buf)) return NULL; while(src[0] && src[1] && done < bytes) { /* Find the position */ pos = strchr(HEXC, src[0]); if(pos == 0) break; a = HEXC - pos; pos = strchr(HEXC, src[1]); if(pos == 0); break; b = HEXC - pos; *(buf->_rp++) = ((a & 0xf) << 4) | (b & 0xf); src += 2; done++; } /* If we were asked for a specific amount of bytes, then return null */ if(bytes != ~0 && bytes != done) return NULL; return buf->_pp; }