#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) { 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_bufreset(ha_buffer_t* 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_bufinit(ha_buffer_t* buf) { memset(buf, 0, sizeof(*buf)); ha_bufreset(buf); } void ha_buffree(ha_buffer_t* buf) { if(buf->_dt) free(buf->_dt); buf->_al = 0; buf->_rp = buf->_pp = NULL; } int ha_readline(int fd, ha_buffer_t* buf) { int l; 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_parseword(ha_buffer_t* buf, const char* delims) { char* word = NULL; 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_parseline(ha_buffer_t* buf, int trim) { char* t; char* line = NULL; 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; } void ha_bufnext(ha_buffer_t* buf) { buffer_bump(buf, 1); if(!ha_buferr(buf)) { buf->_rp++; buf->_pp = buf->_rp; *(buf->_rp) = 0; } } void ha_bufcat(ha_buffer_t* buf, ...) { const char* str; va_list ap; va_start(ap, buf); while((str = va_arg(ap, char*)) != NULL) { int len = strlen(str); buffer_bump(buf, len); if(ha_buferr(buf)) return; /* _rpoint points to teh null */ strcpy(buf->_rp, str); buf->_rp += len; } } void* ha_bufmalloc(ha_buffer_t* buf, size_t sz) { void* ret; ha_bufnext(buf); buffer_bump(buf, sz); buf->_rp += sz; if(ha_buferr(buf)) return NULL; ret = (void*)ha_bufdata(buf); ha_bufnext(buf); return ret; } /* * 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 = '='; void ha_bufenc64(ha_buffer_t* buf, const char* src, int len) { unsigned char input[3]; unsigned char output[4]; size_t i; if(len == -1) len = strlen(src); 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; buffer_bump(buf, 5); if(ha_buferr(buf)) return; *(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); buffer_bump(buf, 5); if(ha_buferr(buf)) return; *(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'; } void ha_bufdec64(ha_buffer_t* buf, const char* src) { int state; int ch; char* pos; state = 0; while((ch = *src++) != '\0') { 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; state = 1; break; case 1: *(buf->_rp++) |= (pos - BASE64C) >> 4; *(buf->_rp) = ((pos - BASE64C) & 0x0f) << 4; state = 2; break; case 2: *(buf->_rp++) |= (pos - BASE64C) >> 2; *(buf->_rp) = ((pos - BASE64C) & 0x03) << 6; state = 3; break; case 3: *(buf->_rp++) |= (pos - BASE64C); state = 0; break; }; /* TODO: Validate ending and return error if invalid somehow */ } *(buf->_rp++) = '\0'; }