diff options
-rw-r--r-- | common/buffer.c | 926 | ||||
-rw-r--r-- | common/compat.c | 28 | ||||
-rw-r--r-- | common/compat.h | 14 | ||||
-rw-r--r-- | common/hash.c | 544 | ||||
-rw-r--r-- | common/md5.c | 296 | ||||
-rw-r--r-- | common/md5.h | 6 | ||||
-rw-r--r-- | common/sha1.c | 190 | ||||
-rw-r--r-- | daemon/Makefile.am | 2 | ||||
-rw-r--r-- | daemon/basic.c | 48 | ||||
-rw-r--r-- | daemon/basic.h | 6 | ||||
-rw-r--r-- | daemon/bd.c | 171 | ||||
-rw-r--r-- | daemon/bd.h | 10 | ||||
-rw-r--r-- | daemon/digest.c | 822 | ||||
-rw-r--r-- | daemon/digest.h | 32 | ||||
-rw-r--r-- | daemon/httpauthd.c | 2021 | ||||
-rw-r--r-- | daemon/httpauthd.h | 137 | ||||
-rw-r--r-- | daemon/ldap.c | 200 | ||||
-rw-r--r-- | daemon/misc.c | 835 | ||||
-rw-r--r-- | daemon/ntlm.c | 1156 | ||||
-rw-r--r-- | daemon/simple.c | 82 | ||||
-rw-r--r-- | daemon/usuals.h | 6 | ||||
-rw-r--r-- | doc/protocol.txt | 16 |
22 files changed, 3777 insertions, 3771 deletions
diff --git a/common/buffer.c b/common/buffer.c index 5a77922..07fa059 100644 --- a/common/buffer.c +++ b/common/buffer.c @@ -31,399 +31,399 @@ typedef struct ha_buffer_internal { - char* end; - struct ha_buffer_internal* next; + char* end; + struct ha_buffer_internal* next; } internal_t; void buffer_bump(ha_buffer_t* buf, int count) { - int allocated; - internal_t* intl; - - ASSERT(buf && count); - - if(ha_buferr(buf)) - return; - - ASSERT(BUF_DELTA < BUF_INITIAL); - - /* Handle this common case first for efficiency */ - if(buf->_rp + (count + BUF_DELTA) < buf->_dt->end) - return; - - /* Now when in joins we let it go closer */ - if(BUF_IN_JOIN(buf) && (buf->_rp + count < buf->_dt->end)) - return; - - /* Okay now we know we have to extend */ - allocated = buf->_dt->end - (char*)(buf->_dt); - ASSERT(allocated > 0 && (allocated % BUF_INITIAL) == 0); - - /* Enlarge the size as much as needed */ - do - { - allocated *= 2; - } - while(allocated < count); - - ASSERT(sizeof(internal_t) < allocated); - intl = (internal_t*)malloc(allocated); - if(!intl) - { - ha_messagex(LOG_CRIT, "out of memory"); - buf->_dt = NULL; - buf->_pp = buf->_rp = NULL; - return; - } - else - { - void* beg = INTERNAL_DATA(intl); - intl->end = ((char*)(intl) + allocated); - intl->next = NULL; + int allocated; + internal_t* intl; + + ASSERT(buf && count); + + if(ha_buferr(buf)) + return; + + ASSERT(BUF_DELTA < BUF_INITIAL); + + /* Handle this common case first for efficiency */ + if(buf->_rp + (count + BUF_DELTA) < buf->_dt->end) + return; + + /* Now when in joins we let it go closer */ + if(BUF_IN_JOIN(buf) && (buf->_rp + count < buf->_dt->end)) + return; + + /* Okay now we know we have to extend */ + allocated = buf->_dt->end - (char*)(buf->_dt); + ASSERT(allocated > 0 && (allocated % BUF_INITIAL) == 0); + + /* Enlarge the size as much as needed */ + do + { + allocated *= 2; + } + while(allocated < count); + + ASSERT(sizeof(internal_t) < allocated); + intl = (internal_t*)malloc(allocated); + if(!intl) + { + ha_messagex(NULL, LOG_CRIT, "out of memory"); + buf->_dt = NULL; + buf->_pp = buf->_rp = NULL; + return; + } + else + { + void* beg = INTERNAL_DATA(intl); + intl->end = ((char*)(intl) + allocated); + intl->next = NULL; #ifdef _DEBUG - FILL_BETWEEN(beg, intl->end, 0xCD); + FILL_BETWEEN(beg, intl->end, 0xCD); #endif - if(BUF_IN_JOIN(buf)) - { - int diff = buf->_rp - buf->_pp; + if(BUF_IN_JOIN(buf)) + { + int diff = buf->_rp - buf->_pp; - /* Always true in a join */ - ASSERT(buf->_pp < buf->_rp); + /* Always true in a join */ + ASSERT(buf->_pp < buf->_rp); - /* Copy the memory and blank out old */ - memcpy(beg, buf->_pp, diff); + /* Copy the memory and blank out old */ + memcpy(beg, buf->_pp, diff); #ifdef _DEBUG - FILL_BETWEEN(buf->_pp, buf->_rp, 0xDD); + FILL_BETWEEN(buf->_pp, buf->_rp, 0xDD); #endif - buf->_pp = beg; - buf->_rp = buf->_pp + diff; - } - else - { - buf->_rp = buf->_pp = INTERNAL_DATA(intl); - } + buf->_pp = beg; + buf->_rp = buf->_pp + diff; + } + else + { + buf->_rp = buf->_pp = INTERNAL_DATA(intl); + } - buf->_dt->next = intl; - buf->_dt = intl; - } + buf->_dt->next = intl; + buf->_dt = intl; + } } void ha_bufinit(ha_buffer_t* buf) { - ASSERT(buf); - memset(buf, 0, sizeof(*buf)); + ASSERT(buf); + memset(buf, 0, sizeof(*buf)); - ASSERT(BUF_INITIAL > sizeof(internal_t)); - buf->_ft = (internal_t*)malloc(BUF_INITIAL); - if(buf->_ft) - { - buf->_ft->end = ((char*)(buf->_ft) + BUF_INITIAL); - buf->_ft->next = NULL; + ASSERT(BUF_INITIAL > sizeof(internal_t)); + buf->_ft = (internal_t*)malloc(BUF_INITIAL); + if(buf->_ft) + { + buf->_ft->end = ((char*)(buf->_ft) + BUF_INITIAL); + buf->_ft->next = NULL; #ifdef _DEBUG - FILL_BETWEEN(INTERNAL_DATA(buf->_ft), buf->_ft->end, 0xCD); + FILL_BETWEEN(INTERNAL_DATA(buf->_ft), buf->_ft->end, 0xCD); #endif - ha_bufreset(buf); - } + ha_bufreset(buf); + } } void ha_bufreset(ha_buffer_t* buf) { #ifdef _DEBUG - internal_t* intl; + internal_t* intl; #endif - ASSERT(buf); - ASSERT(buf->_ft); + ASSERT(buf); + ASSERT(buf->_ft); #ifdef _DEBUG - /* Go through all the buffers and set them to 0xCD */ - for(intl = buf->_ft; intl; intl = intl->next) - FILL_BETWEEN(INTERNAL_DATA(intl), intl->end, 0xCD); + /* Go through all the buffers and set them to 0xCD */ + for(intl = buf->_ft; intl; intl = intl->next) + FILL_BETWEEN(INTERNAL_DATA(intl), intl->end, 0xCD); #endif - buf->_dt = buf->_ft; - buf->_rp = buf->_pp = (char*)INTERNAL_DATA(buf->_ft); + buf->_dt = buf->_ft; + buf->_rp = buf->_pp = (char*)INTERNAL_DATA(buf->_ft); } void ha_buffree(ha_buffer_t* buf) { - internal_t* intl; - internal_t* next; + internal_t* intl; + internal_t* next; - ASSERT(buf); + ASSERT(buf); - /* Go through free all the buffers and set them to 0xDD */ - for(intl = buf->_ft; intl; intl = next) - { - next = intl->next; - FILL_BETWEEN(INTERNAL_DATA(intl), intl->end, 0xDD); - free(intl); - } + /* Go through free all the buffers and set them to 0xDD */ + for(intl = buf->_ft; intl; intl = next) + { + next = intl->next; + FILL_BETWEEN(INTERNAL_DATA(intl), intl->end, 0xDD); + free(intl); + } - buf->_ft = buf->_dt = NULL; - buf->_rp = buf->_pp = NULL; + buf->_ft = buf->_dt = NULL; + buf->_rp = buf->_pp = NULL; } int ha_bufreadline(int fd, ha_buffer_t* buf) { - int l; - - ASSERT(buf); - ASSERT(fd != -1); + int l; - if(ha_buferr(buf)) - return 0; + ASSERT(buf); + ASSERT(fd != -1); - 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 == EAGAIN) - continue; + if(ha_buferr(buf)) + return 0; - /* Fatal errors */ - else if(l == -1) + for(;;) { - if(errno != EINTR) - ha_message(LOG_ERR, "couldn't read data"); - - return 0; + 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 == EAGAIN) + continue; + + /* Fatal errors */ + else if(l == -1) + { + if(errno != EINTR) + ha_message(NULL, LOG_ERR, "couldn't read data"); + + return 0; + } } - } - return 1; + return 1; } char* ha_bufparseword(ha_buffer_t* buf, const char* delims) { - char* word = NULL; + char* word = NULL; - ASSERT(buf && delims); + 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(ha_buferr(buf)) + return NULL; - /* If at end of buffer or end of line return null */ - if(buf->_pp == buf->_rp || *(buf->_pp) == '\n') - return NULL; + /* Knock out any previous delims */ + while(buf->_pp < buf->_rp && strchr(delims, *(buf->_pp))) + buf->_pp++; - /* We do this before we stash away a pointer */ - buffer_bump(buf, 1); + /* If at end of buffer or end of line return null */ + if(buf->_pp == buf->_rp || *(buf->_pp) == '\n') + return NULL; - word = buf->_pp; + /* We do this before we stash away a pointer */ + buffer_bump(buf, 1); - while(!strchr(delims, *(buf->_pp))) - { - buf->_pp++; + word = buf->_pp; - /* At the end of the buffer */ - if(buf->_pp == buf->_rp) + while(!strchr(delims, *(buf->_pp))) { - *(buf->_rp) = 0; - buf->_rp++; - break; + 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; } - /* At the end of a line */ - else if(*(buf->_pp) == '\n') - break; - } - - /* Now null terminate what we found */ - *(buf->_pp) = 0; - buf->_pp++; + /* Now null terminate what we found */ + *(buf->_pp) = 0; + buf->_pp++; - /* We don't return empty strings */ - if(word[0] == 0) - return NULL; + /* We don't return empty strings */ + if(word[0] == 0) + return NULL; - return word; + return word; } char* ha_bufparseline(ha_buffer_t* buf, int trim) { - char* t; - char* line = NULL; + char* t; + char* line = NULL; - ASSERT(buf); + ASSERT(buf); - if(ha_buferr(buf)) - return 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(trim) + { + /* Knock out any previous whitespace */ + while(buf->_pp < buf->_rp && isblank(*(buf->_pp))) + buf->_pp++; + } - if(buf->_pp == buf->_rp) - return NULL; + if(buf->_pp == buf->_rp) + return NULL; - /* We do this before we stash away a pointer */ - buffer_bump(buf, 1); + /* We do this before we stash away a pointer */ + buffer_bump(buf, 1); - line = buf->_pp; + line = buf->_pp; - t = (char*)memchr(buf->_pp, '\n', ha_buflen(buf)); - if(t == NULL) - { - t = (buf->_rp); - buf->_rp++; - } + t = (char*)memchr(buf->_pp, '\n', ha_buflen(buf)); + if(t == NULL) + { + t = (buf->_rp); + buf->_rp++; + } - *t = 0; - buf->_pp = t + 1; + *t = 0; + buf->_pp = t + 1; - if(trim) - line = trim_space(line); + if(trim) + line = trim_space(line); - /* We don't return empty strings */ - if(line[0] == 0) - return NULL; + /* We don't return empty strings */ + if(line[0] == 0) + return NULL; - return line; + return line; } char* ha_bufmcat(ha_buffer_t* buf, ...) { - const char* str; - va_list ap; + const char* str; + va_list ap; - ASSERT(buf); + ASSERT(buf); - va_start(ap, buf); + va_start(ap, buf); - if(ha_buferr(buf)) - return NULL; + if(ha_buferr(buf)) + return NULL; - if(!BUF_IN_JOIN(buf)) - BUF_NEW_BLOCK(buf); + if(!BUF_IN_JOIN(buf)) + BUF_NEW_BLOCK(buf); - while((str = va_arg(ap, char*)) != NULL) - { - int len = strlen(str); + while((str = va_arg(ap, char*)) != NULL) + { + int len = strlen(str); - /* Always add one for the terminating char */ - buffer_bump(buf, len + 1); + /* Always add one for the terminating char */ + buffer_bump(buf, len + 1); - if(ha_buferr(buf)) - return NULL; + if(ha_buferr(buf)) + return NULL; - /* _rp always points to the next write point */ - strcpy(buf->_rp, str); - buf->_rp += len; - } + /* _rp always points to the next write point */ + strcpy(buf->_rp, str); + buf->_rp += len; + } - buf->_rp++; - return buf->_pp; + buf->_rp++; + return buf->_pp; } char* ha_bufcpy(ha_buffer_t* buf, const char* src) { - size_t len; + size_t len; - ASSERT(buf && src); + ASSERT(buf && src); - len = strlen(src); - return ha_bufncpy(buf, src, len); + 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); + ASSERT(buf && src); - if(ha_buferr(buf)) - return NULL; + if(ha_buferr(buf)) + return NULL; - /* Always add one for the terminating char */ - buffer_bump(buf, len + 1); + /* Always add one for the terminating char */ + buffer_bump(buf, len + 1); - if(ha_buferr(buf)) - return NULL; + if(ha_buferr(buf)) + return NULL; - if(!BUF_IN_JOIN(buf)) - BUF_NEW_BLOCK(buf); + if(!BUF_IN_JOIN(buf)) + BUF_NEW_BLOCK(buf); - memcpy(buf->_rp, src, len * sizeof(char)); - buf->_rp += (len + 1); - *(buf->_rp - 1) = 0; - return buf->_pp; + 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; + void* ret; - ASSERT(buf && sz); + ASSERT(buf && sz); - if(ha_buferr(buf)) - return NULL; + if(ha_buferr(buf)) + return NULL; - /* TODO: Align memory on an appropriate boundary here */ - buffer_bump(buf, sz); + /* TODO: Align memory on an appropriate boundary here */ + buffer_bump(buf, sz); - if(ha_buferr(buf)) - return NULL; + if(ha_buferr(buf)) + return NULL; - BUF_NEW_BLOCK(buf); - ret = (void*)buf->_pp; - buf->_rp += sz; - buf->_pp = buf->_rp; - return ret; + BUF_NEW_BLOCK(buf); + ret = (void*)buf->_pp; + buf->_rp += sz; + buf->_pp = buf->_rp; + return ret; } void* ha_bufmemdup(ha_buffer_t* buf, const void* src, size_t bytes) { - void* mem; + void* mem; - ASSERT(buf && src && bytes); + ASSERT(buf && src && bytes); - if((mem = ha_bufmalloc(buf, bytes)) != NULL) - memcpy(mem, src, bytes); + if((mem = ha_bufmalloc(buf, bytes)) != NULL) + memcpy(mem, src, bytes); - return mem; + return mem; } /* @@ -457,251 +457,251 @@ 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; + 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; - - if(!BUF_IN_JOIN(buf)) - BUF_NEW_BLOCK(buf); - - 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); + ASSERT(buf && source && len); 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]]; - } + return NULL; - /* 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++; + if(!BUF_IN_JOIN(buf)) + BUF_NEW_BLOCK(buf); - 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; + 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]]; + } - *(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; - } + /* 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; + *(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; - void* ret; - size_t todo = 0; - size_t done = 0; - - ASSERT(buf && src); - - if(ha_buferr(buf)) - return NULL; - - BUF_NEW_BLOCK(buf); + int state = 0; + int ch; + char* pos; + void* ret; + size_t todo = 0; + size_t done = 0; - if(!bytes || *bytes == 0) - todo = ~0; - else - todo = *bytes; + ASSERT(buf && src); - while((ch = *src++) != '\0' && done < todo) - { - if(isspace(ch)) /* Skip whitespace anywhere. */ - continue; - - if(ch == PAD64C) - break; - - pos = strchr(BASE64C, ch); - if(pos == 0) /* A non-base64 character. */ - break; + if(ha_buferr(buf)) + return NULL; - buffer_bump(buf, 4); + BUF_NEW_BLOCK(buf); - if(ha_buferr(buf)) - return NULL; + if(!bytes || *bytes == 0) + todo = ~0; + else + todo = *bytes; - switch(state) + while((ch = *src++) != '\0' && done < todo) { - case 0: - *(buf->_rp) = (pos - BASE64C) << 2; - 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; - }; - } - - if(state != 3) - buf->_rp++; + 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, 4); + + if(ha_buferr(buf)) + return NULL; + + switch(state) + { + case 0: + *(buf->_rp) = (pos - BASE64C) << 2; + 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; + }; + } + + if(state != 3) + buf->_rp++; - /* TODO: Validate ending and return error if invalid somehow */ + /* TODO: Validate ending and return error if invalid somehow */ - /* We always null terminate anyway */ - *(buf->_rp++) = 0; + /* We always null terminate anyway */ + *(buf->_rp++) = 0; - if(bytes) - *bytes = done; + if(bytes) + *bytes = done; - ret = (void*)buf->_pp; - buf->_pp = buf->_rp; - return ret; + ret = (void*)buf->_pp; + buf->_pp = buf->_rp; + return ret; } 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; + unsigned char* src = (unsigned char*)source; + unsigned char j; - ASSERT(buf && source && len); + ASSERT(buf && source && len); - buffer_bump(buf, (len * 2) + 1); + buffer_bump(buf, (len * 2) + 1); - if(ha_buferr(buf)) - return NULL; + if(ha_buferr(buf)) + return NULL; - if(!BUF_IN_JOIN(buf)) - BUF_NEW_BLOCK(buf); + if(!BUF_IN_JOIN(buf)) + BUF_NEW_BLOCK(buf); - while(len > 0) - { - j = *(src) >> 4 & 0xf; - *(buf->_rp++) = HEXC[j]; + while(len > 0) + { + j = *(src) >> 4 & 0xf; + *(buf->_rp++) = HEXC[j]; - j = *(src++) & 0xf; - *(buf->_rp++) = HEXC[j]; + j = *(src++) & 0xf; + *(buf->_rp++) = HEXC[j]; - len--; - } + len--; + } - *(buf->_rp++) = 0; - return buf->_pp; + *(buf->_rp++) = 0; + return buf->_pp; } void* ha_bufdechex(ha_buffer_t* buf, const char* src, size_t* bytes) { - unsigned short j; - int state = 0; - char* pos; - void* ret; - size_t done = 0; - size_t todo = 0; - - ASSERT(buf && src); - - if(bytes && *bytes != 0) - { - buffer_bump(buf, *bytes + 1); - todo = *bytes; - } - else - { - todo = ~0; - buffer_bump(buf, (strlen(src) / 2) + 1); - } - - if(ha_buferr(buf)) - return NULL; - - BUF_NEW_BLOCK(buf); - - while(src[0] && done < todo) - { - /* Find the position */ - pos = strchr(HEXC, tolower(src[0])); - if(pos == 0) - break; - - j = pos - HEXC; - - if(!state) + unsigned short j; + int state = 0; + char* pos; + void* ret; + size_t done = 0; + size_t todo = 0; + + ASSERT(buf && src); + + if(bytes && *bytes != 0) { - *(buf->_rp) = (j & 0xf) << 4; - state = 1; + buffer_bump(buf, *bytes + 1); + todo = *bytes; } else { - *(buf->_rp++) |= (j & 0xf); - done++; - state = 0; + todo = ~0; + buffer_bump(buf, (strlen(src) / 2) + 1); } - src++; - } + if(ha_buferr(buf)) + return NULL; + + BUF_NEW_BLOCK(buf); + + while(src[0] && done < todo) + { + /* Find the position */ + pos = strchr(HEXC, tolower(src[0])); + if(pos == 0) + break; + + j = pos - HEXC; + + if(!state) + { + *(buf->_rp) = (j & 0xf) << 4; + state = 1; + } + else + { + *(buf->_rp++) |= (j & 0xf); + done++; + state = 0; + } + + src++; + } - /* We always null terminate anyway */ - *(buf->_rp++) = 0; + /* We always null terminate anyway */ + *(buf->_rp++) = 0; - /* All bytes have to come in pairs */ - if(state != 0) - return NULL; + /* All bytes have to come in pairs */ + if(state != 0) + return NULL; - if(bytes) - *bytes = done; + if(bytes) + *bytes = done; - ret = (void*)buf->_pp; - buf->_pp = buf->_rp; - return ret; + ret = (void*)buf->_pp; + buf->_pp = buf->_rp; + return ret; } diff --git a/common/compat.c b/common/compat.c index 5618ee5..daddbd2 100644 --- a/common/compat.c +++ b/common/compat.c @@ -19,25 +19,25 @@ void* reallocf(void* ptr, size_t size) #ifndef HAVE_STRLWR char* strlwr(char* s) { - char* t = s; - while(*t) - { - *t = tolower(*t); - t++; - } - return s; + char* t = s; + while(*t) + { + *t = tolower(*t); + t++; + } + return s; } #endif #ifndef HAVE_STRUPR char* strupr(char* s) { - char* t = s; - while(*t) - { - *t = toupper(*t); - t++; - } - return s; + char* t = s; + while(*t) + { + *t = toupper(*t); + t++; + } + return s; } #endif diff --git a/common/compat.h b/common/compat.h index bb7311c..c7f86cc 100644 --- a/common/compat.h +++ b/common/compat.h @@ -10,7 +10,7 @@ #include <sys/types.h> #ifndef HAVE_STDARG_H -#error ERROR: Must have a working stdarg.h header +# error ERROR: Must have a working stdarg.h header #else #include <stdarg.h> #endif @@ -23,13 +23,13 @@ void* reallocf(void* p, size_t sz); /* TODO: Move this logic to configure */ #if HAVE_ERR_MUTEX == 1 -# define HA_MUTEX_TYPE PTHREAD_MUTEX_ERRORCHECK_NP +# define HA_MUTEX_TYPE PTHREAD_MUTEX_ERRORCHECK_NP #else -# if HAVE_ERR_MUTEX == 2 -# define HA_MUTEX_TYPE PTHREAD_MUTEX_ERRORCHECK -# else -# error "Need error checking mutex functionality" -# endif +# if HAVE_ERR_MUTEX == 2 +# define HA_MUTEX_TYPE PTHREAD_MUTEX_ERRORCHECK +# else +# error "Need error checking mutex functionality" +# endif #endif #ifndef HAVE_STRLWR diff --git a/common/hash.c b/common/hash.c index 5f3308c..3ff3982 100644 --- a/common/hash.c +++ b/common/hash.c @@ -9,7 +9,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -27,9 +27,9 @@ #endif #ifdef HSH_COPYKEYS - #define KEY_DATA(he) (void*)(((unsigned char*)(he)) + sizeof(*(he))) + #define KEY_DATA(he) (void*)(((unsigned char*)(he)) + sizeof(*(he))) #else - #define KEY_DATA(he) ((he)->key) + #define KEY_DATA(he) ((he)->key) #endif /* @@ -45,15 +45,15 @@ typedef struct hsh_entry_t hsh_entry_t; struct hsh_entry_t { - hsh_entry_t* next; - unsigned int hash; + hsh_entry_t* next; + unsigned int hash; #ifndef HSH_COPYKEYS - const void* key; - size_t klen; + const void* key; + size_t klen; #endif - const void* val; + const void* val; #ifdef HSH_TIMESTAMP - time_t stamp; + time_t stamp; #endif }; @@ -66,10 +66,10 @@ struct hsh_entry_t */ struct hsh_index_t { - hsh_t* ht; - hsh_entry_t* ths; - hsh_entry_t* next; - unsigned int index; + hsh_t* ht; + hsh_entry_t* ths; + hsh_entry_t* next; + unsigned int index; }; /* @@ -81,15 +81,15 @@ struct hsh_index_t */ struct hsh_t { - hsh_entry_t** array; - hsh_index_t iterator; /* For hsh_first(...) */ - unsigned int count; - unsigned int max; + hsh_entry_t** array; + hsh_index_t iterator; /* For hsh_first(...) */ + unsigned int count; + unsigned int max; #ifdef HSH_COPYKEYS - unsigned int klen; + unsigned int klen; #endif #ifdef HSH_CALLBACKS - hsh_table_calls_t calls; + hsh_table_calls_t calls; #endif }; @@ -106,47 +106,47 @@ static hsh_memory_calls_t* g_memory_calls = NULL; static void* int_malloc(size_t len) { - if(g_memory_calls) - return (g_memory_calls->f_alloc)(g_memory_calls->arg, len); - else - return malloc(len); + if(g_memory_calls) + return (g_memory_calls->f_alloc)(g_memory_calls->arg, len); + else + return malloc(len); } static void* int_calloc(size_t len) { - void* p = int_malloc(len); - memset(p, 0, len); - return p; + void* p = int_malloc(len); + memset(p, 0, len); + return p; } static void int_free(void* ptr) { - if(g_memory_calls) - { - /* We allow for gc type memory allocation with a null free */ - if(g_memory_calls->f_free) - (g_memory_calls->f_free)(g_memory_calls->arg, ptr); - } - else - free(ptr); + if(g_memory_calls) + { + /* We allow for gc type memory allocation with a null free */ + if(g_memory_calls->f_free) + (g_memory_calls->f_free)(g_memory_calls->arg, ptr); + } + else + free(ptr); } void hsh_set_memory_calls(hsh_memory_calls_t* hmc) { - if(hmc == NULL) - { - g_memory_calls = NULL; - } - else - { - memcpy(&g_memory_calls_cpy, hmc, sizeof(g_memory_calls_cpy)); - g_memory_calls = &g_memory_calls_cpy; - } + if(hmc == NULL) + { + g_memory_calls = NULL; + } + else + { + memcpy(&g_memory_calls_cpy, hmc, sizeof(g_memory_calls_cpy)); + g_memory_calls = &g_memory_calls_cpy; + } } void hsh_set_table_calls(hsh_t* ht, hsh_table_calls_t* htc) { - memcpy(&(ht->calls), htc, sizeof(ht->calls)); + memcpy(&(ht->calls), htc, sizeof(ht->calls)); } #else @@ -163,7 +163,7 @@ void hsh_set_table_calls(hsh_t* ht, hsh_table_calls_t* htc) static hsh_entry_t** alloc_array(hsh_t* ht, unsigned int max) { - return int_calloc(sizeof(*(ht->array)) * (max + 1)); + return int_calloc(sizeof(*(ht->array)) * (max + 1)); } #ifdef HSH_COPYKEYS @@ -172,41 +172,41 @@ hsh_t* hsh_create(size_t klen) hsh_t* hsh_create() #endif { - hsh_t* ht = int_malloc(sizeof(hsh_t)); - if(ht) - { - ht->count = 0; - ht->max = INITIAL_MAX; - ht->array = alloc_array(ht, ht->max); + hsh_t* ht = int_malloc(sizeof(hsh_t)); + if(ht) + { + ht->count = 0; + ht->max = INITIAL_MAX; + ht->array = alloc_array(ht, ht->max); #ifdef HSH_COPYKEYS - ht->klen = klen; + ht->klen = klen; #endif - if(!ht->array) - { - int_free(ht); - return NULL; + if(!ht->array) + { + int_free(ht); + return NULL; + } } - } - return ht; + return ht; } void hsh_free(hsh_t* ht) { - hsh_index_t* hi; + hsh_index_t* hi; - for(hi = hsh_first(ht); hi; hi = hsh_next(hi)) - { + for(hi = hsh_first(ht); hi; hi = hsh_next(hi)) + { #ifdef HSH_CALLBACKS - if(hi->ths->val && ht->calls.f_freeval) - (ht->calls.f_freeval)(ht->calls.arg, (void*)hi->ths->val); + if(hi->ths->val && ht->calls.f_freeval) + (ht->calls.f_freeval)(ht->calls.arg, (void*)hi->ths->val); #endif - int_free(hi->ths); - } + int_free(hi->ths); + } - if(ht->array) - int_free(ht->array); + if(ht->array) + int_free(ht->array); - int_free(ht); + int_free(ht); } /* @@ -215,27 +215,27 @@ void hsh_free(hsh_t* ht) hsh_index_t* hsh_next(hsh_index_t* hi) { - hi->ths = hi->next; - while(!hi->ths) - { - if(hi->index > hi->ht->max) - return NULL; - - hi->ths = hi->ht->array[hi->index++]; - } - hi->next = hi->ths->next; - return hi; + hi->ths = hi->next; + while(!hi->ths) + { + if(hi->index > hi->ht->max) + return NULL; + + hi->ths = hi->ht->array[hi->index++]; + } + hi->next = hi->ths->next; + return hi; } hsh_index_t* hsh_first(hsh_t* ht) { - hsh_index_t* hi = &ht->iterator; + hsh_index_t* hi = &ht->iterator; - hi->ht = ht; - hi->index = 0; - hi->ths = NULL; - hi->next = NULL; - return hsh_next(hi); + hi->ht = ht; + hi->index = 0; + hi->ths = NULL; + hi->next = NULL; + return hsh_next(hi); } #ifdef HSH_COPYKEYS @@ -244,15 +244,15 @@ void* hsh_this(hsh_index_t* hi, const void** key) void* hsh_this(hsh_index_t* hi, const void** key, size_t* klen) #endif { - if(key) - *key = KEY_DATA(hi->ths); + if(key) + *key = KEY_DATA(hi->ths); #ifndef HSH_COPYKEYS - if(klen) - *klen = hi->ths->klen; + if(klen) + *klen = hi->ths->klen; #endif - return (void*)hi->ths->val; + return (void*)hi->ths->val; } @@ -262,29 +262,29 @@ void* hsh_this(hsh_index_t* hi, const void** key, size_t* klen) static int expand_array(hsh_t* ht) { - hsh_index_t* hi; - hsh_entry_t** new_array; - unsigned int new_max; + hsh_index_t* hi; + hsh_entry_t** new_array; + unsigned int new_max; - new_max = ht->max * 2 + 1; - new_array = alloc_array(ht, new_max); + new_max = ht->max * 2 + 1; + new_array = alloc_array(ht, new_max); - if(!new_array) - return 0; + if(!new_array) + return 0; - for(hi = hsh_first(ht); hi; hi = hsh_next(hi)) - { - unsigned int i = hi->ths->hash & new_max; - hi->ths->next = new_array[i]; - new_array[i] = hi->ths; - } + for(hi = hsh_first(ht); hi; hi = hsh_next(hi)) + { + unsigned int i = hi->ths->hash & new_max; + hi->ths->next = new_array[i]; + new_array[i] = hi->ths; + } - if(ht->array) - free(ht->array); + if(ht->array) + free(ht->array); - ht->array = new_array; - ht->max = new_max; - return 1; + ht->array = new_array; + ht->max = new_max; + return 1; } /* @@ -302,283 +302,283 @@ static hsh_entry_t** find_entry(hsh_t* ht, const void* key, const void* val) static hsh_entry_t** find_entry(hsh_t* ht, const void* key, size_t klen, const void* val) #endif { - hsh_entry_t** hep; - hsh_entry_t* he; - const unsigned char* p; - unsigned int hash; - size_t i; + hsh_entry_t** hep; + hsh_entry_t* he; + const unsigned char* p; + unsigned int hash; + size_t i; #ifdef HSH_COPYKEYS - size_t klen = ht->klen; + size_t klen = ht->klen; #endif - /* - * This is the popular `times 33' hash algorithm which is used by - * perl and also appears in Berkeley DB. This is one of the best - * known hash functions for strings because it is both computed - * very fast and distributes very well. - * - * The originator may be Dan Bernstein but the code in Berkeley DB - * cites Chris Torek as the source. The best citation I have found - * is "Chris Torek, Hash function for text in C, Usenet message - * <27038@mimsy.umd.edu> in comp.lang.c , October, 1990." in Rich - * Salz's USENIX 1992 paper about INN which can be found at - * <http://citeseer.nj.nec.com/salz92internetnews.html>. - * - * The magic of number 33, i.e. why it works better than many other - * constants, prime or not, has never been adequately explained by - * anyone. So I try an explanation: if one experimentally tests all - * multipliers between 1 and 256 (as I did while writing a low-level - * data structure library some time ago) one detects that even - * numbers are not useable at all. The remaining 128 odd numbers - * (except for the number 1) work more or less all equally well. - * They all distribute in an acceptable way and this way fill a hash - * table with an average percent of approx. 86%. - * - * If one compares the chi^2 values of the variants (see - * Bob Jenkins ``Hashing Frequently Asked Questions'' at - * http://burtleburtle.net/bob/hash/hashfaq.html for a description - * of chi^2), the number 33 not even has the best value. But the - * number 33 and a few other equally good numbers like 17, 31, 63, - * 127 and 129 have nevertheless a great advantage to the remaining - * numbers in the large set of possible multipliers: their multiply - * operation can be replaced by a faster operation based on just one - * shift plus either a single addition or subtraction operation. And - * because a hash function has to both distribute good _and_ has to - * be very fast to compute, those few numbers should be preferred. - * - * -- Ralf S. Engelschall <rse@engelschall.com> - */ - hash = 0; + /* + * This is the popular `times 33' hash algorithm which is used by + * perl and also appears in Berkeley DB. This is one of the best + * known hash functions for strings because it is both computed + * very fast and distributes very well. + * + * The originator may be Dan Bernstein but the code in Berkeley DB + * cites Chris Torek as the source. The best citation I have found + * is "Chris Torek, Hash function for text in C, Usenet message + * <27038@mimsy.umd.edu> in comp.lang.c , October, 1990." in Rich + * Salz's USENIX 1992 paper about INN which can be found at + * <http://citeseer.nj.nec.com/salz92internetnews.html>. + * + * The magic of number 33, i.e. why it works better than many other + * constants, prime or not, has never been adequately explained by + * anyone. So I try an explanation: if one experimentally tests all + * multipliers between 1 and 256 (as I did while writing a low-level + * data structure library some time ago) one detects that even + * numbers are not useable at all. The remaining 128 odd numbers + * (except for the number 1) work more or less all equally well. + * They all distribute in an acceptable way and this way fill a hash + * table with an average percent of approx. 86%. + * + * If one compares the chi^2 values of the variants (see + * Bob Jenkins ``Hashing Frequently Asked Questions'' at + * http://burtleburtle.net/bob/hash/hashfaq.html for a description + * of chi^2), the number 33 not even has the best value. But the + * number 33 and a few other equally good numbers like 17, 31, 63, + * 127 and 129 have nevertheless a great advantage to the remaining + * numbers in the large set of possible multipliers: their multiply + * operation can be replaced by a faster operation based on just one + * shift plus either a single addition or subtraction operation. And + * because a hash function has to both distribute good _and_ has to + * be very fast to compute, those few numbers should be preferred. + * + * -- Ralf S. Engelschall <rse@engelschall.com> + */ + hash = 0; #ifndef HSH_COPYKEYS - if(klen == HSH_KEY_STRING) - { - for(p = key; *p; p++) - hash = hash * 33 + *p; - - klen = p - (const unsigned char *)key; - } - else + if(klen == HSH_KEY_STRING) + { + for(p = key; *p; p++) + hash = hash * 33 + *p; + + klen = p - (const unsigned char *)key; + } + else #endif - { - for(p = key, i = klen; i; i--, p++) - hash = hash * 33 + *p; - } - - /* scan linked list */ - for(hep = &ht->array[hash & ht->max], he = *hep; - he; hep = &he->next, he = *hep) - { - if(he->hash == hash && + { + for(p = key, i = klen; i; i--, p++) + hash = hash * 33 + *p; + } + + /* scan linked list */ + for(hep = &ht->array[hash & ht->max], he = *hep; + he; hep = &he->next, he = *hep) + { + if(he->hash == hash && #ifndef HSH_COPYKEYS - he->klen == klen && + he->klen == klen && #endif - memcmp(KEY_DATA(he), key, klen) == 0) - break; - } + memcmp(KEY_DATA(he), key, klen) == 0) + break; + } - if(he || !val) - return hep; + if(he || !val) + return hep; - /* add a new entry for non-NULL val */ + /* add a new entry for non-NULL val */ #ifdef HSH_COPYKEYS - he = int_malloc(sizeof(*he) + klen); + he = int_malloc(sizeof(*he) + klen); #else - he = int_malloc(sizeof(*he)); + he = int_malloc(sizeof(*he)); #endif - if(he) - { + if(he) + { #ifdef HSH_COPYKEYS - /* Key data points past end of entry */ - memcpy(KEY_DATA(he), key, klen); + /* Key data points past end of entry */ + memcpy(KEY_DATA(he), key, klen); #else - /* Key points to external data */ - he->key = key; - he->klen = klen; + /* Key points to external data */ + he->key = key; + he->klen = klen; #endif - he->next = NULL; - he->hash = hash; - he->val = val; + he->next = NULL; + he->hash = hash; + he->val = val; #ifdef HSH_TIMESTAMP - he->stamp = 0; + he->stamp = 0; #endif - *hep = he; - ht->count++; - } + *hep = he; + ht->count++; + } - return hep; + return hep; } #ifdef HSH_COPYKEYS void* hsh_get(hsh_t* ht, const void *key) { - hsh_entry_t** he = find_entry(ht, key, NULL); + hsh_entry_t** he = find_entry(ht, key, NULL); #else void* hsh_get(hsh_t* ht, const void *key, size_t klen) { - hsh_entry_t** he = find_entry(ht, key, klen, NULL); + hsh_entry_t** he = find_entry(ht, key, klen, NULL); #endif - if(he && *he) - return (void*)((*he)->val); - else - return NULL; + if(he && *he) + return (void*)((*he)->val); + else + return NULL; } #ifdef HSH_COPYKEYS int hsh_set(hsh_t* ht, const void* key, void* val) { - hsh_entry_t** hep = find_entry(ht, key, val); + hsh_entry_t** hep = find_entry(ht, key, val); #else int hsh_set(hsh_t* ht, const void* key, size_t klen, void* val) { - hsh_entry_t** hep = find_entry(ht, key, klen, val); + hsh_entry_t** hep = find_entry(ht, key, klen, val); #endif - if(hep && *hep) - { + if(hep && *hep) + { #ifdef HSH_CALLBACKS - if((*hep)->val && (*hep)->val != val && ht->calls.f_freeval) - (ht->calls.f_freeval)(ht->calls.arg, (void*)((*hep)->val)); + if((*hep)->val && (*hep)->val != val && ht->calls.f_freeval) + (ht->calls.f_freeval)(ht->calls.arg, (void*)((*hep)->val)); #endif - /* replace entry */ - (*hep)->val = val; + /* replace entry */ + (*hep)->val = val; #ifdef HSH_TIMESTAMP - /* Update or set the timestamp */ - (*hep)->stamp = time(NULL); + /* Update or set the timestamp */ + (*hep)->stamp = time(NULL); #endif - /* check that the collision rate isn't too high */ - if(ht->count > ht->max) - { - if(!expand_array(ht)) - return 0; - } + /* check that the collision rate isn't too high */ + if(ht->count > ht->max) + { + if(!expand_array(ht)) + return 0; + } - return 1; - } + return 1; + } - return 0; + return 0; } #ifdef HSH_COPYKEYS void* hsh_rem(hsh_t* ht, const void* key) { - hsh_entry_t** hep = find_entry(ht, key, NULL); + hsh_entry_t** hep = find_entry(ht, key, NULL); #else void* hsh_rem(hsh_t* ht, const void* key, size_t klen) { - hsh_entry_t** hep = find_entry(ht, key, klen, NULL); + hsh_entry_t** hep = find_entry(ht, key, klen, NULL); #endif - void* val = NULL; - - if(hep && *hep) - { - hsh_entry_t* old = *hep; - *hep = (*hep)->next; - --ht->count; - val = (void*)old->val; - free(old); - } - - return val; + void* val = NULL; + + if(hep && *hep) + { + hsh_entry_t* old = *hep; + *hep = (*hep)->next; + --ht->count; + val = (void*)old->val; + free(old); + } + + return val; } unsigned int hsh_count(hsh_t* ht) { - return ht->count; + return ht->count; } #ifdef HSH_TIMESTAMP int hsh_purge(hsh_t* ht, time_t stamp) { - hsh_index_t* hi; - int r = 0; - void* val; + hsh_index_t* hi; + int r = 0; + void* val; - for(hi = hsh_first(ht); hi; hi = hsh_next(hi)) - { - if(hi->ths->stamp < stamp) + for(hi = hsh_first(ht); hi; hi = hsh_next(hi)) { - /* No need to check for errors as we're deleting */ + if(hi->ths->stamp < stamp) + { + /* No need to check for errors as we're deleting */ #ifdef HSH_COPYKEYS - val = hsh_rem(ht, KEY_DATA(hi->ths)); + val = hsh_rem(ht, KEY_DATA(hi->ths)); #else - val = hsh_rem(ht, hi->ths->key, hi->ths->klen); + val = hsh_rem(ht, hi->ths->key, hi->ths->klen); #endif #ifdef HSH_CALLBACKS - if(val && ht->calls.f_freeval) - (ht->calls.f_freeval)(ht->calls.arg, val); + if(val && ht->calls.f_freeval) + (ht->calls.f_freeval)(ht->calls.arg, val); #endif - r++; + r++; + } } - } - return r; + return r; } #ifdef HSH_COPYKEYS void hsh_touch(hsh_t* ht, const void* key) { - hsh_entry_t** hep = find_entry(ht, key, NULL); + hsh_entry_t** hep = find_entry(ht, key, NULL); #else void hsh_touch(hsh_t* ht, const void* key, size_t* klen) { - hsh_entry_t** hep = find_entry(ht, key, klen, NULL); + hsh_entry_t** hep = find_entry(ht, key, klen, NULL); #endif - if(hep && *hep) - ((*hep)->stamp) = time(NULL); + if(hep && *hep) + ((*hep)->stamp) = time(NULL); } int hsh_bump(hsh_t* ht) { - hsh_index_t* hi; - void* key = NULL; - void* val = NULL; - time_t least = 0; + hsh_index_t* hi; + void* key = NULL; + void* val = NULL; + time_t least = 0; #ifndef HSH_COPYKEYS - size_t klen = 0; + size_t klen = 0; #endif - for(hi = hsh_first(ht); hi; hi = hsh_next(hi)) - { - if(least == 0 || hi->ths->stamp < least) + for(hi = hsh_first(ht); hi; hi = hsh_next(hi)) { - least = hi->ths->stamp; - key = KEY_DATA(hi->ths); + if(least == 0 || hi->ths->stamp < least) + { + least = hi->ths->stamp; + key = KEY_DATA(hi->ths); #ifndef HSH_COPYKEYS - klen = hi->this->klen; + klen = hi->this->klen; #endif + } } - } - if(key) - { + if(key) + { #ifdef HSH_COPYKEYS - val = hsh_rem(ht, key); + val = hsh_rem(ht, key); #else - val = hsh_rem(ht, key, klen); + val = hsh_rem(ht, key, klen); #endif #ifdef HSH_CALLBACKS - if(val && ht->calls.f_freeval) - (ht->calls.f_freeval)(ht->calls.arg, (void*)val); + if(val && ht->calls.f_freeval) + (ht->calls.f_freeval)(ht->calls.arg, (void*)val); #endif - return 1; - } + return 1; + } - return 0; + return 0; } #endif /* HSH_TIMESTAMP */ diff --git a/common/md5.c b/common/md5.c index 2f92bec..00058ef 100644 --- a/common/md5.c +++ b/common/md5.c @@ -24,13 +24,13 @@ void md5_transform(unsigned int buf[4], unsigned int const in[16]); void byteSwap(unsigned int *buf, unsigned words) { - unsigned char *p = (unsigned char *)buf; + unsigned char *p = (unsigned char *)buf; - do { - *buf++ = (unsigned int)((unsigned)p[3] << 8 | p[2]) << 16 | - ((unsigned)p[1] << 8 | p[0]); - p += 4; - } while (--words); + do { + *buf++ = (unsigned int)((unsigned)p[3] << 8 | p[2]) << 16 | + ((unsigned)p[1] << 8 | p[0]); + p += 4; + } while (--words); } #else #define byteSwap(buf,words) @@ -43,13 +43,13 @@ byteSwap(unsigned int *buf, unsigned words) void md5_init(md5_ctx_t* ctx) { - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; - ctx->bytes[0] = 0; - ctx->bytes[1] = 0; + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; } /* @@ -59,38 +59,38 @@ md5_init(md5_ctx_t* ctx) void md5_update(md5_ctx_t* ctx, const void* b, unsigned len) { - unsigned int t; - const unsigned char* buf = (const unsigned char*)b; - - /* Update byte count */ - - t = ctx->bytes[0]; - if ((ctx->bytes[0] = t + len) < t) - ctx->bytes[1]++; /* Carry from low to high */ - - t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ - if (t > len) { - memcpy((unsigned char *)ctx->in + 64 - t, buf, len); - return; - } - /* First chunk is an odd size */ - memcpy((unsigned char *)ctx->in + 64 - t, buf, t); + unsigned int t; + const unsigned char* buf = (const unsigned char*)b; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((unsigned char *)ctx->in + 64 - t, buf, len); + return; + } + /* First chunk is an odd size */ + memcpy((unsigned char *)ctx->in + 64 - t, buf, t); + byteSwap(ctx->in, 16); + md5_transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); byteSwap(ctx->in, 16); md5_transform(ctx->buf, ctx->in); - buf += t; - len -= t; - - /* Process data in 64-byte chunks */ - while (len >= 64) { - memcpy(ctx->in, buf, 64); - byteSwap(ctx->in, 16); - md5_transform(ctx->buf, ctx->in); - buf += 64; - len -= 64; - } - - /* Handle any remaining bytes of data. */ - memcpy(ctx->in, buf, len); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); } /* @@ -100,33 +100,33 @@ md5_update(md5_ctx_t* ctx, const void* b, unsigned len) void md5_final(unsigned char digest[16], md5_ctx_t* ctx) { - int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ - unsigned char *p = (unsigned char *)ctx->in + count; - - /* Set the first char of padding to 0x80. There is always room. */ - *p++ = 0x80; - - /* Bytes of padding needed to make 56 bytes (-8..55) */ - count = 56 - 1 - count; - - if (count < 0) { /* Padding forces an extra block */ - memset(p, 0, (unsigned int)count + 8); - byteSwap(ctx->in, 16); - md5_transform(ctx->buf, ctx->in); - p = (unsigned char *)ctx->in; - count = 56; - } - memset(p, 0, (unsigned int)count); - byteSwap(ctx->in, 14); - - /* Append length in bits and transform */ - ctx->in[14] = ctx->bytes[0] << 3; - ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; - md5_transform(ctx->buf, ctx->in); + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + unsigned char *p = (unsigned char *)ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; - byteSwap(ctx->buf, 4); - memcpy(digest, ctx->buf, 16); - memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, (unsigned int)count + 8); + byteSwap(ctx->in, 16); + md5_transform(ctx->buf, ctx->in); + p = (unsigned char *)ctx->in; + count = 56; + } + memset(p, 0, (unsigned int)count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + md5_transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ } void @@ -156,7 +156,7 @@ md5_strcmp(unsigned char digest[MD5_LEN], const char* str) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f,w,x,y,z,in,s) \ - (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x) + (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to @@ -166,83 +166,83 @@ md5_strcmp(unsigned char digest[MD5_LEN], const char* str) void md5_transform(unsigned int buf[4], unsigned int const in[16]) { - register unsigned int a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; + register unsigned int a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; } diff --git a/common/md5.h b/common/md5.h index de431da..d503f11 100644 --- a/common/md5.h +++ b/common/md5.h @@ -32,9 +32,9 @@ extern "C" { typedef struct md5_ctx { - unsigned int buf[4]; - unsigned int bytes[2]; - unsigned int in[16]; + unsigned int buf[4]; + unsigned int bytes[2]; + unsigned int in[16]; } md5_ctx_t; diff --git a/common/sha1.c b/common/sha1.c index a40732e..0666837 100644 --- a/common/sha1.c +++ b/common/sha1.c @@ -1,6 +1,6 @@ /* - * Fetched from ftp://ftp.funet.fi/pub/crypt/hash/sha/sha1.c on May 4, 1999 - * Modified by EPG May 6, 1999 + * Fetched from ftp://ftp.funet.fi/pub/crypt/hash/sha/sha1.c on May 4, 1999 + * Modified by EPG May 6, 1999 */ /* @@ -23,12 +23,12 @@ void SHA1Transform(ulong state[5], const uchar buffer[64]); /* I got the idea of expanding during the round function from SSLeay */ #ifdef LITTLE_ENDIAN #define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ - |(rol(block->l[i],8)&0x00FF00FF)) + |(rol(block->l[i],8)&0x00FF00FF)) #else #define blk0(i) block->l[i] #endif #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ - ^block->l[(i+2)&15]^block->l[i&15],1)) + ^block->l[(i+2)&15]^block->l[i&15],1)) /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); @@ -42,54 +42,54 @@ void SHA1Transform(ulong state[5], const uchar buffer[64]); void SHA1Transform(ulong state[5], const uchar buffer[64]) { - ulong a, b, c, d, e; - typedef union { - uchar c[64]; - ulong l[16]; - } CHAR64LONG16; - CHAR64LONG16* block; + ulong a, b, c, d, e; + typedef union { + uchar c[64]; + ulong l[16]; + } CHAR64LONG16; + CHAR64LONG16* block; #ifdef SHA1HANDSOFF - static uchar workspace[64]; - block = (CHAR64LONG16*)workspace; - memcpy(block, buffer, 64); + static uchar workspace[64]; + block = (CHAR64LONG16*)workspace; + memcpy(block, buffer, 64); #else - block = (CHAR64LONG16*)buffer; + block = (CHAR64LONG16*)buffer; #endif - /* Copy context->state[] to working vars */ - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - /* 4 rounds of 20 operations each. Loop unrolled. */ - R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); - R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); - R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); - R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); - R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); - R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); - R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); - R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); - R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); - R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); - R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); - R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); - R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); - R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); - R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); - R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); - R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); - R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); - R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); - R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); - /* Add the working vars back into context.state[] */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - /* Wipe variables */ - a = b = c = d = e = 0; + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; } @@ -97,13 +97,13 @@ void SHA1Transform(ulong state[5], const uchar buffer[64]) void sha1_init(sha1_ctx_t* context) { - /* SHA1 initialization constants */ - context->state[0] = 0x67452301; - context->state[1] = 0xEFCDAB89; - context->state[2] = 0x98BADCFE; - context->state[3] = 0x10325476; - context->state[4] = 0xC3D2E1F0; - context->count[0] = context->count[1] = 0; + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; } @@ -111,22 +111,22 @@ void sha1_init(sha1_ctx_t* context) void sha1_update(sha1_ctx_t* context, const void* d, unsigned int len) { - unsigned int i, j; - const uchar* data = (uchar*)d; - - j = (context->count[0] >> 3) & 63; - if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; - context->count[1] += (len >> 29); - if ((j + len) > 63) { - memcpy(&context->buffer[j], data, (i = 64-j)); - SHA1Transform(context->state, context->buffer); - for ( ; i + 63 < len; i += 64) { - SHA1Transform(context->state, &data[i]); + unsigned int i, j; + const uchar* data = (uchar*)d; + + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; + context->count[1] += (len >> 29); + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + SHA1Transform(context->state, &data[i]); + } + j = 0; } - j = 0; - } - else i = 0; - memcpy(&context->buffer[j], &data[i], len - i); + else i = 0; + memcpy(&context->buffer[j], &data[i], len - i); } @@ -134,30 +134,30 @@ void sha1_update(sha1_ctx_t* context, const void* d, unsigned int len) void sha1_final(uchar digest[20], sha1_ctx_t* context) { - ulong i; - uchar finalcount[8]; - - for (i = 0; i < 8; i++) { - finalcount[i] = (uchar)((context->count[(i >= 4 ? 0 : 1)] - >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ - } - sha1_update(context, (uchar *)"\200", 1); - while ((context->count[0] & 504) != 448) { - sha1_update(context, (uchar *)"\0", 1); - } - sha1_update(context, finalcount, 8); /* Should cause a SHA1Transform() */ - for (i = 0; i < 20; i++) { - digest[i] = (uchar) - ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); - } - /* Wipe variables */ - i = 0; - memset(context->buffer, 0, 64); - memset(context->state, 0, 20); - memset(context->count, 0, 8); - memset(&finalcount, 0, 8); -#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ - SHA1Transform(context->state, context->buffer); + ulong i; + uchar finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (uchar)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + sha1_update(context, (uchar *)"\200", 1); + while ((context->count[0] & 504) != 448) { + sha1_update(context, (uchar *)"\0", 1); + } + sha1_update(context, finalcount, 8); /* Should cause a SHA1Transform() */ + for (i = 0; i < 20; i++) { + digest[i] = (uchar) + ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } + /* Wipe variables */ + i = 0; + memset(context->buffer, 0, 64); + memset(context->state, 0, 20); + memset(context->count, 0, 8); + memset(&finalcount, 0, 8); +#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ + SHA1Transform(context->state, context->buffer); #endif } diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 5ad8665..c669f04 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -1,7 +1,7 @@ sbin_PROGRAMS = httpauthd -httpauthd_SOURCES = httpauthd.c httpauthd.h usuals.h compat.h compat.c \ +httpauthd_SOURCES = httpauthd.c httpauthd.h usuals.h compat.h compat.c bd.h bd.c\ buffer.c misc.c basic.h basic.c ntlm.c hash.c hash.h ntlmssp.h ntlmssp.c \ md5.c md5.h sha1.c sha1.h digest.h digest.c ldap.c defaults.h simple.c \ ../common/sock_any.c ../common/sock_any.h ../common/stringx.c\ diff --git a/daemon/basic.c b/daemon/basic.c index fc0a096..6b41a36 100644 --- a/daemon/basic.c +++ b/daemon/basic.c @@ -6,39 +6,39 @@ int basic_parse(const char* header, ha_buffer_t* buf, basic_header_t* rec) { - char* t; - ASSERT(header && buf && rec); + char* t; + ASSERT(header && buf && rec); - memset(rec, 0, sizeof(*rec)); + memset(rec, 0, sizeof(*rec)); - /* - * Authorization header is in this format: - * - * "Basic " B64(user ":" password) - */ + /* + * Authorization header is in this format: + * + * "Basic " B64(user ":" password) + */ - header = trim_start(header); - header = (const char*)ha_bufdec64(buf, header, NULL); + header = trim_start(header); + header = (const char*)ha_bufdec64(buf, header, NULL); - if(!header) - return ha_buferr(buf) ? HA_CRITERROR : HA_FALSE; + if(!header) + return ha_buferr(buf) ? HA_CRITERROR : HA_FALSE; - /* We have a cache key at this point so hash it */ - md5_string(rec->key, header); + /* We have a cache key at this point so hash it */ + md5_string(rec->key, header); - /* Parse the user. We need it in any case */ - t = strchr(header, ':'); - if(t != NULL) - { - /* Break the string in half */ - *t = 0; + /* Parse the user. We need it in any case */ + t = strchr(header, ':'); + if(t != NULL) + { + /* Break the string in half */ + *t = 0; - rec->user = header; - rec->password = t + 1; - } + rec->user = header; + rec->password = t + 1; + } - return HA_OK; + return HA_OK; } diff --git a/daemon/basic.h b/daemon/basic.h index c28dc1e..775a3a7 100644 --- a/daemon/basic.h +++ b/daemon/basic.h @@ -6,9 +6,9 @@ typedef struct basic_header { - const char* user; - const char* password; - unsigned char key[MD5_LEN]; + const char* user; + const char* password; + unsigned char key[MD5_LEN]; } basic_header_t; diff --git a/daemon/bd.c b/daemon/bd.c index 916c453..6cd7b6b 100644 --- a/daemon/bd.c +++ b/daemon/bd.c @@ -25,8 +25,8 @@ static unsigned char g_digest_secret[DIGEST_SECRET_LEN]; static void free_hash_object(void* arg, void* val) { - if(val && val != BASIC_ESTABLISHED) - free(val); + if(val && val != BASIC_ESTABLISHED) + free(val); } static digest_record_t* get_cached_digest(bd_context_t* ctx, ha_context_t* c, @@ -92,7 +92,7 @@ static int save_cached_digest(bd_context_t* ctx, ha_context_t* c, if(!r) { - ha_messagex(LOG_CRIT, "out of memory"); + ha_messagex(NULL, LOG_CRIT, "out of memory"); return HA_CRITERROR; } @@ -120,22 +120,21 @@ static int add_cached_basic(bd_context_t* ctx, ha_context_t* c, if(!r) { - ha_messagex(LOG_CRIT, "out of memory"); + ha_messagex(NULL, LOG_CRIT, "out of memory"); return HA_CRITERROR; } return HA_OK; } -static int do_basic_response(bd_context_t* ctx, const char* header, - const ha_request_t* req, ha_response_t* resp) +static int do_basic_response(ha_request_t* rq, bd_context_t* ctx, const char* header) { basic_header_t basic; int ret = HA_FALSE; - ASSERT(header && resp && req); + ASSERT(header && rq); - if((ret = basic_parse(header, req->buf, &basic)) < 0) + if((ret = basic_parse(header, rq->buf, &basic)) < 0) return ret; /* Past this point we don't return directly */ @@ -143,7 +142,7 @@ static int do_basic_response(bd_context_t* ctx, const char* header, /* Check and see if this connection is in the cache */ if(have_cached_basic(ctx, basic.key)) { - ha_messagex(LOG_NOTICE, "bd: validated basic user against cache: %s", + ha_messagex(rq, LOG_NOTICE, "validated basic user against cache: %s", basic.user); ret = HA_OK; goto finally; @@ -153,42 +152,41 @@ static int do_basic_response(bd_context_t* ctx, const char* header, if(!basic.user || !basic.user[0] || !basic.password || !basic.password[0]) { - ha_messagex(LOG_NOTICE, "bd: no valid basic auth info"); + ha_messagex(rq, LOG_NOTICE, "no valid basic auth info"); ret = HA_FALSE; goto finally; } ASSERT(ctx->f_validate_basic); - ret = ctx->f_validate_basic(req, basic.user, basic.password); + ret = ctx->f_validate_basic(rq, basic.user, basic.password); finally: if(ret == HA_OK) { - resp->code = HA_SERVER_OK; - resp->detail = basic.user; + rq->resp_code = HA_SERVER_OK; + rq->resp_detail = basic.user; /* We put this connection into the successful connections */ - ret = add_cached_basic(ctx, req->context, basic.key); + ret = add_cached_basic(ctx, rq->context, basic.key); } return ret; } -static int do_digest_challenge(bd_context_t* ctx, const ha_request_t* req, - ha_response_t* resp, int stale) +static int do_digest_challenge(ha_request_t* rq, bd_context_t* ctx, int stale) { unsigned char nonce[DIGEST_NONCE_LEN]; const char* nonce_str; const char* header; - ASSERT(ctx && resp && req); + ASSERT(ctx && rq); #ifdef _DEBUG - if(req->context->digest_debugnonce) + if(rq->context->digest_debugnonce) { - nonce_str = req->context->digest_debugnonce; - ha_messagex(LOG_WARNING, "bd: using debug nonce. security non-existant."); + nonce_str = rq->context->digest_debugnonce; + ha_messagex(rq, LOG_WARNING, "using debug nonce. security non-existant."); } else #endif @@ -196,28 +194,27 @@ static int do_digest_challenge(bd_context_t* ctx, const ha_request_t* req, unsigned char nonce[DIGEST_NONCE_LEN]; digest_makenonce(nonce, g_digest_secret, NULL); - nonce_str = ha_bufenchex(req->buf, nonce, DIGEST_NONCE_LEN); + nonce_str = ha_bufenchex(rq->buf, nonce, DIGEST_NONCE_LEN); if(!nonce_str) - return HA_CRITERROR; + return HA_CRITERROR; } /* Now generate a message to send */ - header = digest_challenge(req->buf, nonce_str, req->context->realm, - req->digest_domain, stale); + header = digest_challenge(rq->buf, nonce_str, rq->context->realm, + rq->digest_domain, stale); if(!header) return HA_CRITERROR; /* And append it nicely */ - resp->code = HA_SERVER_DECLINE; - ha_addheader(resp, "WWW-Authenticate", header); + rq->resp_code = HA_SERVER_DECLINE; + ha_addheader(rq, "WWW-Authenticate", header); - ha_messagex(LOG_DEBUG, "bd: created digest challenge with nonce: %s", nonce_str); + ha_messagex(rq, LOG_DEBUG, "created digest challenge with nonce: %s", nonce_str); return HA_OK; } -static int do_digest_response(bd_context_t* ctx, const char* header, - const ha_request_t* req, ha_response_t* resp) +static int do_digest_response(ha_request_t* rq, bd_context_t* ctx, const char* header) { unsigned char nonce[DIGEST_NONCE_LEN]; digest_header_t dg; @@ -228,26 +225,26 @@ static int do_digest_response(bd_context_t* ctx, const char* header, int stale = 0; int r; - ASSERT(ctx && header && req && resp); + ASSERT(ctx && header && rq); /* We use this below to send a default response */ - resp->code = -1; + rq->resp_code = -1; - if((r = digest_parse(header, req->buf, &dg, nonce)) < 0) + if((r = digest_parse(header, rq->buf, &dg, nonce)) < 0) return r; #ifdef _DEBUG - if(req->context->digest_debugnonce) + if(rq->context->digest_debugnonce) { - if(dg.nonce && strcmp(dg.nonce, req->context->digest_debugnonce) != 0) + if(dg.nonce && strcmp(dg.nonce, rq->context->digest_debugnonce) != 0) { ret = HA_FALSE; - ha_messagex(LOG_WARNING, "bd: digest response contains invalid nonce"); + ha_messagex(rq, LOG_WARNING, "digest response contains invalid nonce"); goto finally; } /* Do a rough hash into the real nonce, for use as a key */ - md5_string(nonce, req->context->digest_debugnonce); + md5_string(nonce, rq->context->digest_debugnonce); /* Debug nonce's never expire */ expiry = time(NULL); @@ -259,18 +256,18 @@ static int do_digest_response(bd_context_t* ctx, const char* header, if(r != HA_OK) { if(r == HA_FALSE) - ha_messagex(LOG_WARNING, "bd: digest response contains invalid nonce"); + ha_messagex(rq, LOG_WARNING, "digest response contains invalid nonce"); goto finally; } } - rec = get_cached_digest(ctx, req->context, nonce); + rec = get_cached_digest(ctx, rq->context, nonce); /* Check to see if we're stale */ - if((expiry + req->context->cache_timeout) <= time(NULL)) + if((expiry + rq->context->cache_timeout) <= time(NULL)) { - ha_messagex(LOG_INFO, "bd: nonce expired, sending stale challenge: %s", + ha_messagex(rq, LOG_INFO, "nonce expired, sending stale challenge: %s", dg.username); stale = 1; @@ -279,7 +276,7 @@ static int do_digest_response(bd_context_t* ctx, const char* header, if(!rec) { - ha_messagex(LOG_INFO, "bd: no record in cache, creating one: %s", dg.username); + ha_messagex(rq, LOG_INFO, "no record in cache, creating one: %s", dg.username); /* * If we're valid but don't have a record in the @@ -294,7 +291,7 @@ static int do_digest_response(bd_context_t* ctx, const char* header, } ASSERT(ctx->f_complete_digest); - r = ctx->f_complete_digest(req, dg.username, rec->ha1); + r = ctx->f_complete_digest(rq, dg.username, rec->ha1); if(r != HA_OK) { ret = r; @@ -308,32 +305,32 @@ static int do_digest_response(bd_context_t* ctx, const char* header, rec->nc++; } - ret = digest_check(&dg, rec, req->context, req->buf, - req->args[AUTH_ARG_METHOD], req->args[AUTH_ARG_URI]); + ret = digest_check(&dg, rec, rq->context, rq->buf, + rq->req_args[AUTH_ARG_METHOD], rq->req_args[AUTH_ARG_URI]); if(ret == HA_BADREQ) { ret = HA_FALSE; - resp->code = HA_SERVER_BADREQ; + rq->resp_code = HA_SERVER_BADREQ; } else if(ret == HA_OK) { - resp->code = HA_SERVER_OK; - resp->detail = dg.username; + rq->resp_code = HA_SERVER_OK; + rq->resp_detail = dg.username; /* Figure out if we need a new nonce */ - if((expiry + (req->context->cache_timeout - - (req->context->cache_timeout / 8))) < time(NULL)) + if((expiry + (rq->context->cache_timeout - + (rq->context->cache_timeout / 8))) < time(NULL)) { - ha_messagex(LOG_INFO, "bd: nonce almost expired, creating new one: %s", + ha_messagex(rq, LOG_INFO, "nonce almost expired, creating new one: %s", dg.username); digest_makenonce(nonce, g_digest_secret, NULL); stale = 1; } - t = digest_respond(req->buf, &dg, rec, stale ? nonce : NULL); + t = digest_respond(rq->buf, &dg, rec, stale ? nonce : NULL); if(!t) { ret = HA_CRITERROR; @@ -341,12 +338,12 @@ static int do_digest_response(bd_context_t* ctx, const char* header, } if(t[0]) - ha_addheader(resp, "Authentication-Info", t); + ha_addheader(rq, "Authentication-Info", t); - ha_messagex(LOG_NOTICE, "bd: validated digest user: %s", dg.username); + ha_messagex(rq, LOG_NOTICE, "validated digest user: %s", dg.username); /* Put the connection into the cache */ - if((r = save_cached_digest(ctx, req->context, rec)) < 0) + if((r = save_cached_digest(ctx, rq->context, rec)) < 0) ret = r; rec = NULL; @@ -359,8 +356,8 @@ finally: free(rec); /* If nobody above responded then challenge the client again */ - if(resp->code == -1) - return do_digest_challenge(ctx, req, resp, stale); + if(rq->resp_code == -1) + return do_digest_challenge(rq, ctx, stale); return ret; } @@ -375,7 +372,7 @@ int bd_init(ha_context_t* context) /* Global initialization */ if(!context) { - ha_messagex(LOG_DEBUG, "bd: generating secret"); + ha_messagex(NULL, LOG_DEBUG, "generating secret"); return ha_genrandom(g_digest_secret, DIGEST_SECRET_LEN); } @@ -390,15 +387,15 @@ int bd_init(ha_context_t* context) /* Make sure there are some types of authentication we can do */ if(!(context->allowed_types & (HA_TYPE_BASIC | HA_TYPE_DIGEST))) { - ha_messagex(LOG_ERR, "bd: module configured, but does not implement any " - "configured authentication type."); + ha_messagex(NULL, LOG_ERR, "module configured, but does not implement any " + "configured authentication type."); return HA_FAILED; } /* The cache for digest records and basic */ if(!(ctx->cache = hsh_create(MD5_LEN))) { - ha_messagex(LOG_CRIT, "out of memory"); + ha_messagex(NULL, LOG_CRIT, "out of memory"); return HA_CRITERROR; } @@ -406,7 +403,7 @@ int bd_init(ha_context_t* context) htc.arg = NULL; hsh_set_table_calls(ctx->cache, &htc); - ha_messagex(LOG_INFO, "ldap: initialized handler"); + ha_messagex(NULL, LOG_INFO, "initialized handler"); } return HA_OK; @@ -428,54 +425,54 @@ void bd_destroy(ha_context_t* context) if(ctx->cache) hsh_free(ctx->cache); - ha_messagex(LOG_INFO, "bd: uninitialized handler"); + ha_messagex(NULL, LOG_INFO, "uninitialized handler"); } -int bd_process(const ha_request_t* req, ha_response_t* resp) +int bd_process(ha_request_t* rq) { - bd_context_t* ctx = (bd_context_t*)req->context->ctx_data; + bd_context_t* ctx = (bd_context_t*)rq->context->ctx_data; time_t t = time(NULL); const char* header = NULL; int ret, r; - ASSERT(req && resp); - ASSERT(req->args[AUTH_ARG_METHOD]); - ASSERT(req->args[AUTH_ARG_URI]); + ASSERT(rq); + ASSERT(rq->req_args[AUTH_ARG_METHOD]); + ASSERT(rq->req_args[AUTH_ARG_URI]); ha_lock(NULL); /* Purge out stale connection stuff. */ - r = hsh_purge(ctx->cache, t - req->context->cache_timeout); + r = hsh_purge(ctx->cache, t - rq->context->cache_timeout); ha_unlock(NULL); if(r > 0) - ha_messagex(LOG_DEBUG, "ldap: purged cache records: %d", r); + ha_messagex(rq, LOG_DEBUG, "purged cache records: %d", r); /* We use this below to detect whether to send a default response */ - resp->code = -1; + rq->resp_code = -1; /* Check the headers and see if we got a response thingy */ - if(req->context->allowed_types & HA_TYPE_DIGEST) + if(rq->context->allowed_types & HA_TYPE_DIGEST) { - header = ha_getheader(req, "Authorization", HA_PREFIX_DIGEST); + header = ha_getheader(rq, "Authorization", HA_PREFIX_DIGEST); if(header) { - ha_messagex(LOG_DEBUG, "ldap: processing digest auth header"); - ret = do_digest_response(ctx, header, req, resp); + ha_messagex(rq, LOG_DEBUG, "processing digest auth header"); + ret = do_digest_response(rq, ctx, header); if(ret < 0) return ret; } } /* Or a basic authentication */ - if(!header && req->context->allowed_types & HA_TYPE_BASIC) + if(!header && rq->context->allowed_types & HA_TYPE_BASIC) { - header = ha_getheader(req, "Authorization", HA_PREFIX_BASIC); + header = ha_getheader(rq, "Authorization", HA_PREFIX_BASIC); if(header) { - ha_messagex(LOG_DEBUG, "bd: processing basic auth header"); - ret = do_basic_response(ctx, header, req, resp); + ha_messagex(rq, LOG_DEBUG, "processing basic auth header"); + ret = do_basic_response(rq, ctx, header); if(ret < 0) return ret; } @@ -483,24 +480,24 @@ int bd_process(const ha_request_t* req, ha_response_t* resp) /* Send a default response if that's what we need */ - if(resp->code == -1) + if(rq->resp_code == -1) { - resp->code = HA_SERVER_DECLINE; + rq->resp_code = HA_SERVER_DECLINE; - if(req->context->allowed_types & HA_TYPE_BASIC) + if(rq->context->allowed_types & HA_TYPE_BASIC) { - ha_bufmcat(req->buf, "BASIC realm=\"", req->context->realm , "\"", NULL); + ha_bufmcat(rq->buf, "BASIC realm=\"", rq->context->realm , "\"", NULL); - if(ha_buferr(req->buf)) + if(ha_buferr(rq->buf)) return HA_CRITERROR; - ha_addheader(resp, "WWW-Authenticate", ha_bufdata(req->buf)); - ha_messagex(LOG_DEBUG, "bd: sent basic auth request"); + ha_addheader(rq, "WWW-Authenticate", ha_bufdata(rq->buf)); + ha_messagex(rq, LOG_DEBUG, "sent basic auth request"); } - if(req->context->allowed_types & HA_TYPE_DIGEST) + if(rq->context->allowed_types & HA_TYPE_DIGEST) { - ret = do_digest_challenge(ctx, req, resp, 0); + ret = do_digest_challenge(rq, ctx, 0); if(ret < 0) return ret; } diff --git a/daemon/bd.h b/daemon/bd.h index 450c8e1..272e09a 100644 --- a/daemon/bd.h +++ b/daemon/bd.h @@ -17,8 +17,8 @@ * HA_OK: completed successfully * HA_FAILED: error retrieving hash (should have logged error) */ -typedef int (*bd_complete_digest)(const ha_request_t* req, - const char* user, unsigned char* ha1); +typedef int (*bd_complete_digest)(ha_request_t* rq, + const char* user, unsigned char* ha1); /* * A callback for validating a given user's password. @@ -28,8 +28,8 @@ typedef int (*bd_complete_digest)(const ha_request_t* req, * HA_FALSE: invalid password * HA_FAILED: error validating (should have logged error) */ -typedef int (*bd_validate_basic)(const ha_request_t* req, - const char* user, const char* password); +typedef int (*bd_validate_basic)(ha_request_t* rq, + const char* user, const char* password); /* ---------------------------------------------------------------------------------- * Base Context @@ -66,6 +66,6 @@ void bd_destroy(ha_context_t* context); * The base/digest processer for requests. Call this from your * 'derived' handler process function. */ -int bd_process(const ha_request_t* req, ha_response_t* resp); +int bd_process(ha_request_t* rq); #endif /* BD_H */ diff --git a/daemon/digest.c b/daemon/digest.c index 405a661..099bf31 100644 --- a/daemon/digest.c +++ b/daemon/digest.c @@ -12,103 +12,103 @@ static unsigned int g_digest_unique = 0; typedef struct internal_nonce { - unsigned char hash[MD5_LEN]; - time_t tm; - unsigned int unique; + unsigned char hash[MD5_LEN]; + time_t tm; + unsigned int unique; } internal_nonce_t; void digest_makenonce(unsigned char* nonce, unsigned char* secret, unsigned char* old) { - internal_nonce_t in; - md5_ctx_t md5; - - ASSERT(nonce && secret); - ASSERT(sizeof(internal_nonce_t) == DIGEST_NONCE_LEN); - - if(old) - { - internal_nonce_t* nold = (internal_nonce_t*)old; - in.tm = nold->tm; - in.unique = nold->unique; - } - else - { - in.tm = time(NULL); - ha_lock(NULL); - in.unique = g_digest_unique++; - ha_unlock(NULL); - } - - md5_init(&md5); - md5_update(&md5, secret, DIGEST_SECRET_LEN); - md5_update(&md5, &(in.tm), sizeof(in.tm)); - md5_update(&md5, &(in.unique), sizeof(in.unique)); - md5_final(in.hash, &md5); - - memcpy(nonce, &in, DIGEST_NONCE_LEN); + internal_nonce_t in; + md5_ctx_t md5; + + ASSERT(nonce && secret); + ASSERT(sizeof(internal_nonce_t) == DIGEST_NONCE_LEN); + + if(old) + { + internal_nonce_t* nold = (internal_nonce_t*)old; + in.tm = nold->tm; + in.unique = nold->unique; + } + else + { + in.tm = time(NULL); + ha_lock(NULL); + in.unique = g_digest_unique++; + ha_unlock(NULL); + } + + md5_init(&md5); + md5_update(&md5, secret, DIGEST_SECRET_LEN); + md5_update(&md5, &(in.tm), sizeof(in.tm)); + md5_update(&md5, &(in.unique), sizeof(in.unique)); + md5_final(in.hash, &md5); + + memcpy(nonce, &in, DIGEST_NONCE_LEN); } int digest_checknonce(unsigned char* nonce, unsigned char* secret, time_t* tm) { - internal_nonce_t in; + internal_nonce_t in; - ASSERT(nonce && secret); - ASSERT(sizeof(internal_nonce_t) == DIGEST_NONCE_LEN); + ASSERT(nonce && secret); + ASSERT(sizeof(internal_nonce_t) == DIGEST_NONCE_LEN); - digest_makenonce((unsigned char*)&in, secret, nonce); + digest_makenonce((unsigned char*)&in, secret, nonce); - if(memcmp((unsigned char*)&in, nonce, DIGEST_SECRET_LEN) == 0) - { - if(tm) - *tm = in.tm; + if(memcmp((unsigned char*)&in, nonce, DIGEST_SECRET_LEN) == 0) + { + if(tm) + *tm = in.tm; - return HA_OK; - } + return HA_OK; + } - return HA_FALSE; + return HA_FALSE; } digest_record_t* digest_makerec(unsigned char* nonce, const char* user) { - digest_record_t* rec = (digest_record_t*)malloc(sizeof(*rec)); + digest_record_t* rec = (digest_record_t*)malloc(sizeof(*rec)); - ASSERT(nonce && user); + ASSERT(nonce && user); - if(!rec) - { - ha_messagex(LOG_CRIT, "out of memory"); - return NULL; - } + if(!rec) + { + ha_messagex(NULL, LOG_CRIT, "out of memory"); + return NULL; + } - memset(rec, 0, sizeof(*rec)); - memcpy(rec->nonce, nonce, DIGEST_NONCE_LEN); + memset(rec, 0, sizeof(*rec)); + memcpy(rec->nonce, nonce, DIGEST_NONCE_LEN); - md5_string(rec->userhash, user); - return rec; + md5_string(rec->userhash, user); + return rec; } const char* digest_challenge(ha_buffer_t* buf, const char* nonce_str, const char* realm, const char* domains, int stale) { - ASSERT(buf && realm && nonce_str); + ASSERT(buf && realm && nonce_str); - ha_bufmcat(buf, HA_PREFIX_DIGEST, " realm=\"", realm, "\", nonce=\"", - nonce_str, "\", qop=\"auth\", algorithm=\"MD5\"", NULL); + ha_bufmcat(buf, HA_PREFIX_DIGEST, " realm=\"", realm, "\", nonce=\"", + nonce_str, "\", qop=\"auth\", algorithm=\"MD5\"", NULL); - if(domains) - { - ha_bufjoin(buf); - ha_bufmcat(buf, ", domain=\"", domains, "\"", NULL); - } + if(domains) + { + ha_bufjoin(buf); + ha_bufmcat(buf, ", domain=\"", domains, "\"", NULL); + } - if(stale) - { - ha_bufjoin(buf); - ha_bufcat(buf, ", stale=true"); - } + if(stale) + { + ha_bufjoin(buf); + ha_bufcat(buf, ", stale=true"); + } - return ha_bufdata(buf); + return ha_bufdata(buf); } /* @@ -130,316 +130,396 @@ const char* digest_challenge(ha_buffer_t* buf, const char* nonce_str, int digest_parse(char* header, ha_buffer_t* buf, digest_header_t* rec, unsigned char* nonce) { - char next; - char* key; - char* value; - - ASSERT(header && buf && rec); - - header = ha_bufcpy(buf, header); - - if(!header) - return HA_CRITERROR; - - memset(rec, 0, sizeof(*rec)); - - while(header[0]) - { - /* find key */ - header = (char*)trim_start(header); - key = header; + char next; + char* key; + char* value; - while(header[0] && header[0] != '=' && header[0] != ',' && - !isspace(header[0])) - header++; + ASSERT(header && buf && rec); - /* null terminate and move on */ - next = header[0]; - header[0] = '\0'; - header++; + header = ha_bufcpy(buf, header); - if(!next) - break; - - if(isspace(header[0])) - { - header = (char*)trim_start(header); - next = header[0]; - } + if(!header) + return HA_CRITERROR; - /* find value */ + memset(rec, 0, sizeof(*rec)); - if(next == '=') + while(header[0]) { - header = (char*)trim_start(header); + /* find key */ + header = (char*)trim_start(header); + key = header; - if(header[0] == '\"') /* quoted string */ - { - header++; - value = header; - - while(header[0] && header[0] != '\"') - header++; + while(header[0] && header[0] != '=' && header[0] != ',' && + !isspace(header[0])) + header++; + /* null terminate and move on */ next = header[0]; - header[0] = 0; + header[0] = '\0'; header++; - } - else /* token */ - { - value = header; + if(!next) + break; + + if(isspace(header[0])) + { + header = (char*)trim_start(header); + next = header[0]; + } - while(header[0] && header[0] != ',' && !isspace(header[0])) - header++; + /* find value */ - next = header[0]; - header[0] = 0; - header++; - } - - if(next != ',') - { - while(header[0] && header[0] != ',') - header++; - - if(header[0]) - header++; - } - - if(!strcasecmp(key, "username")) - rec->username = value; - else if(!strcasecmp(key, "realm")) - rec->realm = value; - else if (!strcasecmp(key, "nonce")) - rec->nonce = value; - else if (!strcasecmp(key, "uri")) - rec->uri = value; - else if (!strcasecmp(key, "response")) - rec->digest = value; - else if (!strcasecmp(key, "algorithm")) - rec->algorithm = value; - else if (!strcasecmp(key, "cnonce")) - rec->cnonce = value; - else if (!strcasecmp(key, "opaque")) - rec->opaque = value; - else if (!strcasecmp(key, "qop")) - rec->qop = value; - else if (!strcasecmp(key, "nc")) - rec->nc = value; + if(next == '=') + { + header = (char*)trim_start(header); + + if(header[0] == '\"') /* quoted string */ + { + header++; + value = header; + + while(header[0] && header[0] != '\"') + header++; + + next = header[0]; + header[0] = 0; + header++; + } + + else /* token */ + { + value = header; + + while(header[0] && header[0] != ',' && !isspace(header[0])) + header++; + + next = header[0]; + header[0] = 0; + header++; + } + + if(next != ',') + { + while(header[0] && header[0] != ',') + header++; + + if(header[0]) + header++; + } + + if(!strcasecmp(key, "username")) + rec->username = value; + else if(!strcasecmp(key, "realm")) + rec->realm = value; + else if (!strcasecmp(key, "nonce")) + rec->nonce = value; + else if (!strcasecmp(key, "uri")) + rec->uri = value; + else if (!strcasecmp(key, "response")) + rec->digest = value; + else if (!strcasecmp(key, "algorithm")) + rec->algorithm = value; + else if (!strcasecmp(key, "cnonce")) + rec->cnonce = value; + else if (!strcasecmp(key, "opaque")) + rec->opaque = value; + else if (!strcasecmp(key, "qop")) + rec->qop = value; + else if (!strcasecmp(key, "nc")) + rec->nc = value; + } } - } - if(nonce) - { - memset(nonce, 0, DIGEST_NONCE_LEN); - - if(rec->nonce) + if(nonce) { - size_t len = DIGEST_NONCE_LEN; - void* d = ha_bufdechex(buf, rec->nonce, &len); + memset(nonce, 0, DIGEST_NONCE_LEN); + + if(rec->nonce) + { + size_t len = DIGEST_NONCE_LEN; + void* d = ha_bufdechex(buf, rec->nonce, &len); - if(d && len == DIGEST_NONCE_LEN) - memcpy(nonce, d, DIGEST_NONCE_LEN); + if(d && len == DIGEST_NONCE_LEN) + memcpy(nonce, d, DIGEST_NONCE_LEN); + } } - } - return HA_OK; + return HA_OK; } int digest_check(digest_header_t* dg, digest_record_t* rec, const ha_context_t* ctx, ha_buffer_t* buf, const char* method, const char* uri) { - unsigned char hash[MD5_LEN]; - md5_ctx_t md5; - const char* digest; - const char* t; - - ASSERT(ctx && method && buf && dg && rec); - - /* TODO: Many of these should somehow communicate BAD REQ back to the client */ - - /* Check for digest */ - if(!dg->digest || !dg->digest[0]) - { - ha_messagex(LOG_WARNING, "digest response missing digest"); - return HA_BADREQ; - } - - /* Username */ - if(!dg->username || !dg->username[0]) - { - ha_messagex(LOG_WARNING, "digest response missing username"); - return HA_BADREQ; - } - - if(md5_strcmp(rec->userhash, dg->username) != 0) - { - ha_messagex(LOG_ERR, "digest response contains invalid username"); - return HA_FALSE; - } - - /* The realm */ - if(!dg->realm) - { - ha_messagex(LOG_WARNING, "digest response contains missing realm"); - return HA_BADREQ; - } - - if(strcmp(dg->realm, ctx->realm) != 0) - { - ha_messagex(LOG_ERR, "digest response contains invalid realm: %s", dg->realm); - return HA_FALSE; - } + unsigned char hash[MD5_LEN]; + md5_ctx_t md5; + const char* digest; + const char* t; - /* Components in the new RFC */ - if(dg->qop) - { - /* - * We only support 'auth' qop. We don't have access to the data - * and wouldn't be able to support anything else. - */ - if(strcmp(dg->qop, "auth") != 0) + ASSERT(ctx && method && buf && dg && rec); + + /* TODO: This stuff should probably go into bd.c */ + + /* Check for digest */ + if(!dg->digest || !dg->digest[0]) { - ha_messagex(LOG_WARNING, "digest response contains unknown or unsupported qop: '%s'", - dg->qop ? dg->qop : ""); - return HA_BADREQ; + ha_messagex(NULL, LOG_WARNING, "digest response missing digest"); + return HA_BADREQ; } - /* The cnonce */ - if(!dg->cnonce || !dg->cnonce[0]) + /* Username */ + if(!dg->username || !dg->username[0]) { - ha_messagex(LOG_WARNING, "digest response is missing cnonce value"); - return HA_BADREQ; + ha_messagex(NULL, LOG_WARNING, "digest response missing username"); + return HA_BADREQ; + } + + if(md5_strcmp(rec->userhash, dg->username) != 0) + { + ha_messagex(NULL, LOG_ERR, "digest response contains invalid username"); + return HA_FALSE; } - if(!ctx->digest_ignorenc) + /* The realm */ + if(!dg->realm) { - /* The nonce count */ - if(!dg->nc || !dg->nc[0]) - { - ha_messagex(LOG_WARNING, "digest response is missing nc value"); + ha_messagex(NULL, LOG_WARNING, "digest response contains missing realm"); return HA_BADREQ; - } + } - /* Validate the nc */ - else - { - char* e; - long nc = strtol(dg->nc, &e, 16); + if(strcmp(dg->realm, ctx->realm) != 0) + { + ha_messagex(NULL, LOG_ERR, "digest response contains invalid realm: %s", dg->realm); + return HA_FALSE; + } - if(*e) + /* Components in the new RFC */ + if(dg->qop) + { + /* + * We only support 'auth' qop. We don't have access to the data + * and wouldn't be able to support anything else. + */ + if(strcmp(dg->qop, "auth") != 0) { - ha_messagex(LOG_ERR, "digest response has invalid nc value: %s", dg->nc); - return HA_BADREQ; + ha_messagex(NULL, LOG_WARNING, "digest response contains unknown or unsupported qop: '%s'", + dg->qop ? dg->qop : ""); + return HA_BADREQ; } - /* If we didn't a nc then save it away */ - if(!*e && rec->nc == 0) - rec->nc = nc; + /* The cnonce */ + if(!dg->cnonce || !dg->cnonce[0]) + { + ha_messagex(NULL, LOG_WARNING, "digest response is missing cnonce value"); + return HA_BADREQ; + } - if(*e || nc != rec->nc) + if(!ctx->digest_ignorenc) { - ha_messagex(LOG_WARNING, "digest response has wrong nc value. " - "possible replay attack: %s", dg->nc); - return HA_FALSE; + /* The nonce count */ + if(!dg->nc || !dg->nc[0]) + { + ha_messagex(NULL, LOG_WARNING, "digest response is missing nc value"); + return HA_BADREQ; + } + + /* Validate the nc */ + else + { + char* e; + long nc = strtol(dg->nc, &e, 16); + + if(*e) + { + ha_messagex(NULL, LOG_ERR, "digest response has invalid nc value: %s", dg->nc); + return HA_BADREQ; + } + + /* If we didn't a nc then save it away */ + if(!*e && rec->nc == 0) + rec->nc = nc; + + if(*e || nc != rec->nc) + { + ha_messagex(NULL, LOG_WARNING, "digest response has wrong nc value. " + "possible replay attack: %s", dg->nc); + return HA_FALSE; + } + } } - } } - } - - /* The algorithm */ - if(dg->algorithm && strcasecmp(dg->algorithm, "MD5") != 0) - { - ha_messagex(LOG_WARNING, "digest response contains unknown or unsupported algorithm: '%s'", - dg->algorithm ? dg->algorithm : ""); - return HA_BADREQ; - } - - /* Request URI */ - if(!dg->uri) - { - ha_messagex(LOG_WARNING, "digest response is missing uri"); - return HA_BADREQ; - } - - if(!ctx->digest_ignoreuri && strcmp(dg->uri, uri) != 0) - { - ha_uri_t d_uri; - ha_uri_t s_uri; - - if(ha_uriparse(buf, dg->uri, &d_uri) < 0) + + /* The algorithm */ + if(dg->algorithm && strcasecmp(dg->algorithm, "MD5") != 0) { - if(ha_buferr(buf)) - return HA_CRITERROR; + ha_messagex(NULL, LOG_WARNING, "digest response contains unknown or unsupported algorithm: '%s'", + dg->algorithm ? dg->algorithm : ""); + return HA_BADREQ; + } - ha_messagex(LOG_WARNING, "digest response constains invalid uri: %s", dg->uri); - return HA_BADREQ; + /* Request URI */ + if(!dg->uri) + { + ha_messagex(NULL, LOG_WARNING, "digest response is missing uri"); + return HA_BADREQ; } - if(ha_uriparse(buf, uri, &s_uri) < 0) + if(!ctx->digest_ignoreuri && strcmp(dg->uri, uri) != 0) { - if(ha_buferr(buf)) + ha_uri_t d_uri; + ha_uri_t s_uri; + + if(ha_uriparse(buf, dg->uri, &d_uri) < 0) + { + if(ha_buferr(buf)) + return HA_CRITERROR; + + ha_messagex(NULL, LOG_WARNING, "digest response constains invalid uri: %s", dg->uri); + return HA_BADREQ; + } + + if(ha_uriparse(buf, uri, &s_uri) < 0) + { + if(ha_buferr(buf)) + return HA_CRITERROR; + + ha_messagex(NULL, LOG_ERR, "server sent us an invalid uri"); + return HA_BADREQ; + } + + if(ha_uricmp(&d_uri, &s_uri) != 0) + { + ha_messagex(NULL, LOG_ERR, "digest response contains wrong uri: %s " + "(should be %s)", dg->uri, uri); + return HA_FALSE; + } + } + + /* + * nonce: should have already been validated by the caller who + * found this nice rec structure to pass us. + * + * opaque: We also don't use opaque. The caller should have validated it + * if it's used there. + */ + + /* + * Now we validate the digest response + */ + + /* Encode ha1 */ + t = ha_bufenchex(buf, rec->ha1, MD5_LEN); + + if(t == NULL) + return HA_CRITERROR; + + /* Encode ha2 */ + md5_init(&md5); + md5_update(&md5, method, strlen(method)); + md5_update(&md5, ":", 1); + md5_update(&md5, dg->uri, strlen(dg->uri)); + md5_final(hash, &md5); + + ha_bufenchex(buf, hash, MD5_LEN); + + if(!ha_bufdata(buf)) return HA_CRITERROR; - ha_messagex(LOG_ERR, "server sent us an invalid uri"); - return HA_BADREQ; + + /* Old style digest (RFC 2069) */ + if(!dg->qop) + { + md5_init(&md5); + md5_update(&md5, t, MD5_LEN * 2); /* ha1 */ + md5_update(&md5, ":", 1); + md5_update(&md5, dg->nonce, strlen(dg->nonce)); /* nonce */ + md5_update(&md5, ":", 1); + md5_update(&md5, ha_bufdata(buf), MD5_LEN * 2); /* ha1 */ + md5_final(hash, &md5); + } + + /* New style 'auth' digest (RFC 2617) */ + else + { + md5_init(&md5); + md5_update(&md5, t, MD5_LEN * 2); /* ha1 */ + md5_update(&md5, ":", 1); + md5_update(&md5, dg->nonce, strlen(dg->nonce)); /* nonce */ + md5_update(&md5, ":", 1); + md5_update(&md5, dg->nc, strlen(dg->nc)); /* nc */ + md5_update(&md5, ":", 1); + md5_update(&md5, dg->cnonce, strlen(dg->cnonce)); /* cnonce */ + md5_update(&md5, ":", 1); + md5_update(&md5, dg->qop, strlen(dg->qop)); /* qop */ + md5_update(&md5, ":", 1); + md5_update(&md5, ha_bufdata(buf), MD5_LEN * 2); /* ha2 */ + md5_final(hash, &md5); } - if(ha_uricmp(&d_uri, &s_uri) != 0) + /* Encode the digest */ + digest = ha_bufenchex(buf, hash, MD5_LEN); + + if(digest == NULL) + return HA_CRITERROR; + + if(strcasecmp(dg->digest, digest) != 0) { - ha_messagex(LOG_ERR, "digest response contains wrong uri: %s " - "(should be %s)", dg->uri, uri); - return HA_FALSE; + ha_messagex(NULL, LOG_WARNING, "digest authentication failed for user: %s", dg->username); + return HA_FALSE; } - } - /* - * nonce: should have already been validated by the caller who - * found this nice rec structure to pass us. - * - * opaque: We also don't use opaque. The caller should have validated it - * if it's used there. - */ + return HA_OK; +} - /* - * Now we validate the digest response - */ +const char* digest_respond(ha_buffer_t* buf, digest_header_t* dg, + digest_record_t* rec, unsigned char* next) +{ + unsigned char hash[MD5_LEN]; + md5_ctx_t md5; + const char* nextnonce = NULL; + const char* t; - /* Encode ha1 */ - t = ha_bufenchex(buf, rec->ha1, MD5_LEN); + ASSERT(buf && dg && rec); - if(t == NULL) - return HA_CRITERROR; + /* This makes a new buffer */ + ha_bufcpy(buf, ""); - /* Encode ha2 */ - md5_init(&md5); - md5_update(&md5, method, strlen(method)); - md5_update(&md5, ":", 1); - md5_update(&md5, dg->uri, strlen(dg->uri)); - md5_final(hash, &md5); + if(next) + { + nextnonce = ha_bufenc64(buf, next, DIGEST_NONCE_LEN); - ha_bufenchex(buf, hash, MD5_LEN); + if(nextnonce == NULL) + return NULL; + } - if(!ha_bufdata(buf)) - return HA_CRITERROR; + /* For older clients RFC 2069 */ + if(!dg->qop) + { + if(nextnonce) + ha_bufmcat(buf, "nextnonce=\"", nextnonce, "\"", NULL); + + return ha_bufdata(buf); + } + + /* Otherwise we do the whole song and dance */ + /* Encode ha1 */ + t = ha_bufenchex(buf, rec->ha1, MD5_LEN); - /* Old style digest (RFC 2069) */ - if(!dg->qop) - { + if(t == NULL) + return NULL; + + /* Encode ha2 */ md5_init(&md5); - md5_update(&md5, t, MD5_LEN * 2); /* ha1 */ - md5_update(&md5, ":", 1); - md5_update(&md5, dg->nonce, strlen(dg->nonce)); /* nonce */ md5_update(&md5, ":", 1); - md5_update(&md5, ha_bufdata(buf), MD5_LEN * 2); /* ha1 */ + md5_update(&md5, dg->uri, strlen(dg->uri)); md5_final(hash, &md5); - } - /* New style 'auth' digest (RFC 2617) */ - else - { + ha_bufenchex(buf, hash, MD5_LEN); + + if(!ha_bufdata(buf)) + return NULL; + + /* New style 'auth' digest (RFC 2617) */ md5_init(&md5); md5_update(&md5, t, MD5_LEN * 2); /* ha1 */ md5_update(&md5, ":", 1); @@ -453,119 +533,39 @@ int digest_check(digest_header_t* dg, digest_record_t* rec, const ha_context_t* md5_update(&md5, ":", 1); md5_update(&md5, ha_bufdata(buf), MD5_LEN * 2); /* ha2 */ md5_final(hash, &md5); - } - /* Encode the digest */ - digest = ha_bufenchex(buf, hash, MD5_LEN); + /* Encode the digest */ + t = ha_bufenchex(buf, hash, MD5_LEN); - if(digest == NULL) - return HA_CRITERROR; + if(t == NULL) + return NULL; - if(strcasecmp(dg->digest, digest) != 0) - { - ha_messagex(LOG_WARNING, "digest authentication failed for user: %s", dg->username); - return HA_FALSE; - } - - return HA_OK; -} - -const char* digest_respond(ha_buffer_t* buf, digest_header_t* dg, - digest_record_t* rec, unsigned char* next) -{ - unsigned char hash[MD5_LEN]; - md5_ctx_t md5; - const char* nextnonce = NULL; - const char* t; - - ASSERT(buf && dg && rec); + ha_bufmcat(buf, "rspauth=\"", t, "\"", + ", qop=", dg->qop, + ", nc=", dg->nc, + ", cnonce=\"", dg->cnonce, "\"", NULL); - /* This makes a new buffer */ - ha_bufcpy(buf, ""); - - if(next) - { - nextnonce = ha_bufenc64(buf, next, DIGEST_NONCE_LEN); - - if(nextnonce == NULL) - return NULL; - } - - /* For older clients RFC 2069 */ - if(!dg->qop) - { if(nextnonce) - ha_bufmcat(buf, "nextnonce=\"", nextnonce, "\"", NULL); + { + ha_bufjoin(buf); + ha_bufmcat(buf, ", nextnonce=\"", nextnonce, "\"", NULL); + } return ha_bufdata(buf); - } - - /* Otherwise we do the whole song and dance */ - - /* Encode ha1 */ - t = ha_bufenchex(buf, rec->ha1, MD5_LEN); - - if(t == NULL) - return NULL; - - /* Encode ha2 */ - md5_init(&md5); - md5_update(&md5, ":", 1); - md5_update(&md5, dg->uri, strlen(dg->uri)); - md5_final(hash, &md5); - - ha_bufenchex(buf, hash, MD5_LEN); - - if(!ha_bufdata(buf)) - return NULL; - - /* New style 'auth' digest (RFC 2617) */ - md5_init(&md5); - md5_update(&md5, t, MD5_LEN * 2); /* ha1 */ - md5_update(&md5, ":", 1); - md5_update(&md5, dg->nonce, strlen(dg->nonce)); /* nonce */ - md5_update(&md5, ":", 1); - md5_update(&md5, dg->nc, strlen(dg->nc)); /* nc */ - md5_update(&md5, ":", 1); - md5_update(&md5, dg->cnonce, strlen(dg->cnonce)); /* cnonce */ - md5_update(&md5, ":", 1); - md5_update(&md5, dg->qop, strlen(dg->qop)); /* qop */ - md5_update(&md5, ":", 1); - md5_update(&md5, ha_bufdata(buf), MD5_LEN * 2); /* ha2 */ - md5_final(hash, &md5); - - /* Encode the digest */ - t = ha_bufenchex(buf, hash, MD5_LEN); - - if(t == NULL) - return NULL; - - ha_bufmcat(buf, "rspauth=\"", t, "\"", - ", qop=", dg->qop, - ", nc=", dg->nc, - ", cnonce=\"", dg->cnonce, "\"", NULL); - - if(nextnonce) - { - ha_bufjoin(buf); - ha_bufmcat(buf, ", nextnonce=\"", nextnonce, "\"", NULL); - } - - return ha_bufdata(buf); } void digest_makeha1(unsigned char* digest, const char* user, const char* realm, const char* password) { - md5_ctx_t md5; + md5_ctx_t md5; - ASSERT(digest && user && realm && password); + ASSERT(digest && user && realm && password); - md5_init(&md5); - md5_update(&md5, user, strlen(user)); - md5_update(&md5, ":", 1); - md5_update(&md5, realm, strlen(realm)); - md5_update(&md5, ":", 1); - md5_update(&md5, password, strlen(password)); - md5_final(digest, &md5); + md5_init(&md5); + md5_update(&md5, user, strlen(user)); + md5_update(&md5, ":", 1); + md5_update(&md5, realm, strlen(realm)); + md5_update(&md5, ":", 1); + md5_update(&md5, password, strlen(password)); + md5_final(digest, &md5); } diff --git a/daemon/digest.h b/daemon/digest.h index 8b3ecdf..f763133 100644 --- a/daemon/digest.h +++ b/daemon/digest.h @@ -10,28 +10,28 @@ /* Parsed Digest response from the client */ typedef struct digest_header { - const char* scheme; - const char* realm; - const char* username; - const char* nonce; - const char* uri; - const char* method; - const char* digest; - const char* algorithm; - const char* cnonce; - const char* opaque; - const char* qop; - const char* nc; + const char* scheme; + const char* realm; + const char* username; + const char* nonce; + const char* uri; + const char* method; + const char* digest; + const char* algorithm; + const char* cnonce; + const char* opaque; + const char* qop; + const char* nc; } digest_header_t; /* Kept by the server for validating the client */ typedef struct digest_record { - unsigned char nonce[DIGEST_NONCE_LEN]; - unsigned char userhash[MD5_LEN]; - unsigned char ha1[MD5_LEN]; - unsigned int nc; + unsigned char nonce[DIGEST_NONCE_LEN]; + unsigned char userhash[MD5_LEN]; + unsigned char ha1[MD5_LEN]; + unsigned int nc; } digest_record_t; diff --git a/daemon/httpauthd.c b/daemon/httpauthd.c index c238a1a..17ed15c 100644 --- a/daemon/httpauthd.c +++ b/daemon/httpauthd.c @@ -36,15 +36,15 @@ extern ha_handler_t ntlm_handler; /* This is the list of all available handlers */ ha_handler_t* g_handlerlist[] = { - &simple_handler, - &ldap_handler, - &ntlm_handler + &simple_handler, + &ldap_handler, + &ntlm_handler }; typedef struct httpauth_loaded { - ha_context_t ctx; - struct httpauth_loaded* next; + ha_context_t ctx; + struct httpauth_loaded* next; } httpauth_loaded_t; @@ -58,34 +58,34 @@ httpauth_loaded_t* g_handlers = NULL; /* A command definition. Used in parsing */ typedef struct httpauth_command { - const char* name; - int code; - int word_args; /* Arguments to be parsed as words */ - int rest_arg; /* Parse remainder as one arg? */ - const char** headers; /* Headers needed/allowed */ + const char* name; + int code; + int word_args; /* Arguments to be parsed as words */ + int rest_arg; /* Parse remainder as one arg? */ + const char** headers; /* Headers needed/allowed */ } httpauth_command_t; /* The various valid headers for the auth command */ const char* kAuthHeaders[] = { - "Authorization", - NULL + "Authorization", + NULL }; /* The command definitions */ const httpauth_command_t kCommands[] = { - { "auth", REQTYPE_AUTH, 3, 0, kAuthHeaders }, - { "set", REQTYPE_SET, 1, 1, NULL }, - { "quit", REQTYPE_QUIT, 0, 0, NULL }, - { NULL, -1, 0, 0, NULL } + { "auth", REQTYPE_AUTH, 3, 0, kAuthHeaders }, + { "set", REQTYPE_SET, 1, 1, NULL }, + { "quit", REQTYPE_QUIT, 0, 0, NULL }, + { NULL, -1, 0, 0, NULL } }; typedef struct httpauth_thread { - pthread_t tid; - int fd; + pthread_t tid; + int fd; } httpauth_thread_t; @@ -126,9 +126,8 @@ static int usage(); static void writepid(const char* pid); static void* httpauth_thread(void* arg); static int httpauth_processor(int ifd, int ofd); -static int httpauth_respond(int ofd, int scode, int ccode, const char* msg); -static int process_auth(ha_request_t* req, ha_response_t* resp, - ha_buffer_t* outb); +static int httpauth_respond(ha_request_t* rq, int ofd, int scode, int ccode, const char* msg); +static int process_auth(ha_request_t* rq); static int config_parse(const char* file, ha_buffer_t* buf); static void on_quit(int signal); @@ -138,990 +137,984 @@ static void on_quit(int signal); int main(int argc, char* argv[]) { - const char* conf = DEFAULT_CONFIG; - const char* pidfile = NULL; - httpauth_thread_t* threads = NULL; - httpauth_loaded_t* h; - char peername[MAXPATHLEN]; - struct sockaddr_any sany; - int daemonize = 1; - ha_buffer_t cbuf; - int r, i, sock; - int ch = 0; - - /* Keep note of the main thread */ - g_mainthread = pthread_self(); - - /* Create the main mutex */ - if(pthread_mutexattr_init(&g_mutexattr) != 0 || - pthread_mutexattr_settype(&g_mutexattr, HA_MUTEX_TYPE) || - pthread_mutex_init(&g_mutex, &g_mutexattr) != 0) - errx(1, "threading problem. can't create mutex"); - - /* Parse the arguments nicely */ + const char* conf = DEFAULT_CONFIG; + const char* pidfile = NULL; + httpauth_thread_t* threads = NULL; + httpauth_loaded_t* h; + char peername[MAXPATHLEN]; + struct sockaddr_any sany; + int daemonize = 1; + ha_buffer_t cbuf; + int r, i, sock; + int ch = 0; + + /* Keep note of the main thread */ + g_mainthread = pthread_self(); + + /* Create the main mutex */ + if(pthread_mutexattr_init(&g_mutexattr) != 0 || + pthread_mutexattr_settype(&g_mutexattr, HA_MUTEX_TYPE) || + pthread_mutex_init(&g_mutex, &g_mutexattr) != 0) + errx(1, "threading problem. can't create mutex"); + + /* Parse the arguments nicely */ while((ch = getopt(argc, argv, "d:f:p:X")) != -1) { switch(ch) { /* Don't daemonize */ - case 'd': - { - char* t; - - daemonize = 0; - g_debuglevel = strtol(optarg, &t, 10); - if(*t || g_debuglevel > 4) - errx(1, "invalid debug log level"); - g_debuglevel += LOG_ERR; - } - break; - - /* The configuration file */ - case 'f': - conf = optarg; - break; - - /* Write out a pid file */ - case 'p': - pidfile = optarg; - break; - - /* Process console input instead */ + case 'd': + { + char* t; + daemonize = 0; + g_debuglevel = strtol(optarg, &t, 10); + if(*t || g_debuglevel > 4) + errx(1, "invalid debug log level"); + g_debuglevel += LOG_ERR; + } + break; + + /* The configuration file */ + case 'f': + conf = optarg; + break; + + /* Write out a pid file */ + case 'p': + pidfile = optarg; + break; + + /* Process console input instead */ case 'X': - g_console = 1; - daemonize = 0; - break; + g_console = 1; + daemonize = 0; + break; - /* Usage information */ - case '?': - default: - return usage(); - break; - } - } + /* Usage information */ + case '?': + default: + return usage(); + break; + } + } - argc -= optind; - argv += optind; + argc -= optind; + argv += optind; - if(argc != 0) - return usage(); + if(argc != 0) + return usage(); - ha_messagex(LOG_DEBUG, "starting up..."); + ha_messagex(NULL, LOG_DEBUG, "starting up..."); - /* From here on out we need to quit in an orderly fashion */ + /* From here on out we need to quit in an orderly fashion */ - /* Run global initialization on all handlers */ - for(i = 0; i < countof(g_handlerlist); i++) - { - if(g_handlerlist[i]->f_init) + /* Run global initialization on all handlers */ + for(i = 0; i < countof(g_handlerlist); i++) { - if((r = (g_handlerlist[i]->f_init)(NULL)) == -1) - goto finally; + if(g_handlerlist[i]->f_init) + { + if((r = (g_handlerlist[i]->f_init)(NULL)) == -1) + goto finally; + } } - } - /* Initialize our configuration buffer */ - ha_bufinit(&cbuf); + /* Initialize our configuration buffer */ + ha_bufinit(&cbuf); - /* Parse the configuration */ - config_parse(conf, &cbuf); + /* Parse the configuration */ + config_parse(conf, &cbuf); - if(!g_console) - { - /* Create the thread buffers */ - threads = (httpauth_thread_t*)calloc(g_maxthreads, sizeof(httpauth_thread_t)); - if(!threads) - errx(1, "out of memory"); + if(!g_console) + { + /* Create the thread buffers */ + threads = (httpauth_thread_t*)calloc(g_maxthreads, sizeof(httpauth_thread_t)); + if(!threads) + errx(1, "out of memory"); - /* Get the socket type */ - if(sock_any_pton(g_socket, &sany, DEFAULT_PORT) == -1) - errx(1, "invalid socket name or ip: %s", g_socket); + /* TODO: Import the new sock_any from clamsmtp */ + /* Get the socket type */ + if(sock_any_pton(g_socket, &sany, DEFAULT_PORT) == -1) + errx(1, "invalid socket name or ip: %s", g_socket); - /* Create the socket */ - sock = socket(SANY_TYPE(sany), SOCK_STREAM, 0); - if(sock < 0) - err(1, "couldn't open socket"); + /* Create the socket */ + sock = socket(SANY_TYPE(sany), SOCK_STREAM, 0); + if(sock < 0) + err(1, "couldn't open socket"); - /* Unlink the socket file if it exists */ - /* TODO: Is this safe? */ - unlink(g_socket); + /* Unlink the socket file if it exists */ + /* TODO: Is this safe? */ + unlink(g_socket); - if(bind(sock, &SANY_ADDR(sany), SANY_LEN(sany)) != 0) - err(1, "couldn't bind to address: %s", g_socket); + if(bind(sock, &SANY_ADDR(sany), SANY_LEN(sany)) != 0) + err(1, "couldn't bind to address: %s", g_socket); - /* Let 5 connections queue up */ - if(listen(sock, 5) != 0) - err(1, "couldn't listen on socket"); + /* Let 5 connections queue up */ + if(listen(sock, 5) != 0) + err(1, "couldn't listen on socket"); - ha_messagex(LOG_DEBUG, "created socket: %s", g_socket); - } + ha_messagex(NULL, LOG_DEBUG, "created socket: %s", g_socket); + } - /* Initialize all the handlers */ - for(h = g_handlers; h; h = h->next) - { - if(h->ctx.handler->f_init) + /* Initialize all the handlers */ + for(h = g_handlers; h; h = h->next) { - if((r = (h->ctx.handler->f_init)(&(h->ctx))) == -1) - goto finally; + if(h->ctx.handler->f_init) + { + if((r = (h->ctx.handler->f_init)(&(h->ctx))) == -1) + goto finally; + } } - } - - - /* This is for debugging the internal processes */ - if(g_console) - { - ha_messagex(LOG_DEBUG, "processing from console"); - r = httpauth_processor(0, 1); - goto finally; - } - /* This is the daemon section of the code */ - else - { - if(daemonize) + /* This is for debugging the internal processes */ + if(g_console) { - /* Fork a daemon nicely here */ - if(daemon(0, 0) == -1) - { - ha_message(LOG_ERR, "couldn't run httpauth as daemon"); - exit(1); - } - - ha_messagex(LOG_DEBUG, "running as a daemon"); - g_daemonized = 1; + ha_messagex(NULL, LOG_DEBUG, "processing from console"); + r = httpauth_processor(0, 1); + goto finally; } - writepid(pidfile); - /* Handle some signals */ - signal(SIGPIPE, SIG_IGN); - signal(SIGHUP, SIG_IGN); - signal(SIGINT, on_quit); - signal(SIGTERM, on_quit); + /* This is the daemon section of the code */ + else + { + if(daemonize) + { + /* Fork a daemon nicely here */ + if(daemon(0, 0) == -1) + { + ha_message(NULL, LOG_ERR, "couldn't run httpauth as daemon"); + exit(1); + } - siginterrupt(SIGINT, 1); - siginterrupt(SIGTERM, 1); + ha_messagex(NULL, LOG_DEBUG, "running as a daemon"); + g_daemonized = 1; + } - /* Open the system log */ - openlog("httpauthd", 0, LOG_AUTHPRIV); + writepid(pidfile); - ha_messagex(LOG_DEBUG, "accepting connections"); + /* Handle some signals */ + signal(SIGPIPE, SIG_IGN); + signal(SIGHUP, SIG_IGN); + signal(SIGINT, on_quit); + signal(SIGTERM, on_quit); - /* Now loop and accept the connections */ - while(!g_quit) - { - int fd; + siginterrupt(SIGINT, 1); + siginterrupt(SIGTERM, 1); - fd = accept(sock, NULL, NULL); - if(fd == -1) - { - switch(errno) - { - case EINTR: - case EAGAIN: - break; + /* Open the system log */ + openlog("httpauthd", 0, LOG_AUTHPRIV); - case ECONNABORTED: - ha_message(LOG_ERR, "couldn't accept a connection"); - break; + ha_messagex(NULL, LOG_DEBUG, "accepting connections"); - default: - ha_message(LOG_ERR, "couldn't accept a connection"); - g_quit = 1; - break; - }; + /* Now loop and accept the connections */ + while(!g_quit) + { + int fd; - if(g_quit) - break; + fd = accept(sock, NULL, NULL); + if(fd == -1) + { + switch(errno) + { + case EINTR: + case EAGAIN: + break; + + case ECONNABORTED: + ha_message(NULL, LOG_ERR, "couldn't accept a connection"); + break; + + default: + ha_message(NULL, LOG_ERR, "couldn't accept a connection"); + g_quit = 1; + break; + }; + + if(g_quit) + break; + + continue; + } - continue; - } + memset(&sany, 0, sizeof(sany)); + SANY_LEN(sany) = sizeof(sany); - memset(&sany, 0, sizeof(sany)); - SANY_LEN(sany) = sizeof(sany); + /* TODO: Move this code into the thread */ + /* Get the peer name */ + if(getpeername(fd, &SANY_ADDR(sany), &SANY_LEN(sany)) == -1 || + sock_any_ntop(&sany, peername, MAXPATHLEN, SANY_OPT_NOPORT) == -1) + ha_messagex(NULL, LOG_WARNING, "%d: couldn't get peer address", fd); + else + ha_messagex(NULL, LOG_INFO, "%d: accepted connection from: %s", fd, peername); - /* Get the peer name */ - if(getpeername(fd, &SANY_ADDR(sany), &SANY_LEN(sany)) == -1 || - sock_any_ntop(&sany, peername, MAXPATHLEN, SANY_OPT_NOPORT) == -1) - ha_messagex(LOG_WARNING, "%d: couldn't get peer address", fd); - else - ha_messagex(LOG_INFO, "%d: accepted connection from: %s", fd, peername); + /* Look for thread and also clean up others */ + for(i = 0; i < g_maxthreads; i++) + { + /* Clean up quit threads */ + if(threads[i].tid != 0) + { + if(threads[i].fd == -1) + { + ha_messagex(NULL, LOG_DEBUG, "cleaning up completed thread"); + pthread_join(threads[i].tid, NULL); + threads[i].tid = 0; + } + } + + /* Start a new thread if neccessary */ + if(fd != -1 && threads[i].tid == 0) + { + threads[i].fd = fd; + r = pthread_create(&(threads[i].tid), NULL, httpauth_thread, + (void*)(threads + i)); + if(r != 0) + { + errno = r; + ha_message(NULL, LOG_ERR, "couldn't create thread"); + g_quit = 1; + break; + } + + ha_messagex(NULL, LOG_DEBUG, "%d: created thread for connection", fd); + fd = -1; + break; + } + } - /* Look for thread and also clean up others */ - for(i = 0; i < g_maxthreads; i++) - { - /* Clean up quit threads */ - if(threads[i].tid != 0) - { - if(threads[i].fd == -1) - { - ha_messagex(LOG_DEBUG, "cleaning up completed thread"); - pthread_join(threads[i].tid, NULL); - threads[i].tid = 0; - } + /* Check to make sure we have a thread */ + if(fd != -1) + { + ha_messagex(NULL, LOG_ERR, "too many connections open (max %d)", g_maxthreads); + httpauth_respond(NULL, fd, HA_SERVER_ERROR, 0, "too many connections"); + shutdown(fd, SHUT_RDWR); + } } - /* Start a new thread if neccessary */ - if(fd != -1 && threads[i].tid == 0) + ha_messagex(NULL, LOG_INFO, "waiting for threads to quit"); + + /* Quit all threads here */ + for(i = 0; i < g_maxthreads; i++) { - threads[i].fd = fd; - r = pthread_create(&(threads[i].tid), NULL, httpauth_thread, - (void*)(threads + i)); - if(r != 0) - { - errno = r; - ha_message(LOG_ERR, "couldn't create thread"); - g_quit = 1; - break; - } + /* Clean up quit threads */ + if(threads[i].tid != 0) + { + if(threads[i].fd != -1) + shutdown(threads[i].fd, SHUT_RDWR); - ha_messagex(LOG_DEBUG, "%d: created thread for connection", fd); - fd = -1; - break; + pthread_join(threads[i].tid, NULL); + } } - } - - /* Check to make sure we have a thread */ - if(fd != -1) - { - ha_messagex(LOG_ERR, "too many connections open (max %d)", g_maxthreads); - httpauth_respond(fd, HA_SERVER_ERROR, 0, "too many connections"); - shutdown(fd, SHUT_RDWR); - } - } - - ha_messagex(LOG_INFO, "waiting for threads to quit"); - /* Quit all threads here */ - for(i = 0; i < g_maxthreads; i++) - { - /* Clean up quit threads */ - if(threads[i].tid != 0) - { - if(threads[i].fd != -1) - shutdown(threads[i].fd, SHUT_RDWR); - - pthread_join(threads[i].tid, NULL); - } + r = 0; } - r = 0; - } - finally: - ha_messagex(LOG_DEBUG, "performing cleanup..."); + ha_messagex(NULL, LOG_DEBUG, "performing cleanup..."); - /* Uninitialize all the handlers */ - for(h = g_handlers; h; h = h->next) - { - if(h->ctx.handler->f_destroy) - (h->ctx.handler->f_destroy)(&(h->ctx)); - } - - /* Run global destroy for all handlers */ - for(i = 0; i < countof(g_handlerlist); i++) - { - if(g_handlerlist[i]->f_destroy) - (g_handlerlist[i]->f_destroy)(NULL); - } + /* Uninitialize all the handlers */ + for(h = g_handlers; h; h = h->next) + { + if(h->ctx.handler->f_destroy) + (h->ctx.handler->f_destroy)(&(h->ctx)); + } - /* Clean up memory and stuff */ - ha_buffree(&cbuf); + /* Run global destroy for all handlers */ + for(i = 0; i < countof(g_handlerlist); i++) + { + if(g_handlerlist[i]->f_destroy) + (g_handlerlist[i]->f_destroy)(NULL); + } - /* Close the mutex */ - pthread_mutex_destroy(&g_mutex); - pthread_mutexattr_destroy(&g_mutexattr); + /* Clean up memory and stuff */ + ha_buffree(&cbuf); - ha_messagex(LOG_DEBUG, "stopped"); + /* Close the mutex */ + pthread_mutex_destroy(&g_mutex); + pthread_mutexattr_destroy(&g_mutexattr); - return r == -1 ? 1 : 0; + ha_messagex(NULL, LOG_DEBUG, "stopped"); + return r == -1 ? 1 : 0; } static void on_quit(int signal) { - g_quit = 1; - fprintf(stderr, "httpauthd: got signal to quit\n"); + g_quit = 1; + fprintf(stderr, "httpauthd: got signal to quit\n"); } static int usage() { - fprintf(stderr, "usage: httpauthd [-d level] [-X] [-p pidfile] [-f conffile]\n"); - return 2; + fprintf(stderr, "usage: httpauthd [-d level] [-X] [-p pidfile] [-f conffile]\n"); + return 2; } static void writepid(const char* pidfile) { - FILE* f = fopen(pidfile, "w"); - if(f == NULL) - { - warnx("couldn't open pid file: %s", pidfile); - } - else - { - fprintf(f, "%d\n", (int)getpid()); - - if(ferror(f)) - warnx("couldn't write to pid file: %s", pidfile); - - fclose(f); - } + FILE* f = fopen(pidfile, "w"); + if(f == NULL) + { + warnx("couldn't open pid file: %s", pidfile); + } + else + { + fprintf(f, "%d\n", (int)getpid()); + + if(ferror(f)) + warnx("couldn't write to pid file: %s", pidfile); + + fclose(f); + } } static void* httpauth_thread(void* arg) { - httpauth_thread_t* thread = (httpauth_thread_t*)arg; - int r; + httpauth_thread_t* thread = (httpauth_thread_t*)arg; + int r; - siginterrupt(SIGINT, 1); - siginterrupt(SIGTERM, 1); - - ASSERT(thread); - ASSERT(thread->fd != -1); + siginterrupt(SIGINT, 1); + siginterrupt(SIGTERM, 1); - /* call the processor */ - r = httpauth_processor(thread->fd, thread->fd); + ASSERT(thread); + ASSERT(thread->fd != -1); - ha_messagex(LOG_INFO, "%d: closed connection", thread->fd); + /* call the processor */ + r = httpauth_processor(thread->fd, thread->fd); - /* mark this as done */ - thread->fd = -1; + /* TODO: Move this to more appropriate place (where we have a req) */ + ha_messagex(NULL, LOG_INFO, "%d: closed connection", thread->fd); - return (void*)r; + /* mark this as done */ + thread->fd = -1; + return (void*)r; } /* ----------------------------------------------------------------------- * Logging */ -void log_request(ha_request_t* req, ha_buffer_t* buf, int fd) +void log_request(ha_request_t* rq) { - const httpauth_command_t* cmd; - const char* t; - const char* t2; - int i; + const httpauth_command_t* cmd; + const char* t; + const char* t2; + int i; - if(g_debuglevel < LOG_DEBUG) - return; + if(g_debuglevel < LOG_DEBUG) + return; - if(req->type == REQTYPE_IGNORE || req->type == -1) - return; + if(rq->req_type == REQTYPE_IGNORE || rq->req_type == -1) + return; - ha_bufcpy(buf, ""); + ha_bufcpy(rq->buf, ""); - for(i = 0; i < HA_MAX_ARGS; i++) - { - if(req->args[i]) + for(i = 0; i < HA_MAX_ARGS; i++) { - ha_bufjoin(buf); - ha_bufmcat(buf, ha_buflen(buf) > 0 ? ", " : "", req->args[i], NULL); + if(rq->req_args[i]) + { + ha_bufjoin(rq->buf); + ha_bufmcat(rq->buf, ha_buflen(rq->buf) > 0 ? ", " : "", rq->req_args[i], NULL); + } } - } - t = ha_bufdata(buf); + t = ha_bufdata(rq->buf); + t2 = NULL; - t2 = NULL; - - /* Figure out which command it is */ - for(cmd = kCommands; cmd->name; cmd++) - { - if(cmd->code == req->type) + /* Figure out which command it is */ + for(cmd = kCommands; cmd->name; cmd++) { - t2 = cmd->name; - break; + if(cmd->code == rq->req_type) + { + t2 = cmd->name; + break; + } } - } - ASSERT(t2); + ASSERT(t2); - ha_messagex(LOG_DEBUG, "%d: received request: " - "[ type: %s / args: %s ]", fd, t2, t); + ha_messagex(rq, LOG_DEBUG, "received request: [ type: %s / args: %s ]", t2, t); - for(i = 0; i < HA_MAX_HEADERS; i++) - { - if(req->headers[i].name) + for(i = 0; i < HA_MAX_HEADERS; i++) { - ASSERT(req->headers[i].data); - ha_messagex(LOG_DEBUG, "%d: received header: [ %s: %s ]", fd, - req->headers[i].name, req->headers[i].data); + if(rq->req_headers[i].name) + { + ASSERT(rq->req_headers[i].data); + ha_messagex(rq, LOG_DEBUG, "received header: [ %s: %s ]", + rq->req_headers[i].name, rq->req_headers[i].data); + } } - } } -void log_response(ha_response_t* resp, int fd) +void log_response(ha_request_t* rq) { - int i; + int i; - if(g_debuglevel < LOG_DEBUG) - return; + if(g_debuglevel < LOG_DEBUG) + return; - ha_messagex(LOG_DEBUG, "%d: sending response: " - "[ code: 200 / ccode: %d / detail: %s ]", fd, - resp->code, resp->detail ? resp->detail : ""); + ha_messagex(rq, LOG_DEBUG, "sending response: [ code: 200 / ccode: %d / detail: %s ]", + rq->resp_code, rq->resp_detail ? rq->resp_detail : ""); - for(i = 0; i < HA_MAX_HEADERS; i++) - { - if(resp->headers[i].name) + for(i = 0; i < HA_MAX_HEADERS; i++) { - ASSERT(resp->headers[i].data); - ha_messagex(LOG_DEBUG, "%d: sending header: [ %s: %s ]", fd, - resp->headers[i].name, resp->headers[i].data); + if(rq->resp_headers[i].name) + { + ASSERT(rq->resp_headers[i].data); + ha_messagex(rq, LOG_DEBUG, "sending header: [ %s: %s ]", + rq->resp_headers[i].name, rq->resp_headers[i].data); + } } - } } -void log_respcode(int code, const char* msg, int fd) +void log_respcode(ha_request_t* rq, int code, const char* msg) { - if(g_debuglevel < LOG_DEBUG) - return; + if(g_debuglevel < LOG_DEBUG) + return; - ha_messagex(LOG_DEBUG, "%d: sending response: " - "[ code: %d / detail: %s ]", fd, code, msg ? msg : ""); + ha_messagex(rq, LOG_DEBUG, "sending response: [ code: %d / detail: %s ]", + code, msg ? msg : ""); } /* ----------------------------------------------------------------------- * Command Parsing and Handling */ -static int httpauth_read(int ifd, ha_request_t* req, - ha_buffer_t* buf) +static int httpauth_read(ha_request_t* rq, int ifd) { - const httpauth_command_t* cmd; - char* t; - int i, r; - int more = 1; + const httpauth_command_t* cmd; + char* t; + int i, r; + int more = 1; - ASSERT(req && buf); - ASSERT(ifd != -1); + ASSERT(r); + ASSERT(ifd != -1); - /* Clean up the request header */ - req->type = -1; - memset(req->args, 0, sizeof(req->args)); - memset(req->headers, 0, sizeof(req->headers)); + /* Clean up the request header */ + rq->req_type = -1; + memset(rq->req_args, 0, sizeof(rq->req_args)); + memset(rq->req_headers, 0, sizeof(rq->req_headers)); - /* This guarantees a bit of memory allocated, and resets buffer */ - ha_bufreset(buf); + /* This guarantees a bit of memory allocated, and resets buffer */ + ha_bufreset(rq->buf); - r = ha_bufreadline(ifd, buf); - if(r == -1) - return -1; + r = ha_bufreadline(ifd, rq->buf); + if(r == -1) + return -1; - /* Check if this is the last line */ - if(r == 0) - more = 0; + /* Check if this is the last line */ + if(r == 0) + more = 0; - /* Check to see if we got anything */ - if(ha_buflen(buf) == 0) - { - req->type = REQTYPE_IGNORE; - return more; - } + /* Check to see if we got anything */ + if(ha_buflen(rq->buf) == 0) + { + rq->req_type = REQTYPE_IGNORE; + return more; + } - /* Find the first space in the line */ - t = ha_bufparseword(buf, " \t"); + /* Find the first space in the line */ + t = ha_bufparseword(rq->buf, " \t"); - if(t) - { - /* Figure out which command it is */ - for(cmd = kCommands; cmd->name; cmd++) + if(t) { - if(strcasecmp(t, cmd->name) == 0) - { - req->type = cmd->code; - break; - } + /* Figure out which command it is */ + for(cmd = kCommands; cmd->name; cmd++) + { + if(strcasecmp(t, cmd->name) == 0) + { + rq->req_type = cmd->code; + break; + } + } } - } - - else - { - req->type = REQTYPE_IGNORE; - return more; - } - /* Check for invalid command */ - if(req->type == -1) - return more; + else + { + rq->req_type = REQTYPE_IGNORE; + return more; + } - /* Now parse the arguments if any */ - for(i = 0; i < cmd->word_args; i++) - req->args[i] = ha_bufparseword(buf, " \t"); + /* Check for invalid command */ + if(rq->req_type == -1) + return more; - /* Does it want the rest as one argument? */ - if(cmd->rest_arg) - req->args[i] = ha_bufparseline(buf, 1); + /* Now parse the arguments if any */ + for(i = 0; i < cmd->word_args; i++) + rq->req_args[i] = ha_bufparseword(rq->buf, " \t"); + /* Does it want the rest as one argument? */ + if(cmd->rest_arg) + rq->req_args[i] = ha_bufparseline(rq->buf, 1); - /* Now skip anything else we have in the buffer */ - ha_bufskip(buf); + /* Now skip anything else we have in the buffer */ + ha_bufskip(rq->buf); - /* If we need headers, then read them now */ - if(cmd->headers) - { - const char** head; /* For iterating through valid headers */ - int valid = 0; /* The last header was valid */ - i = 0; /* The header we're working with */ - for(;;) + /* If we need headers, then read them now */ + if(cmd->headers) { - /* Make sure we have more data */ - if(!more) - break; - - r = ha_bufreadline(ifd, buf); - if(r == -1) - return -1; - - /* Check if this is the last line */ - if(r == 0) - more = 0; - - /* An empty line is the end of the headers */ - if(ha_buflen(buf) == 0) - break; + const char** head; /* For iterating through valid headers */ + int valid = 0; /* The last header was valid */ + i = 0; /* The header we're working with */ - /* Check if the header starts with a space */ - if(isspace(ha_bufchar(buf))) - { - /* Skip all the spaces */ - while(ha_buflen(buf) > 0 && isspace(ha_bufchar(buf))) - ha_bufeat(buf); + for(;;) + { + /* Make sure we have more data */ + if(!more) + break; - /* An empty line is the end of the headers - even if that line has spaces on it */ - if(ha_buflen(buf) == 0) - break; + r = ha_bufreadline(ifd, rq->buf); + if(r == -1) + return -1; - /* A header that has data on it but started - with a space continues the previous header */ - if(valid && i > 0) - { - t = ha_bufparseline(buf, 0); - if(t) - { - char* t2 = (char*)req->headers[i - 1].data + strlen(req->headers[i - 1].data); - - /* Fill the area between the end of the last - valid header and this with spaces */ - memset(t2, ' ', t - t2); - } - } - } - else - { - if(i < HA_MAX_HEADERS) - { - t = ha_bufparseword(buf, ":"); + /* Check if this is the last line */ + if(r == 0) + more = 0; - if(t) - { - for(head = cmd->headers; ; head++) - { - if(!(*head)) - { - t = NULL; + /* An empty line is the end of the headers */ + if(ha_buflen(rq->buf) == 0) break; - } - if(strcasecmp(t, *head) == 0) - break; + /* Check if the header starts with a space */ + if(isspace(ha_bufchar(rq->buf))) + { + /* Skip all the spaces */ + while(ha_buflen(rq->buf) > 0 && isspace(ha_bufchar(rq->buf))) + ha_bufeat(rq->buf); + + /* An empty line is the end of the headers + even if that line has spaces on it */ + if(ha_buflen(rq->buf) == 0) + break; + + /* A header that has data on it but started + with a space continues the previous header */ + if(valid && i > 0) + { + t = ha_bufparseline(rq->buf, 0); + if(t) + { + char* t2 = (char*)rq->req_headers[i - 1].data + strlen(rq->req_headers[i - 1].data); + + /* Fill the area between the end of the last + valid header and this with spaces */ + memset(t2, ' ', t - t2); + } + } + } + else + { + if(i < HA_MAX_HEADERS) + { + t = ha_bufparseword(rq->buf, ":"); + + if(t) + { + for(head = cmd->headers; ; head++) + { + if(!(*head)) + { + t = NULL; + break; + } + + if(strcasecmp(t, *head) == 0) + break; + } + } + + if(t) + { + rq->req_headers[i].name = t; + rq->req_headers[i].data = ha_bufparseline(rq->buf, 1); + i++; + } + + valid = (t != NULL) ? 1 : 0; + } } - } - - if(t) - { - req->headers[i].name = t; - req->headers[i].data = ha_bufparseline(buf, 1); - i++; - } - valid = (t != NULL) ? 1 : 0; + ha_bufskip(rq->buf); } - } - - ha_bufskip(buf); } - } - return more; + return more; } -static int write_data(int ofd, const char* data) +static int write_data(ha_request_t* rq, int ofd, const char* data) { - int r; + int r; - ASSERT(data); - ASSERT(ofd != -1); + ASSERT(data); + ASSERT(ofd != -1); - while(*data != 0) - { - r = write(ofd, data, strlen(data)); + while(*data != 0) + { + r = write(ofd, data, strlen(data)); - if(r > 0) - data += r; + if(r > 0) + data += r; - else if(r == -1) - { - if(errno == EAGAIN) - continue; + else if(r == -1) + { + if(errno == EAGAIN) + continue; - /* The other end closed. no message */ - if(errno != EPIPE) - ha_message(LOG_ERR, "couldn't write data"); + /* The other end closed. no message */ + if(errno != EPIPE) + ha_message(rq, LOG_ERR, "couldn't write data"); - return HA_CRITERROR; + return HA_CRITERROR; + } } - } - return 0; + return 0; } -static int httpauth_respond(int ofd, int scode, int ccode, const char* msg) +static int httpauth_respond(ha_request_t* rq, int ofd, int scode, int ccode, const char* msg) { - char num[16]; + char num[16]; - ASSERT(ofd != -1); - ASSERT(scode > 99 && scode < 1000); - ASSERT(ccode == 0 || (ccode > 99 && ccode < 1000)); + ASSERT(ofd != -1); + ASSERT(scode > 99 && scode < 1000); + ASSERT(ccode == 0 || (ccode > 99 && ccode < 1000)); - /* Can only have a client code when server code is 200 */ - ASSERT(ccode == 0 || scode == HA_SERVER_OK); + /* Can only have a client code when server code is 200 */ + ASSERT(ccode == 0 || scode == HA_SERVER_OK); - sprintf(num, "%d ", scode); + sprintf(num, "%d ", scode); - if(write_data(ofd, num) < 0) - return HA_CRITERROR; + if(write_data(rq, ofd, num) < 0) + return HA_CRITERROR; - if(ccode != 0) - { - sprintf(num, "%d ", ccode); + if(ccode != 0) + { + sprintf(num, "%d ", ccode); - if(write_data(ofd, num) < 0) - return HA_CRITERROR; - } + if(write_data(rq, ofd, num) < 0) + return HA_CRITERROR; + } - if(!msg) - { - switch(scode) + if(!msg) { - case HA_SERVER_ACCEPTED: - msg = "Accepted"; - break; - case HA_SERVER_ERROR: - msg = "Internal Error "; - break; - case HA_SERVER_BADREQ: - msg = "Bad Request "; - break; - case HA_SERVER_DECLINE: - msg = "Unauthorized "; - break; - default: - msg = NULL; - break; - }; - } + switch(scode) + { + case HA_SERVER_ACCEPTED: + msg = "Accepted"; + break; + case HA_SERVER_ERROR: + msg = "Internal Error "; + break; + case HA_SERVER_BADREQ: + msg = "Bad Request "; + break; + case HA_SERVER_DECLINE: + msg = "Unauthorized "; + break; + default: + msg = NULL; + break; + }; + } - if(msg && write_data(ofd, msg) < 0) - return HA_CRITERROR; + if(msg && write_data(rq, ofd, msg) < 0) + return HA_CRITERROR; - /* When the client code is 0, then caller should log */ - if(ccode == 0) - log_respcode(scode, msg, ofd); + /* When the client code is 0, then caller should log */ + if(ccode == 0) + log_respcode(rq, scode, msg); - return write_data(ofd, "\n"); + return write_data(rq, ofd, "\n"); } const char kHeaderDelimiter[] = ": "; -static int httpauth_write(int ofd, ha_response_t* resp) +static int httpauth_write(ha_request_t* rq, int ofd) { - int i; - int wrote = 0; + int i; + int wrote = 0; - ASSERT(ofd != -1); - ASSERT(resp); + ASSERT(ofd != -1); + ASSERT(rq); - if(httpauth_respond(ofd, HA_SERVER_OK, resp->code, resp->detail) < 0) - return HA_CRITERROR; + if(httpauth_respond(rq, ofd, HA_SERVER_OK, rq->resp_code, rq->resp_detail) < 0) + return HA_CRITERROR; - for(i = 0; i < HA_MAX_HEADERS; i++) - { - if(resp->headers[i].name) + for(i = 0; i < HA_MAX_HEADERS; i++) { - if(write_data(ofd, resp->headers[i].name) == -1 || - write_data(ofd, kHeaderDelimiter) == -1 || - write_data(ofd, resp->headers[i].data) == -1 || - write_data(ofd, "\n") == -1) - return -1; + if(rq->resp_headers[i].name) + { + if(write_data(rq, ofd, rq->resp_headers[i].name) == -1 || + write_data(rq, ofd, kHeaderDelimiter) == -1 || + write_data(rq, ofd, rq->resp_headers[i].data) == -1 || + write_data(rq, ofd, "\n") == -1) + return -1; - wrote = 1; + wrote = 1; + } } - } - if(write_data(ofd, "\n") == -1) - return -1; + if(write_data(rq, ofd, "\n") == -1) + return -1; - log_response(resp, ofd); + log_response(rq); - return 0; + return 0; } -static int httpauth_error(int ofd, int r) +static int httpauth_error(ha_request_t* rq, int ofd, int r) { - int scode = 0; - const char* msg = NULL; + int scode = 0; + const char* msg = NULL; - ASSERT(r < 0); + ASSERT(r < 0); - switch(r) - { - case HA_BADREQ: - scode = HA_SERVER_BADREQ; - break; + switch(r) + { + case HA_BADREQ: + scode = HA_SERVER_BADREQ; + break; - case HA_CRITERROR: - msg = "Critical Error"; - /* fall through */ + case HA_CRITERROR: + msg = "Critical Error"; + /* fall through */ - case HA_FAILED: - scode = HA_SERVER_ERROR; - break; + case HA_FAILED: + scode = HA_SERVER_ERROR; + break; - default: - ASSERT(0 && "invalid error code"); - break; - } + default: + ASSERT(0 && "invalid error code"); + break; + }; - return httpauth_respond(ofd, scode, 0, msg); + return httpauth_respond(rq, ofd, scode, 0, msg); } -static int httpauth_ready(int ofd, ha_buffer_t* buf) +static int httpauth_ready(ha_request_t* rq, int ofd) { - const char* t; - httpauth_loaded_t* h; + const char* t; + httpauth_loaded_t* h; - ASSERT(ofd != -1); - ASSERT(buf); + ASSERT(ofd != -1); + ASSERT(rq); - /* We send a ready banner to our client */ + /* We send a ready banner to our client */ - if(ha_buferr(buf)) - return httpauth_error(ofd, HA_CRITERROR); - - else - return httpauth_respond(ofd, HA_SERVER_READY, 0, "HTTPAUTH/1.0"); + if(ha_buferr(rq->buf)) + return httpauth_error(rq, ofd, HA_CRITERROR); + else + return httpauth_respond(rq, ofd, HA_SERVER_READY, 0, "HTTPAUTH/1.0"); } -static int httpauth_auth(int ofd, ha_request_t* req, ha_response_t* resp) +static int httpauth_auth(ha_request_t* rq, int ofd) { - int r; - - ASSERT(req && resp); - - if(!req->context) - { - ha_messagex(LOG_ERR, "no auth handler set"); - return httpauth_respond(ofd, HA_SERVER_BADREQ, 0, "No Auth Handler Set"); - } - - /* Clear out our response */ - resp->code = -1; - resp->detail = NULL; - memset(resp->headers, 0, sizeof(resp->headers)); - ASSERT(resp->buf != NULL); - - /* Check our connection argument */ - if(!req->args[AUTH_ARG_CONN] || !(req->args[AUTH_ARG_CONN][0])) - { - ha_messagex(LOG_ERR, "missing connection ID in request"); - return httpauth_respond(ofd, HA_SERVER_BADREQ, 0, "Missing Connection ID"); - } - - /* Check our uri argument */ - if(!req->args[AUTH_ARG_URI] || !(req->args[AUTH_ARG_URI][0])) - { - ha_messagex(LOG_ERR, "missing URI in request"); - return httpauth_respond(ofd, HA_SERVER_BADREQ, 0, "Missing URI"); - } - - /* Check our connection arguments */ - if(!req->args[AUTH_ARG_METHOD] || !(req->args[AUTH_ARG_METHOD][0])) - { - ha_messagex(LOG_ERR, "missing HTTP method in request"); - return httpauth_respond(ofd, HA_SERVER_BADREQ, 0, "Missing HTTP Method"); - } - - ASSERT(req->context->handler && req->context->handler->f_process); - r = (req->context->handler->f_process)(req, resp); - if(r < 0) - return r; - - if(httpauth_write(ofd, resp) < 0) - return HA_CRITERROR; - - return HA_OK; + int r; + + ASSERT(rq); + + if(!rq->context) + { + ha_messagex(rq, LOG_ERR, "no auth handler set"); + return httpauth_respond(rq, ofd, HA_SERVER_BADREQ, 0, "No Auth Handler Set"); + } + + /* Clear out our response */ + rq->resp_code = -1; + rq->resp_detail = NULL; + memset(rq->resp_headers, 0, sizeof(rq->resp_headers)); + + /* Check our connection argument */ + if(!rq->req_args[AUTH_ARG_CONN] || !(rq->req_args[AUTH_ARG_CONN][0])) + { + ha_messagex(rq, LOG_ERR, "missing connection ID in request"); + return httpauth_respond(rq, ofd, HA_SERVER_BADREQ, 0, "Missing Connection ID"); + } + + /* Check our uri argument */ + if(!rq->req_args[AUTH_ARG_URI] || !(rq->req_args[AUTH_ARG_URI][0])) + { + ha_messagex(rq, LOG_ERR, "missing URI in request"); + return httpauth_respond(rq, ofd, HA_SERVER_BADREQ, 0, "Missing URI"); + } + + /* Check our connection arguments */ + if(!rq->req_args[AUTH_ARG_METHOD] || !(rq->req_args[AUTH_ARG_METHOD][0])) + { + ha_messagex(rq, LOG_ERR, "missing HTTP method in request"); + return httpauth_respond(rq, ofd, HA_SERVER_BADREQ, 0, "Missing HTTP Method"); + } + + ASSERT(rq->context->handler && rq->context->handler->f_process); + r = (rq->context->handler->f_process)(rq); + if(r < 0) + return r; + + if(httpauth_write(rq, ofd) < 0) + return HA_CRITERROR; + + return HA_OK; } -static int httpauth_set(int ofd, ha_request_t* req) +static int httpauth_set(ha_request_t* rq, int ofd) { - httpauth_loaded_t* h; - const char* name = req->args[0]; - const char* value = req->args[1]; - - ASSERT(req); - - /* Check our name argument */ - if(!name || !*name) - { - ha_messagex(LOG_ERR, "missing name in SET request"); - return HA_BADREQ; - } - - if(strcasecmp(name, "Domain") == 0) - { - req->digest_domain = value ? value : ""; - } - - else if(strcasecmp(name, "Handler") == 0) - { - if(!value || !*value) + httpauth_loaded_t* h; + const char* name = rq->req_args[0]; + const char* value = rq->req_args[1]; + + /* Check our name argument */ + if(!name || !*name) { - ha_messagex(LOG_ERR, "no auth handler specified in SET request."); - return HA_BADREQ; + ha_messagex(rq, LOG_ERR, "missing name in SET request"); + return HA_BADREQ; } - /* Find a handler for this type */ - for(h = g_handlers; h; h = h->next) + if(strcasecmp(name, "Domain") == 0) { - if(strcasecmp(h->ctx.name, value) == 0) - { - req->context = &(h->ctx); - value = NULL; - break; - } + rq->digest_domain = value ? value : ""; } - if(value != NULL) + else if(strcasecmp(name, "Handler") == 0) { - ha_messagex(LOG_ERR, "unknown authentication type: %s", req->args[0]); - return httpauth_respond(ofd, HA_SERVER_BADREQ, 0, "Unknown Auth Handler"); + if(!value || !*value) + { + ha_messagex(rq, LOG_ERR, "no auth handler specified in SET request."); + return HA_BADREQ; + } + + /* Find a handler for this type */ + for(h = g_handlers; h; h = h->next) + { + if(strcasecmp(h->ctx.name, value) == 0) + { + rq->context = &(h->ctx); + value = NULL; + break; + } + } + + if(value != NULL) + { + ha_messagex(rq, LOG_ERR, "unknown authentication type: %s", rq->req_args[0]); + return httpauth_respond(rq, ofd, HA_SERVER_BADREQ, 0, "Unknown Auth Handler"); + } } - } - else - { - ha_messagex(LOG_ERR, "bad option in SET request"); - return HA_BADREQ; - } + else + { + ha_messagex(rq, LOG_ERR, "bad option in SET request"); + return HA_BADREQ; + } - return httpauth_respond(ofd, HA_SERVER_ACCEPTED, 0, NULL); + return httpauth_respond(rq, ofd, HA_SERVER_ACCEPTED, 0, NULL); } static int httpauth_processor(int ifd, int ofd) { - ha_buffer_t buf; - ha_request_t req; - ha_response_t resp; - int result = -1; - int r; + ha_buffer_t buf; + ha_request_t rq; + int result = -1; + int r; - ASSERT(ifd != -1); - ASSERT(ofd != -1); + ASSERT(ifd != -1); + ASSERT(ofd != -1); - /* Initialize the memory buffers */ - ha_bufinit(&buf); + /* Initialize the memory buffers */ + ha_bufinit(&buf); - memset(&req, 0, sizeof(req)); - memset(&resp, 0, sizeof(resp)); + memset(&rq, 0, sizeof(rq)); - /* Set up some context stuff */ - req.digest_domain = ""; - req.buf = &buf; - resp.buf = &buf; + /* Set up some context stuff */ + rq.digest_domain = ""; + rq.buf = &buf; - if(httpauth_ready(ofd, &buf) == -1) - { - result = 1; - goto finally; - } + if(httpauth_ready(&rq, ofd) == -1) + { + result = 1; + goto finally; + } - /* Now loop and handle the commands */ - while(result == -1) - { - ha_bufreset(&buf); + /* Now loop and handle the commands */ + while(result == -1) + { + ha_bufreset(&buf); - r = httpauth_read(ifd, &req, &buf); + r = httpauth_read(&rq, ifd); - if(ha_buferr(&buf)) - r = HA_CRITERROR; + if(ha_buferr(&buf)) + r = HA_CRITERROR; - if(r < 0) - { - httpauth_error(ofd, r); - result = 1; - break; - } + if(r < 0) + { + httpauth_error(&rq, ofd, r); + result = 1; + break; + } - log_request(&req, &buf, ifd); + log_request(&rq); - if(r == 0) - result = 0; + if(r == 0) + result = 0; - switch(req.type) - { - case REQTYPE_AUTH: - r = httpauth_auth(ofd, &req, &resp); - break; + switch(rq.req_type) + { + case REQTYPE_AUTH: + r = httpauth_auth(&rq, ofd); + break; - case REQTYPE_SET: - r = httpauth_set(ofd, &req); - break; + case REQTYPE_SET: + r = httpauth_set(&rq, ofd); + break; - case REQTYPE_QUIT: - r = HA_OK; - result = 0; - break; + case REQTYPE_QUIT: + r = HA_OK; + result = 0; + break; - case REQTYPE_IGNORE: - r = HA_FALSE; - break; + case REQTYPE_IGNORE: + r = HA_FALSE; + break; - default: - ha_messagex(LOG_WARNING, "%d: received unknown command from client", ifd); - r = httpauth_respond(ofd, HA_SERVER_BADREQ, 0, "Unknown command"); - break; - }; + default: + ha_messagex(&rq, LOG_WARNING, "received unknown command from client"); + r = httpauth_respond(&rq, ofd, HA_SERVER_BADREQ, 0, "Unknown command"); + break; + }; - if(ha_buferr(&buf)) - r = HA_CRITERROR; + if(ha_buferr(&buf)) + r = HA_CRITERROR; - if(r < 0) - { - httpauth_error(ofd, r); + if(r < 0) + { + httpauth_error(&rq, ofd, r); - if(r == HA_CRITERROR) - result = 1; + if(r == HA_CRITERROR) + result = 1; + } } - } - if(ifd == ofd) - shutdown(ofd, SHUT_RDWR); - else - close(ofd); + if(ifd == ofd) + { + shutdown(ofd, SHUT_RDWR); + close(ofd); + } + else + { + close(ifd); + close(ofd); + } finally: - ha_buffree(&buf); - - return result; + ha_buffree(&buf); + return result; } /* ----------------------------------------------------------------------- @@ -1129,335 +1122,335 @@ finally: */ static ha_context_t* config_addhandler(ha_buffer_t* buf, const char* alias, - ha_handler_t* handler, const ha_context_t* defaults) + ha_handler_t* handler, const ha_context_t* defaults) { - httpauth_loaded_t* loaded; - int len; + httpauth_loaded_t* loaded; + int len; - ASSERT(buf && alias && handler && defaults); + ASSERT(buf && alias && handler && defaults); - len = sizeof(httpauth_loaded_t) + handler->context_size; + len = sizeof(httpauth_loaded_t) + handler->context_size; - loaded = (httpauth_loaded_t*)ha_bufmalloc(buf, len); - if(!loaded) - errx(1, "out of memory"); + loaded = (httpauth_loaded_t*)ha_bufmalloc(buf, len); + if(!loaded) + errx(1, "out of memory"); - memset(loaded, 0, len); + memset(loaded, 0, len); - /* Setup the options from the defaults */ - memcpy(&(loaded->ctx), defaults, sizeof(ha_context_t)); + /* Setup the options from the defaults */ + memcpy(&(loaded->ctx), defaults, sizeof(ha_context_t)); - if(handler->context_size) - { - void* mem = ((unsigned char*)(loaded)) + sizeof(httpauth_loaded_t); - - /* Initialize the defaults properly */ - if(handler->context_default) - memcpy(mem, handler->context_default, handler->context_size); + if(handler->context_size) + { + void* mem = ((unsigned char*)(loaded)) + sizeof(httpauth_loaded_t); - loaded->ctx.ctx_data = mem; - } + /* Initialize the defaults properly */ + if(handler->context_default) + memcpy(mem, handler->context_default, handler->context_size); - else - { - loaded->ctx.ctx_data = NULL; - } + loaded->ctx.ctx_data = mem; + } - loaded->ctx.name = (char*)alias; - loaded->ctx.handler = handler; + else + { + loaded->ctx.ctx_data = NULL; + } - if(!g_handlers) - { - g_handlers = loaded; - } - else - { - httpauth_loaded_t* l = g_handlers; + loaded->ctx.name = (char*)alias; + loaded->ctx.handler = handler; - for(;;) + if(!g_handlers) + { + g_handlers = loaded; + } + else { - if(strcasecmp(alias, l->ctx.name) == 0) - errx(1, "duplicate handler section for '%s'", alias); + httpauth_loaded_t* l = g_handlers; - if(!(l->next)) - break; + for(;;) + { + if(strcasecmp(alias, l->ctx.name) == 0) + errx(1, "duplicate handler section for '%s'", alias); - l = l->next; - } + if(!(l->next)) + break; - l->next = loaded; - } + l = l->next; + } - ha_messagex(LOG_DEBUG, "configuration: handler: %s (%s)", alias, handler->type); - return &(loaded->ctx); + l->next = loaded; + } + + ha_messagex(NULL, LOG_DEBUG, "configuration: handler: %s (%s)", alias, handler->type); + return &(loaded->ctx); } #define VALID_ALIAS_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWYZ_-." static int config_parse(const char* file, ha_buffer_t* buf) { - ha_context_t defaults; - ha_context_t* ctx = NULL; - int line = 0; - int fd; - char* t; - char* name; - char* value; - int more = 1; - int recog; - int r, i; - - ASSERT(file && buf); - - /* Open the configuration file */ - fd = open(file, O_RDONLY); - if(fd == -1) - err(1, "couldn't open configuration file: %s", file); - - /* These are the default options for the contexts */ - memset(&defaults, 0, sizeof(defaults)); - defaults.allowed_types = 0xFFFFFFFF; /* All types by default */ - defaults.cache_timeout = DEFAULT_TIMEOUT; /* Timeout for cache */ - defaults.cache_max = DEFAULT_CACHEMAX; - defaults.realm = ""; - - /* Read each line and process */ - while(more) - { - ha_bufskip(buf); - - if((more = ha_bufreadline(fd, buf)) == -1) - return -1; - - line++; - - /* Eat all white space at beginning of line */ - while(ha_buflen(buf) && isspace(ha_bufchar(buf))) - ha_bufeat(buf); - - /* Skip blank lines */ - if(ha_buflen(buf) == 0) - continue; - - /* Skip comment lines */ - if(ha_bufchar(buf) == '#') - continue; - - /* Check for a handler */ - if(ha_bufchar(buf) == '[') + ha_context_t defaults; + ha_context_t* ctx = NULL; + int line = 0; + int fd; + char* t; + char* name; + char* value; + int more = 1; + int recog; + int r, i; + + ASSERT(file && buf); + + /* Open the configuration file */ + fd = open(file, O_RDONLY); + if(fd == -1) + err(1, "couldn't open configuration file: %s", file); + + /* These are the default options for the contexts */ + memset(&defaults, 0, sizeof(defaults)); + defaults.allowed_types = 0xFFFFFFFF; /* All types by default */ + defaults.cache_timeout = DEFAULT_TIMEOUT; /* Timeout for cache */ + defaults.cache_max = DEFAULT_CACHEMAX; + defaults.realm = ""; + + /* Read each line and process */ + while(more) { - ha_handler_t* handler = NULL; - const char* x; + ha_bufskip(buf); - ha_bufeat(buf); - name = ha_bufparseline(buf, 1); + if((more = ha_bufreadline(fd, buf)) == -1) + return -1; - if(!name || name[strlen(name) - 1] != ']') - errx(1, "handler section invalid (line %d)", line); + line++; + /* Eat all white space at beginning of line */ + while(ha_buflen(buf) && isspace(ha_bufchar(buf))) + ha_bufeat(buf); - /* remove the bracket */ - name[strlen(name) - 1] = 0; + /* Skip blank lines */ + if(ha_buflen(buf) == 0) + continue; - /* - * Take out any colon found, past which would - * be an aliased name - */ - t = strchr(name, ':'); - if(t != NULL) - { - *t = 0; - t++; + /* Skip comment lines */ + if(ha_bufchar(buf) == '#') + continue; - /* Rid of whitespace on ends */ - t = trim_space(t); + /* Check for a handler */ + if(ha_bufchar(buf) == '[') + { + ha_handler_t* handler = NULL; + const char* x; - /* Validate the alias name */ - if(!*t || strspn(t, VALID_ALIAS_CHARS) != strlen(t)) - errx(1, "invalid name for handler: %s", t); - } + ha_bufeat(buf); + name = ha_bufparseline(buf, 1); - /* Rid of whitespace */ - name = trim_space(name); + if(!name || name[strlen(name) - 1] != ']') + errx(1, "handler section invalid (line %d)", line); - /* Look for a handler with this type */ - for(i = 0; i < countof(g_handlerlist); i++) - { - if(g_handlerlist[i] && g_handlerlist[i]->type && - strcasecmp(name, g_handlerlist[i]->type) == 0) - { - handler = g_handlerlist[i]; - break; - } - } - if(handler == NULL) - errx(1, "unknown handler type '%s' (line %d)", name, line); + /* remove the bracket */ + name[strlen(name) - 1] = 0; - /* If we had a last handler then add it to handlers */ - ctx = config_addhandler(buf, t ? t : name, handler, &defaults); + /* + * Take out any colon found, past which would + * be an aliased name + */ + t = strchr(name, ':'); + if(t != NULL) + { + *t = 0; + t++; - /* Rest doesn't apply to handler headers */ - continue; - } + /* Rid of whitespace on ends */ + t = trim_space(t); + /* Validate the alias name */ + if(!*t || strspn(t, VALID_ALIAS_CHARS) != strlen(t)) + errx(1, "invalid name for handler: %s", t); + } - /* Parse out the name */ - name = ha_bufparseword(buf, ":"); - if(!name || !name[0]) - errx(1, "configuration file invalid (line %d)", line); + /* Rid of whitespace */ + name = trim_space(name); - strlwr(name); + /* Look for a handler with this type */ + for(i = 0; i < countof(g_handlerlist); i++) + { + if(g_handlerlist[i] && g_handlerlist[i]->type && + strcasecmp(name, g_handlerlist[i]->type) == 0) + { + handler = g_handlerlist[i]; + break; + } + } - /* And get the rest of the line */ - value = ha_bufparseline(buf, 1); - if(value == NULL) - errx(1, "configuration missing value at (line %d)", line); + if(handler == NULL) + errx(1, "unknown handler type '%s' (line %d)", name, line); + /* If we had a last handler then add it to handlers */ + ctx = config_addhandler(buf, t ? t : name, handler, &defaults); - recog = 0; + /* Rest doesn't apply to handler headers */ + continue; + } - /* Is this the global section? */ - if(!ctx) - { - /* Look and see if that's a name we want */ - if(strcmp("socket", name) == 0) - { - g_socket = value; - recog = 1; - } - - else if(strcmp("maxthreads", name) == 0) - { - if(ha_confint(name, value, 1, 256, &g_maxthreads) == -1) - exit(1); - recog = 1; - } - } - /* Otherwise we're in a handler */ - else - { - if(ctx->handler->f_config) - { - r = (ctx->handler->f_config)(ctx, name, value); - if(r < 0) - return r; + /* Parse out the name */ + name = ha_bufparseword(buf, ":"); + if(!name || !name[0]) + errx(1, "configuration file invalid (line %d)", line); - if(!recog && r == HA_OK) - recog = 1; - } - } + strlwr(name); - /* Options that are legal in both global and internal sections */ - if(!recog) - { - ha_context_t* opts = ctx ? ctx : &defaults; - ASSERT(opts); - - if(strcmp(name, "cachetimeout") == 0) - { - int v; - if(ha_confint(name, value, 0, 86400, &v) < 0) - exit(1); /* Message already printed */ - - opts->cache_timeout = v; - recog = 1; - } - - else if(strcmp(name, "cachemax") == 0) - { - int v; - if(ha_confint(name, value, 0, 0x7FFFFFFF, &v) < 0) - exit(1); /* Message already printed */ - - opts->cache_max = v; - recog = 1; - } - - else if(strcmp(name, "authtypes") == 0) - { - int types = 0; - char* t; - - strlwr(value); - - /* Split the line into tokens at the spaces */ - while(*value) - { - value = trim_space(value); - t = value; + /* And get the rest of the line */ + value = ha_bufparseline(buf, 1); + if(value == NULL) + errx(1, "configuration missing value at (line %d)", line); - while(*t && !isspace(*t)) - t++; - if(strncmp(value, "basic", 5) == 0) - types |= HA_TYPE_BASIC; + recog = 0; - else if(strncmp(value, "digest", 6) == 0) - types |= HA_TYPE_DIGEST; + /* Is this the global section? */ + if(!ctx) + { + /* Look and see if that's a name we want */ + if(strcmp("socket", name) == 0) + { + g_socket = value; + recog = 1; + } - else if(strncmp(value, "ntlm", 4) == 0) - types |= HA_TYPE_NTLM; + else if(strcmp("maxthreads", name) == 0) + { + if(ha_confint(name, value, 1, 256, &g_maxthreads) == -1) + exit(1); + recog = 1; + } + } - else - errx(1, "invalid type for '%s': %s (line %d)", name, value, line); + /* Otherwise we're in a handler */ + else + { + if(ctx->handler->f_config) + { + r = (ctx->handler->f_config)(ctx, name, value); + if(r < 0) + return r; - value = t; + if(!recog && r == HA_OK) + recog = 1; + } } - if(types == 0) - errx(1, "no authentication types for '%s' (line %d)", name, line); + /* Options that are legal in both global and internal sections */ + if(!recog) + { + ha_context_t* opts = ctx ? ctx : &defaults; + ASSERT(opts); - opts->allowed_types = types; - recog = 1; - } + if(strcmp(name, "cachetimeout") == 0) + { + int v; + if(ha_confint(name, value, 0, 86400, &v) < 0) + exit(1); /* Message already printed */ - else if(strcmp(name, "realm") == 0) - { - opts->realm = value; - recog = 1; - } + opts->cache_timeout = v; + recog = 1; + } - else if(strcmp(name, "digestignoreuri") == 0) - { - int v; - if(ha_confbool(name, value, &v) < 0) - exit(1); /* Message already printed */ + else if(strcmp(name, "cachemax") == 0) + { + int v; + if(ha_confint(name, value, 0, 0x7FFFFFFF, &v) < 0) + exit(1); /* Message already printed */ - opts->digest_ignoreuri = v; - recog = 1; - } + opts->cache_max = v; + recog = 1; + } - else if(strcmp(name, "digestignorenc") == 0) - { - int v; - if(ha_confbool(name, value, &v) < 0) - exit(1); /* Message already printed */ + else if(strcmp(name, "authtypes") == 0) + { + int types = 0; + char* t; - opts->digest_ignorenc = v; - recog = 1; - } + strlwr(value); + + /* Split the line into tokens at the spaces */ + while(*value) + { + value = trim_space(value); + t = value; + + while(*t && !isspace(*t)) + t++; + + if(strncmp(value, "basic", 5) == 0) + types |= HA_TYPE_BASIC; + + else if(strncmp(value, "digest", 6) == 0) + types |= HA_TYPE_DIGEST; + + else if(strncmp(value, "ntlm", 4) == 0) + types |= HA_TYPE_NTLM; + + else + errx(1, "invalid type for '%s': %s (line %d)", name, value, line); + + value = t; + } + + if(types == 0) + errx(1, "no authentication types for '%s' (line %d)", name, line); + + opts->allowed_types = types; + recog = 1; + } + + else if(strcmp(name, "realm") == 0) + { + opts->realm = value; + recog = 1; + } + + else if(strcmp(name, "digestignoreuri") == 0) + { + int v; + if(ha_confbool(name, value, &v) < 0) + exit(1); /* Message already printed */ + + opts->digest_ignoreuri = v; + recog = 1; + } + + else if(strcmp(name, "digestignorenc") == 0) + { + int v; + if(ha_confbool(name, value, &v) < 0) + exit(1); /* Message already printed */ + + opts->digest_ignorenc = v; + recog = 1; + } #ifdef _DEBUG - else if(strcmp(name, "digestdebugnonce") == 0) - { - opts->digest_debugnonce = value; - recog = 1; - } + else if(strcmp(name, "digestdebugnonce") == 0) + { + opts->digest_debugnonce = value; + recog = 1; + } #endif - } + } - if(!recog) - errx(1, "unrecognized configuration setting '%s' (line %d)", name, line); - else - ha_messagex(LOG_DEBUG, "configuration: setting: [ %s: %s ]", name, value); - } + if(!recog) + errx(1, "unrecognized configuration setting '%s' (line %d)", name, line); + else + ha_messagex(NULL, LOG_DEBUG, "configuration: setting: [ %s: %s ]", name, value); + } - if(!g_handlers) - ha_messagex(LOG_WARNING, "configuration: no handlers found in configuration file"); + if(!g_handlers) + ha_messagex(NULL, LOG_WARNING, "configuration: no handlers found in configuration file"); - return 0; + return 0; } diff --git a/daemon/httpauthd.h b/daemon/httpauthd.h index 84a30cd..39bf94e 100644 --- a/daemon/httpauthd.h +++ b/daemon/httpauthd.h @@ -2,6 +2,8 @@ #ifndef __HTTPAUTHD_H__ #define __HTTPAUTHD_H__ +#include <syslog.h> + /* ----------------------------------------------------------------------- * Memory Buffers */ @@ -11,10 +13,10 @@ struct ha_buffer_internal; /* A buffer which owns memory */ typedef struct ha_buffer { - struct ha_buffer_internal* _ft; - struct ha_buffer_internal* _dt; - char* _pp; - char* _rp; + struct ha_buffer_internal* _ft; + struct ha_buffer_internal* _dt; + char* _pp; + char* _rp; } ha_buffer_t; @@ -28,16 +30,16 @@ void ha_buffree(ha_buffer_t* buf); void ha_bufreset(ha_buffer_t* buf); #define ha_buflen(buf) \ - ((buf)->_rp - (buf)->_pp) + ((buf)->_rp - (buf)->_pp) #define ha_bufchar(buf) \ - ((!ha_buferr(buf) && ha_buflen(buf) > 0) ? *((buf)->_pp) : '\0' ) + ((!ha_buferr(buf) && ha_buflen(buf) > 0) ? *((buf)->_pp) : '\0' ) #define ha_bufdata(buf) \ - ((buf)->_pp) + ((buf)->_pp) #define ha_buferr(buf) \ - ((buf)->_dt == NULL) + ((buf)->_dt == NULL) /* Buffer input functions ------------------------------------------------ */ @@ -51,10 +53,10 @@ char* ha_bufparseline(ha_buffer_t* buf, int trim); char* ha_bufparseword(ha_buffer_t* buf, const char* delims); #define ha_bufskip(buf) \ - ((buf)->_pp = (buf)->_rp) + ((buf)->_pp = (buf)->_rp) #define ha_bufeat(buf) \ - ((!ha_buferr(buf) && ha_buflen(buf) > 0) ? ++((buf)->_pp) : (buf)->_pp) + ((!ha_buferr(buf) && ha_buflen(buf) > 0) ? ++((buf)->_pp) : (buf)->_pp) /* Buffer output functions ----------------------------------------------- */ @@ -69,7 +71,7 @@ char* ha_bufncpy(ha_buffer_t* buf, const char* src, size_t len); /* Opens up the end of the current block so it can be joined by more data */ #define ha_bufjoin(buf) \ - ((buf)->_rp && ((buf)->_rp != (buf)->_pp) ? (buf)->_rp-- : (buf)->_rp) + ((buf)->_rp && ((buf)->_rp != (buf)->_pp) ? (buf)->_rp-- : (buf)->_rp) #define ha_bufcat ha_bufcpy @@ -102,7 +104,6 @@ void* ha_bufdechex(ha_buffer_t* buf, const char* src, size_t* bytes); struct ha_context; struct ha_request; -struct ha_response; /* * This function initializes the handler. It gets called @@ -131,18 +132,18 @@ typedef int (*auth_config_t)(struct ha_context* ctx, const char* name, const cha * for this handler. Note that all data access in this * function must be thread-safe. */ -typedef int (*auth_process_t)(const struct ha_request* req, struct ha_response* resp); +typedef int (*auth_process_t)(struct ha_request* rq); /* An authentication handler */ typedef struct ha_handler { - const char* type; - auth_init_t f_init; /* #1 Called to initialize handler */ - auth_destroy_t f_destroy; /* #3 Called when exiting */ - auth_config_t f_config; /* #0 Called for each config param */ - auth_process_t f_process; /* #2 Called for each auth request */ - const void* context_default; /* The default context */ - const size_t context_size; /* Bytes of extra context needed */ + const char* type; + auth_init_t f_init; /* #1 Called to initialize handler */ + auth_destroy_t f_destroy; /* #3 Called when exiting */ + auth_config_t f_config; /* #0 Called for each config param */ + auth_process_t f_process; /* #2 Called for each auth request */ + const void* context_default; /* The default context */ + const size_t context_size; /* Bytes of extra context needed */ } ha_handler_t; @@ -177,22 +178,22 @@ ha_handler_t; /* Context passed to the handler functions above */ typedef struct ha_context { - const char* name; /* A name assigned by the configuration file */ - const ha_handler_t* handler; /* The original handler structure */ - void* ctx_data; /* Handler specific data */ - - /* Context specific options */ - unsigned int allowed_types; - int cache_timeout; - int cache_max; - - /* For basic and digest auth: */ - const char* realm; - - /* For digest auth: */ - unsigned int digest_ignoreuri : 1; - unsigned int digest_ignorenc : 1; - const char* digest_debugnonce; + const char* name; /* A name assigned by the configuration file */ + const ha_handler_t* handler; /* The original handler structure */ + void* ctx_data; /* Handler specific data */ + + /* Context specific options */ + unsigned int allowed_types; + int cache_timeout; + int cache_max; + + /* For basic and digest auth: */ + const char* realm; + + /* For digest auth: */ + unsigned int digest_ignoreuri : 1; + unsigned int digest_ignorenc : 1; + const char* digest_debugnonce; } ha_context_t; @@ -228,8 +229,8 @@ ha_context_t; /* A single header in memory */ typedef struct ha_header { - const char* name; - const char* data; + const char* name; + const char* data; } ha_header_t; @@ -243,19 +244,25 @@ ha_header_t; #define AUTH_ARG_METHOD 1 #define AUTH_ARG_URI 2 -/* A single request from client */ +/* A single request from client along with response */ typedef struct ha_request { - int type; - const char* args[HA_MAX_ARGS]; - ha_header_t headers[HA_MAX_HEADERS]; + unsigned int id; /* Unique connection identifier */ + + int req_type; /* The command type */ + const char* req_args[HA_MAX_ARGS]; /* Arguments for the command */ + ha_header_t req_headers[HA_MAX_HEADERS]; /* Headers for command */ + + /* Additional request info */ + ha_context_t* context; + const char* digest_domain; - /* Additional request info */ - ha_context_t* context; - const char* digest_domain; + /* The buffer in use */ + ha_buffer_t* buf; - /* The buffer in use */ - ha_buffer_t* buf; + int resp_code; /* The response code */ + const char* resp_detail; /* The details for response */ + ha_header_t resp_headers[HA_MAX_HEADERS]; /* Headers for the response */ } ha_request_t; @@ -267,22 +274,12 @@ ha_request_t; #define HA_SERVER_BADREQ 400 #define HA_SERVER_BUSY 500 -/* A response to the client */ -typedef struct ha_response -{ - int code; - const char* detail; - ha_header_t headers[HA_MAX_HEADERS]; - ha_buffer_t* buf; -} -ha_response_t; - /* Request functions */ -const ha_header_t* ha_findheader(const ha_request_t* req, const char* name); -const char* ha_getheader(const ha_request_t* req, const char* name, const char* prefix); +const ha_header_t* ha_findheader(const ha_request_t* rq, const char* name); +const char* ha_getheader(const ha_request_t* rq, const char* name, const char* prefix); /* Response functions */ -void ha_addheader(ha_response_t* resp, const char* name, const char* data); +void ha_addheader(ha_request_t* rq, const char* name, const char* data); /* Configuration functions */ int ha_confbool(const char* name, const char* conf, int* value); @@ -292,8 +289,8 @@ int ha_confint(const char* name, const char* conf, int min, int max, int* value) * Error Handling */ -void ha_message(int level, const char* msg, ...); -void ha_messagex(int level, const char* msg, ...); +void ha_message(const ha_request_t* rq, int level, const char* msg, ...); +void ha_messagex(const ha_request_t* rq, int level, const char* msg, ...); /* ----------------------------------------------------------------------- @@ -318,14 +315,14 @@ void ha_messagex(int level, const char* msg, ...); typedef struct ha_uri { - const char* scheme; - const char* user; - const char* pw; - const char* host; - unsigned short port; - const char* path; - const char* query; - const char* fragment; + const char* scheme; + const char* user; + const char* pw; + const char* host; + unsigned short port; + const char* path; + const char* query; + const char* fragment; } ha_uri_t; diff --git a/daemon/ldap.c b/daemon/ldap.c index e0349fb..719ac0d 100644 --- a/daemon/ldap.c +++ b/daemon/ldap.c @@ -72,8 +72,8 @@ typedef struct ldap_context ldap_context_t; /* Forward declarations for callbacks */ -static int complete_digest(const ha_request_t* req, const char* user, unsigned char* ha1); -static int validate_basic(const ha_request_t* req, const char* user, const char* password); +static int complete_digest(ha_request_t* rq, const char* user, unsigned char* ha1); +static int validate_basic(ha_request_t* rq, const char* user, const char* password); /* The defaults for the context */ static const ldap_context_t ldap_defaults = @@ -101,20 +101,20 @@ static const ldap_context_t ldap_defaults = * Internal Functions */ -static int report_ldap(const char* msg, int code) +static int report_ldap(const ha_request_t* rq, const char* msg, int code) { ASSERT(code != LDAP_SUCCESS); switch(code) { case LDAP_NO_MEMORY: - ha_messagex(LOG_CRIT, "out of memory"); + ha_messagex(NULL, LOG_CRIT, "out of memory"); return HA_CRITERROR; default: if(!msg) msg = "error"; - ha_messagex(LOG_ERR, "ldap: %s: %s", msg, ldap_err2string(code)); + ha_messagex(rq, LOG_ERR, "%s: %s", msg, ldap_err2string(code)); return HA_FAILED; }; } @@ -159,49 +159,49 @@ static const char* escape_ldap(ha_buffer_t* buf, const char* str) return ha_bufdata(buf); } -static const char* substitute_params(ldap_context_t* ctx, const ha_request_t* req, +static const char* substitute_params(const ha_request_t* rq, ldap_context_t* ctx, const char* user, const char* str) { const char* t; - ASSERT(ctx && req && user && str); + ASSERT(ctx && rq && user && str); /* TODO: We need to be escaping the user and realm properly */ /* This starts a new block to join */ - ha_bufcpy(req->buf, ""); + ha_bufcpy(rq->buf, ""); while(str[0]) { t = strchr(str, '%'); if(!t) { - ha_bufjoin(req->buf); - ha_bufcpy(req->buf, str); + ha_bufjoin(rq->buf); + ha_bufcpy(rq->buf, str); break; } - ha_bufjoin(req->buf); - ha_bufncpy(req->buf, str, t - str); + ha_bufjoin(rq->buf); + ha_bufncpy(rq->buf, str, t - str); t++; switch(t[0]) { case 'u': - ha_bufjoin(req->buf); - escape_ldap(req->buf, user); + ha_bufjoin(rq->buf); + escape_ldap(rq->buf, user); t++; break; case 'r': - ha_bufjoin(req->buf); - escape_ldap(req->buf, req->context->realm); + ha_bufjoin(rq->buf); + escape_ldap(rq->buf, rq->context->realm); t++; break; case '%': - ha_bufjoin(req->buf); - ha_bufcpy(req->buf, "%"); + ha_bufjoin(rq->buf); + ha_bufcpy(rq->buf, "%"); t++; break; }; @@ -209,7 +209,7 @@ static const char* substitute_params(ldap_context_t* ctx, const ha_request_t* re str = t; } - return ha_bufdata(req->buf); + return ha_bufdata(rq->buf); } static const char* make_password_md5(ha_buffer_t* buf, const char* clearpw) @@ -295,17 +295,17 @@ static const char* find_cleartext_password(ha_buffer_t* buf, const char** pws) return NULL; } -static int parse_ldap_ha1(ha_buffer_t* buf, struct berval* bv, unsigned char* ha1) +static int parse_ldap_ha1(const ha_request_t* rq, struct berval* bv, unsigned char* ha1) { size_t len; void* d; - ASSERT(buf && bv && ha1); + ASSERT(rq && bv && ha1); /* Raw binary */ if(bv->bv_len == MD5_LEN) { - ha_messagex(LOG_DEBUG, "ldap: found ha1 in raw binary format"); + ha_messagex(rq, LOG_DEBUG, "found ha1 in raw binary format"); memcpy(ha1, bv->bv_val, MD5_LEN); return HA_OK; } @@ -314,11 +314,11 @@ static int parse_ldap_ha1(ha_buffer_t* buf, struct berval* bv, unsigned char* ha else if(bv->bv_len == (MD5_LEN * 2)) { len = MD5_LEN; - d = ha_bufdechex(buf, bv->bv_val, &len); + d = ha_bufdechex(rq->buf, bv->bv_val, &len); if(d && len == MD5_LEN) { - ha_messagex(LOG_DEBUG, "ldap: found ha1 in hex encoded format"); + ha_messagex(rq, LOG_DEBUG, "found ha1 in hex encoded format"); memcpy(ha1, d, MD5_LEN); return HA_OK; } @@ -328,21 +328,21 @@ static int parse_ldap_ha1(ha_buffer_t* buf, struct berval* bv, unsigned char* ha else { len = MD5_LEN; - d = ha_bufdec64(buf, bv->bv_val, &len); + d = ha_bufdec64(rq->buf, bv->bv_val, &len); if(d && len == MD5_LEN) { - ha_messagex(LOG_DEBUG, "ldap: found ha1 in b64 encoded format"); - memcpy(ha1, ha_bufdata(buf), MD5_LEN); + ha_messagex(rq, LOG_DEBUG, "found ha1 in b64 encoded format"); + memcpy(ha1, ha_bufdata(rq->buf), MD5_LEN); return HA_OK; } } - return ha_buferr(buf) ? HA_CRITERROR : HA_FALSE; + return ha_buferr(rq->buf) ? HA_CRITERROR : HA_FALSE; } -static int validate_ldap_password(ldap_context_t* ctx, LDAP* ld, LDAPMessage* entry, - ha_buffer_t* buf, const char* user, const char* clearpw) +static int validate_ldap_password(const ha_request_t* rq, ldap_context_t* ctx, LDAP* ld, + LDAPMessage* entry, const char* user, const char* clearpw) { char** pws; char** t; @@ -352,7 +352,7 @@ static int validate_ldap_password(ldap_context_t* ctx, LDAP* ld, LDAPMessage* en int res = HA_FALSE; int unknown = 0; - ASSERT(entry && ld && ctx && clearpw); + ASSERT(entry && ld && ctx && clearpw && rq); ASSERT(ctx->pw_attr); pws = ldap_get_values(ld, entry, ctx->pw_attr); @@ -371,7 +371,7 @@ static int validate_ldap_password(ldap_context_t* ctx, LDAP* ld, LDAPMessage* en break; case LDAP_PW_MD5: - p = make_password_md5(buf, clearpw); + p = make_password_md5(rq->buf, clearpw); break; case LDAP_PW_CRYPT: @@ -382,7 +382,7 @@ static int validate_ldap_password(ldap_context_t* ctx, LDAP* ld, LDAPMessage* en break; case LDAP_PW_SHA: - p = make_password_sha(buf, clearpw); + p = make_password_sha(rq->buf, clearpw); break; case LDAP_PW_UNKNOWN: @@ -402,7 +402,7 @@ static int validate_ldap_password(ldap_context_t* ctx, LDAP* ld, LDAPMessage* en if(strcmp(pw, p) == 0) { - ha_messagex(LOG_DEBUG, "ldap: successful validate against password"); + ha_messagex(rq, LOG_DEBUG, "successful validate against password"); res = HA_OK; break; } @@ -412,13 +412,13 @@ static int validate_ldap_password(ldap_context_t* ctx, LDAP* ld, LDAPMessage* en } if(res == HA_FALSE && unknown) - ha_messagex(LOG_ERR, "ldap: server does not contain any compatible passwords for user: %s", user); + ha_messagex(rq, LOG_ERR, "server does not contain any compatible passwords for user: %s", user); return res; } -static int validate_ldap_ha1(ldap_context_t* ctx, LDAP* ld, LDAPMessage* entry, - ha_buffer_t* buf, const char* user, const char* realm, +static int validate_ldap_ha1(const ha_request_t* rq, ldap_context_t* ctx, LDAP* ld, + LDAPMessage* entry, const char* user, const char* realm, const char* clearpw) { struct berval** ha1s; @@ -428,7 +428,7 @@ static int validate_ldap_ha1(ldap_context_t* ctx, LDAP* ld, LDAPMessage* entry, int r, first = 1; int res = HA_FALSE; - ASSERT(ctx && ld && entry && buf && user && clearpw); + ASSERT(ctx && ld && entry && rq && user && clearpw); if(!ctx->ha1_attr) return HA_FALSE; @@ -441,7 +441,7 @@ static int validate_ldap_ha1(ldap_context_t* ctx, LDAP* ld, LDAPMessage* entry, for(b = ha1s ; *b; b++) { - r = parse_ldap_ha1(buf, *b, k); + r = parse_ldap_ha1(rq, *b, k); if(r < 0) { res = r; @@ -451,7 +451,7 @@ static int validate_ldap_ha1(ldap_context_t* ctx, LDAP* ld, LDAPMessage* entry, if(r == HA_FALSE) { if(first) - ha_messagex(LOG_ERR, "ldap: server contains invalid HA1 digest hash for user: %s", user); + ha_messagex(rq, LOG_ERR, "server contains invalid HA1 digest hash for user: %s", user); first = 0; continue; @@ -459,7 +459,7 @@ static int validate_ldap_ha1(ldap_context_t* ctx, LDAP* ld, LDAPMessage* entry, if(memcmp(key, k, MD5_LEN) == 0) { - ha_messagex(LOG_DEBUG, "ldap: successful validate against ha1"); + ha_messagex(rq, LOG_DEBUG, "successful validate against ha1"); res = HA_OK; break; } @@ -471,7 +471,7 @@ static int validate_ldap_ha1(ldap_context_t* ctx, LDAP* ld, LDAPMessage* entry, return res; } -static LDAP* get_ldap_connection(ldap_context_t* ctx) +static LDAP* get_ldap_connection(const ha_request_t* rq, ldap_context_t* ctx) { LDAP* ld; int i, r; @@ -483,7 +483,7 @@ static LDAP* get_ldap_connection(ldap_context_t* ctx) /* An open connection in the pool */ if(ctx->pool[i]) { - ha_messagex(LOG_DEBUG, "ldap: using cached connection"); + ha_messagex(rq, LOG_DEBUG, "using cached connection"); ld = ctx->pool[i]; ctx->pool[i] = NULL; return ld; @@ -492,14 +492,14 @@ static LDAP* get_ldap_connection(ldap_context_t* ctx) if(ctx->pool_mark >= ctx->ldap_max) { - ha_messagex(LOG_ERR, "ldap: too many open connections"); + ha_messagex(rq, LOG_ERR, "too many open connections"); return NULL; } ld = ldap_init(ctx->servers, ctx->port); if(!ld) { - ha_message(LOG_ERR, "ldap: couldn't initialize connection"); + ha_message(rq, LOG_ERR, "couldn't initialize connection"); return NULL; } @@ -509,25 +509,25 @@ static LDAP* get_ldap_connection(ldap_context_t* ctx) ctx->password ? ctx->password : ""); if(r != LDAP_SUCCESS) { - report_ldap("ldap: couldn't bind to LDAP server", r); + report_ldap(rq, "couldn't bind to LDAP server", r); ldap_unbind_s(ld); return NULL; } } ctx->pool_mark++; - ha_messagex(LOG_DEBUG, "ldap: opened new connection (total %d)", ctx->pool_mark); + ha_messagex(rq, LOG_DEBUG, "opened new connection (total %d)", ctx->pool_mark); return ld; } -static void discard_ldap_connection(ldap_context_t* ctx, LDAP* ld) +static void discard_ldap_connection(const ha_request_t* rq, ldap_context_t* ctx, LDAP* ld) { ldap_unbind_s(ld); ctx->pool_mark--; - ha_messagex(LOG_DEBUG, "ldap: discarding connection (total %d)", ctx->pool_mark); + ha_messagex(rq, LOG_DEBUG, "discarding connection (total %d)", ctx->pool_mark); } -static void save_ldap_connection(ldap_context_t* ctx, LDAP* ld) +static void save_ldap_connection(const ha_request_t* rq, ldap_context_t* ctx, LDAP* ld) { int i, e; @@ -544,7 +544,7 @@ static void save_ldap_connection(ldap_context_t* ctx, LDAP* ld) case LDAP_SERVER_DOWN: case LDAP_LOCAL_ERROR: case LDAP_NO_MEMORY: - discard_ldap_connection(ctx, ld); + discard_ldap_connection(rq, ctx, ld); break; default: @@ -553,7 +553,7 @@ static void save_ldap_connection(ldap_context_t* ctx, LDAP* ld) /* An open connection in the pool */ if(!ctx->pool[i]) { - ha_messagex(LOG_DEBUG, "ldap: caching connection for later use"); + ha_messagex(rq, LOG_DEBUG, "caching connection for later use"); ctx->pool[i] = ld; ld = NULL; break; @@ -563,7 +563,7 @@ static void save_ldap_connection(ldap_context_t* ctx, LDAP* ld) }; } -static int retrieve_user_entry(ldap_context_t* ctx, const ha_request_t* req, LDAP* ld, +static int retrieve_user_entry(const ha_request_t* rq, ldap_context_t* ctx, LDAP* ld, const char* user, const char** dn, LDAPMessage** entry, LDAPMessage** result) { @@ -574,12 +574,12 @@ static int retrieve_user_entry(ldap_context_t* ctx, const ha_request_t* req, LDA int scope; int r; - ASSERT(ctx && req && ld && user && dn && entry && result); + ASSERT(ctx && rq && ld && user && dn && entry && result); if(ctx->filter) { /* Filters can also have %u and %r */ - filter = substitute_params(ctx, req, user, ctx->filter); + filter = substitute_params(rq, ctx, user, ctx->filter); if(!filter) return HA_CRITERROR; } @@ -598,7 +598,7 @@ static int retrieve_user_entry(ldap_context_t* ctx, const ha_request_t* req, LDA base = *dn ? *dn : ctx->base; scope = *dn ? LDAP_SCOPE_BASE : ctx->scope; - ha_messagex(LOG_DEBUG, "ldap: performing search: [ base: %s / scope: %d / filter: %s ]", + ha_messagex(rq, LOG_DEBUG, "performing search: [ base: %s / scope: %d / filter: %s ]", base, scope, filter); r = ldap_search_st(ld, base, scope, filter, (char**)attrs, 0, &tv, result); @@ -607,11 +607,11 @@ static int retrieve_user_entry(ldap_context_t* ctx, const ha_request_t* req, LDA { if(r == LDAP_NO_SUCH_OBJECT) { - ha_messagex(LOG_WARNING, "ldap: user not found in LDAP: %s", user); + ha_messagex(rq, LOG_WARNING, "user not found in %s", user); return HA_FALSE; } - return report_ldap("couldn't search LDAP server", r); + return report_ldap(rq, "couldn't search LDAP server", r); } @@ -623,25 +623,25 @@ static int retrieve_user_entry(ldap_context_t* ctx, const ha_request_t* req, LDA if(!(*dn)) { *dn = ldap_get_dn(ld, *entry); - ha_messagex(LOG_DEBUG, "ldap: found entry for user: %s", *dn); + ha_messagex(rq, LOG_DEBUG, "found entry for user: %s", *dn); } return HA_OK; case 0: - ha_messagex(LOG_WARNING, "ldap: user not found in LDAP: %s", user); + ha_messagex(rq, LOG_WARNING, "user not found in %s", user); break; default: - ha_messagex(LOG_WARNING, "ldap: more than one user found for filter: %s", filter); + ha_messagex(rq, LOG_WARNING, "more than one user found for filter: %s", filter); break; }; return HA_FALSE; } -static int complete_digest(const ha_request_t* req, const char* user, unsigned char* ha1) +static int complete_digest(ha_request_t* rq, const char* user, unsigned char* ha1) { - ldap_context_t* ctx = (ldap_context_t*)req->context->ctx_data; + ldap_context_t* ctx = (ldap_context_t*)rq->context->ctx_data; LDAP* ld = NULL; /* freed in finally */ LDAPMessage* results = NULL; /* freed in finally */ LDAPMessage* entry = NULL; /* no need to free */ @@ -651,9 +651,9 @@ static int complete_digest(const ha_request_t* req, const char* user, unsigned c const char* dn = NULL; int r; - ASSERT(req && ha1 && user); + ASSERT(rq && ha1 && user); - ld = get_ldap_connection(ctx); + ld = get_ldap_connection(rq, ctx); if(!ld) { ret = HA_FAILED; @@ -668,18 +668,18 @@ static int complete_digest(const ha_request_t* req, const char* user, unsigned c if(ctx->dnmap) { /* The map can have %u and %r to denote user and realm */ - dn = substitute_params(ctx, req, user, ctx->dnmap); + dn = substitute_params(rq, ctx, user, ctx->dnmap); if(!dn) { ret = HA_FAILED; goto finally; } - ha_messagex(LOG_INFO, "ldap: mapped %s to %s", user, dn); + ha_messagex(rq, LOG_INFO, "mapped %s to %s", user, dn); } /* Okay now we contact the LDAP server. */ - r = retrieve_user_entry(ctx, req, ld, user, &dn, &entry, &results); + r = retrieve_user_entry(rq, ctx, ld, user, &dn, &entry, &results); if(r != HA_OK) { ret = r; @@ -694,15 +694,15 @@ static int complete_digest(const ha_request_t* req, const char* user, unsigned c { if(*ha1s) { - ret = parse_ldap_ha1(req->buf, *ha1s, ha1); + ret = parse_ldap_ha1(rq, *ha1s, ha1); if(ret != HA_OK) { if(ret == HA_FALSE) - ha_messagex(LOG_ERR, "ldap: server contains invalid HA1 for user: %s", user); + ha_messagex(rq, LOG_ERR, "server contains invalid HA1 for user: %s", user); } } - ha_messagex(LOG_DEBUG, "ldap: using HA1 from ldap"); + ha_messagex(rq, LOG_DEBUG, "using HA1 from ldap"); ldap_value_free_len(ha1s); goto finally; } @@ -713,11 +713,11 @@ static int complete_digest(const ha_request_t* req, const char* user, unsigned c if(pws) { /* Find a cleartext password */ - const char* t = find_cleartext_password(req->buf, (const char**)pws); + const char* t = find_cleartext_password(rq->buf, (const char**)pws); if(t) { - digest_makeha1(ha1, user, req->context->realm, t); + digest_makeha1(ha1, user, rq->context->realm, t); ret = HA_OK; } @@ -725,17 +725,17 @@ static int complete_digest(const ha_request_t* req, const char* user, unsigned c if(ret == HA_OK) { - ha_messagex(LOG_DEBUG, "ldap: using clear password from ldap"); + ha_messagex(rq, LOG_DEBUG, "using clear password from ldap"); goto finally; } } - ha_messagex(LOG_ERR, "ldap: server contains no clear password or HA1 for user: %s", user); + ha_messagex(rq, LOG_ERR, "server contains no clear password or HA1 for user: %s", user); finally: if(ld) - save_ldap_connection(ctx, ld); + save_ldap_connection(rq, ctx, ld); if(results) ldap_msgfree(results); @@ -743,9 +743,9 @@ finally: return ret; } -static int validate_basic(const ha_request_t* req, const char* user, const char* password) +static int validate_basic(ha_request_t* rq, const char* user, const char* password) { - ldap_context_t* ctx = (ldap_context_t*)req->context->ctx_data; + ldap_context_t* ctx = (ldap_context_t*)rq->context->ctx_data; LDAP* ld = NULL; LDAPMessage* entry = NULL; LDAPMessage* results = NULL; @@ -754,9 +754,9 @@ static int validate_basic(const ha_request_t* req, const char* user, const char* int found = 0; int r; - ASSERT(req && user && password); + ASSERT(rq && user && password); - ld = get_ldap_connection(ctx); + ld = get_ldap_connection(rq, ctx); if(!ld) { ret = HA_FAILED; @@ -772,14 +772,14 @@ static int validate_basic(const ha_request_t* req, const char* user, const char* if(ctx->dnmap) { /* The map can have %u and %r to denote user and realm */ - dn = substitute_params(ctx, req, user, ctx->dnmap); + dn = substitute_params(rq, ctx, user, ctx->dnmap); if(!dn) { ret = HA_CRITERROR; goto finally; } - ha_messagex(LOG_INFO, "ldap: mapped %s to %s", user, dn); + ha_messagex(rq, LOG_INFO, "mapped %s to %s", user, dn); } @@ -800,7 +800,7 @@ static int validate_basic(const ha_request_t* req, const char* user, const char* if(!ctx->dobind || !dn || ctx->filter) { - r = retrieve_user_entry(ctx, req, ld, user, &dn, &entry, &results); + r = retrieve_user_entry(rq, ctx, ld, user, &dn, &entry, &results); if(r != HA_OK) { ret = r; @@ -818,17 +818,17 @@ static int validate_basic(const ha_request_t* req, const char* user, const char* if(r != LDAP_SUCCESS) { if(r == LDAP_INVALID_CREDENTIALS) - ha_messagex(LOG_WARNING, "ldap: basic authentication (via bind) failed for user: %s", + ha_messagex(rq, LOG_WARNING, "basic authentication (via bind) failed for user: %s", user); else - report_ldap("couldn't bind to LDAP server", r); + report_ldap(rq, "couldn't bind to LDAP server", r); goto finally; } /* It worked! */ - ha_messagex(LOG_NOTICE, "ldap: validated basic user using bind: %s", user); + ha_messagex(rq, LOG_NOTICE, "validated basic user using bind: %s", user); found = 1; /* Now we have to rebind the connection back to the main user */ @@ -836,10 +836,10 @@ static int validate_basic(const ha_request_t* req, const char* user, const char* ctx->password ? ctx->password : ""); if(r != LDAP_SUCCESS) { - report_ldap("ldap: couldn't rebind LDAP connection back to auth credentials", r); + report_ldap(rq, "couldn't rebind LDAP connection back to auth credentials", r); /* Discard the connection since it's useless to us */ - discard_ldap_connection(ctx, ld); + discard_ldap_connection(rq, ctx, ld); ld = NULL; } } @@ -848,27 +848,27 @@ static int validate_basic(const ha_request_t* req, const char* user, const char* /* Otherwise we compare the password attribute */ else { - ret = validate_ldap_password(ctx, ld, entry, req->buf, user, password); + ret = validate_ldap_password(rq, ctx, ld, entry, user, password); if(ret == HA_FALSE) - ret = validate_ldap_ha1(ctx, ld, entry, req->buf, user, - req->context->realm, password); + ret = validate_ldap_ha1(rq, ctx, ld, entry, user, + rq->context->realm, password); if(ret == HA_OK) { - ha_messagex(LOG_NOTICE, "ldap: validated basic user password/ha1: %s", user); + ha_messagex(rq, LOG_NOTICE, "validated basic user password/ha1: %s", user); found = 1; } else { - ha_messagex(LOG_WARNING, "ldap: invalid, unreadable or unrecognized password for user: %s", user); + ha_messagex(rq, LOG_WARNING, "invalid, unreadable or unrecognized password for user: %s", user); } } finally: if(ld) - save_ldap_connection(ctx, ld); + save_ldap_connection(rq, ctx, ld); if(results) ldap_msgfree(results); @@ -946,7 +946,7 @@ int ldap_config(ha_context_t* context, const char* name, const char* value) ctx->scope = LDAP_SCOPE_ONELEVEL; else { - ha_messagex(LOG_ERR, "invalid value for '%s' (must be 'sub', 'base' or 'one')", name); + ha_messagex(NULL, LOG_ERR, "invalid value for '%s' (must be 'sub', 'base' or 'one')", name); return HA_FAILED; } @@ -987,14 +987,14 @@ int ldap_inithand(ha_context_t* context) /* Check for mandatory configuration */ if(!ctx->servers) { - ha_messagex(LOG_ERR, "ldap: configuration incomplete. " + ha_messagex(NULL, LOG_ERR, "configuration incomplete. " "Must have LDAPServers."); return HA_FAILED; } if(!ctx->dnmap && (!ctx->filter || !ctx->base)) { - ha_messagex(LOG_ERR, "ldap: configuration incomplete. " + ha_messagex(NULL, LOG_ERR, "configuration incomplete. " "When not using LDAPDNMap must specify LDAPBase and LDAPFilter."); return HA_FAILED; } @@ -1010,12 +1010,12 @@ int ldap_inithand(ha_context_t* context) ctx->pool = (LDAP**)malloc(sizeof(LDAP*) * ctx->ldap_max); if(!ctx->pool) { - ha_messagex(LOG_CRIT, "out of memory"); + ha_messagex(NULL, LOG_CRIT, "out of memory"); return HA_CRITERROR; } memset(ctx->pool, 0, sizeof(LDAP*) * ctx->ldap_max); - ha_messagex(LOG_INFO, "ldap: initialized handler"); + ha_messagex(NULL, LOG_INFO, "initialized handler"); } return HA_OK; @@ -1046,7 +1046,7 @@ void ldap_destroy(ha_context_t* context) } bd_destroy(context); - ha_messagex(LOG_INFO, "ldap: uninitialized handler"); + ha_messagex(NULL, LOG_INFO, "uninitialized ldap handler"); } diff --git a/daemon/misc.c b/daemon/misc.c index 8e361be..f48d801 100644 --- a/daemon/misc.c +++ b/daemon/misc.c @@ -20,60 +20,71 @@ extern pthread_mutex_t g_mutex; const char kMsgDelimiter[] = ": "; #define MAX_MSGLEN 128 -void ha_messagex(int level, const char* msg, ...) +static void vmessage(const ha_request_t* rq, int level, int err, + const char* msg, va_list ap) { - va_list ap; - va_start(ap, msg); + size_t len; + char* m; + int e = errno; + int x; - ASSERT(msg); + if(g_daemonized) + { + if(level >= LOG_DEBUG) + return; + } + else + { + if(g_debuglevel < level) + return; + } + + ASSERT(msg); - /* Either to syslog or stderr */ - if(g_daemonized) - { - if(level < LOG_DEBUG) - vsyslog(level, msg, ap); - } + len = strlen(msg) + 20 + MAX_MSGLEN; + m = (char*)alloca(len); - else - { - if(g_debuglevel >= level) - vwarnx(msg, ap); - } + if(m) + { + if(rq) + snprintf(m, len, "%06X: %s%s", rq->id, msg, err ? ": " : ""); + else + snprintf(m, len, "%s%s", msg, err ? ": " : ""); - va_end(ap); + if(err) + { + /* TODO: strerror_r doesn't want to work for us + strerror_r(e, m + strlen(m), MAX_MSGLEN); */ + strncat(m, strerror(e), len); + } + + m[len - 1] = 0; + msg = m; + } + + /* Either to syslog or stderr */ + if(g_daemonized) + vsyslog(level, msg, ap); + else + vwarnx(msg, ap); } -void ha_message(int level, const char* msg, ...) +void ha_messagex(const ha_request_t* rq, int level, const char* msg, ...) { - va_list ap; - va_start(ap, msg); - - ASSERT(msg); + va_list ap; - /* Either to syslog or stderr */ - if(g_daemonized) - { - if(level < LOG_DEBUG) - { - char* m = (char*)alloca(strlen(msg) + MAX_MSGLEN + sizeof(kMsgDelimiter)); + va_start(ap, msg); + vmessage(rq, level, 0, msg, ap); + va_end(ap); +} - if(m) - { - strcpy(m, msg); - strcat(m, kMsgDelimiter); - strerror_r(errno, m + strlen(m), MAX_MSGLEN); - } +void ha_message(const ha_request_t* rq, int level, const char* msg, ...) +{ + va_list ap; - vsyslog(LOG_ERR, m ? m : msg, ap); - } - } - else - { - if(g_debuglevel >= level) - vwarn(msg, ap); - } - - va_end(ap); + va_start(ap, msg); + vmessage(rq, level, 1, msg, ap); + va_end(ap); } @@ -81,67 +92,67 @@ void ha_message(int level, const char* msg, ...) * Header Functionality */ -const ha_header_t* ha_findheader(const ha_request_t* req, const char* name) +const ha_header_t* ha_findheader(const ha_request_t* rq, const char* name) { - int i; + int i; - ASSERT(req && name); + ASSERT(rq && name); - for(i = 0; i < HA_MAX_HEADERS; i++) - { - if(req->headers[i].name) + for(i = 0; i < HA_MAX_HEADERS; i++) { - if(strcasecmp(req->headers[i].name, name) == 0) - return &(req->headers[i]); + if(rq->req_headers[i].name) + { + if(strcasecmp(rq->req_headers[i].name, name) == 0) + return &(rq->req_headers[i]); + } } - } - return NULL; + return NULL; } -const char* ha_getheader(const ha_request_t* req, const char* name, const char* prefix) +const char* ha_getheader(const ha_request_t* rq, const char* name, const char* prefix) { - int i, l; + int i, l; - ASSERT(req && name); + ASSERT(rq && name); - for(i = 0; i < HA_MAX_HEADERS; i++) - { - if(req->headers[i].name) + for(i = 0; i < HA_MAX_HEADERS; i++) { - if(strcasecmp(req->headers[i].name, name) == 0) - { - if(!prefix) - return req->headers[i].data; + if(rq->req_headers[i].name) + { + if(strcasecmp(rq->req_headers[i].name, name) == 0) + { + if(!prefix) + return rq->req_headers[i].data; - l = strlen(prefix); + l = strlen(prefix); - if(strncasecmp(prefix, req->headers[i].data, l) == 0) - return req->headers[i].data + l; - } + if(strncasecmp(prefix, rq->req_headers[i].data, l) == 0) + return rq->req_headers[i].data + l; + } + } } - } - return NULL; + return NULL; } -void ha_addheader(ha_response_t* resp, const char* name, const char* data) +void ha_addheader(ha_request_t* rq, const char* name, const char* data) { - int i = 0; + int i = 0; - ASSERT(resp && name && data); + ASSERT(rq && name && data); - for(i = 0; i < HA_MAX_HEADERS; i++) - { - if(!(resp->headers[i].name)) + for(i = 0; i < HA_MAX_HEADERS; i++) { - resp->headers[i].name = name; - resp->headers[i].data = data; - return; + if(!(rq->resp_headers[i].name)) + { + rq->resp_headers[i].name = name; + rq->resp_headers[i].data = data; + return; + } } - } - ha_messagex(LOG_WARNING, "too many headers in response. discarding '%s'", name); + ha_messagex(rq, LOG_WARNING, "too many headers in response. discarding '%s'", name); } @@ -151,51 +162,51 @@ void ha_addheader(ha_response_t* resp, const char* name, const char* data) void ha_lock(pthread_mutex_t* mtx) { - int r; + int r; #ifdef _DEBUG - int wait = 0; + int wait = 0; #endif - if(!mtx) - mtx = &g_mutex; + if(!mtx) + mtx = &g_mutex; #ifdef _DEBUG - r = pthread_mutex_trylock(mtx); - if(r == EBUSY) - { - wait = 1; - ha_message(LOG_DEBUG, "thread will block: %d", pthread_self()); - r = pthread_mutex_lock(mtx); - } + r = pthread_mutex_trylock(mtx); + if(r == EBUSY) + { + wait = 1; + ha_message(NULL, LOG_DEBUG, "thread will block: %d", pthread_self()); + r = pthread_mutex_lock(mtx); + } #else - r = pthread_mutex_lock(mtx); + r = pthread_mutex_lock(mtx); #endif - if(r != 0) - { - errno = r; - ha_message(LOG_CRIT, "threading problem. couldn't lock mutex"); - } + if(r != 0) + { + errno = r; + ha_message(NULL, LOG_CRIT, "threading problem. couldn't lock mutex"); + } #ifdef _DEBUG - else if(wait) - { - ha_message(LOG_DEBUG, "thread unblocked: %d", pthread_self()); - } + else if(wait) + { + ha_message(NULL, LOG_DEBUG, "thread unblocked: %d", pthread_self()); + } #endif } void ha_unlock(pthread_mutex_t* mtx) { - int r = pthread_mutex_unlock(mtx ? mtx : &g_mutex); - if(r != 0) - { - errno = r; - ha_message(LOG_CRIT, "threading problem. couldn't unlock mutex"); - } + int r = pthread_mutex_unlock(mtx ? mtx : &g_mutex); + if(r != 0) + { + errno = r; + ha_message(NULL, LOG_CRIT, "threading problem. couldn't unlock mutex"); + } } @@ -205,51 +216,51 @@ void ha_unlock(pthread_mutex_t* mtx) int ha_confbool(const char* name, const char* conf, int* value) { - ASSERT(name && value); - - if(conf == NULL || - conf[0] == 0 || - strcasecmp(conf, "0") == 0 || - strcasecmp(conf, "no") == 0 || - strcasecmp(conf, "false") == 0 || - strcasecmp(conf, "f") == 0 || - strcasecmp(conf, "off") == 0) - { - *value = 0; - return HA_OK; - } - - if(strcasecmp(conf, "1") == 0 || - strcasecmp(conf, "yes") == 0 || - strcasecmp(conf, "true") == 0 || - strcasecmp(conf, "t") == 0 || - strcasecmp(conf, "on") == 0) - { - *value = 1; - return HA_OK; - } + ASSERT(name && value); + + if(conf == NULL || + conf[0] == 0 || + strcasecmp(conf, "0") == 0 || + strcasecmp(conf, "no") == 0 || + strcasecmp(conf, "false") == 0 || + strcasecmp(conf, "f") == 0 || + strcasecmp(conf, "off") == 0) + { + *value = 0; + return HA_OK; + } - ha_messagex(LOG_ERR, "invalid configuration value '%s': must be 'on' or 'off'.", name); - return HA_FAILED; + if(strcasecmp(conf, "1") == 0 || + strcasecmp(conf, "yes") == 0 || + strcasecmp(conf, "true") == 0 || + strcasecmp(conf, "t") == 0 || + strcasecmp(conf, "on") == 0) + { + *value = 1; + return HA_OK; + } + + ha_messagex(NULL, LOG_ERR, "invalid configuration value '%s': must be 'on' or 'off'.", name); + return HA_FAILED; } int ha_confint(const char* name, const char* conf, int min, int max, int* value) { - char* p; + char* p; - ASSERT(name && conf && value); - ASSERT(min <= max); + ASSERT(name && conf && value); + ASSERT(min <= max); - errno = 0; - *value = strtol(conf, &p, 10); + errno = 0; + *value = strtol(conf, &p, 10); - if(*p || errno == ERANGE || (*value < min) || (*value > max)) - { - ha_messagex(LOG_ERR, "invalid configuration value '%s': must be a number between %d and %d", name, min, max); - return HA_FAILED; - } + if(*p || errno == ERANGE || (*value < min) || (*value > max)) + { + ha_messagex(NULL, LOG_ERR, "invalid configuration value '%s': must be a number between %d and %d", name, min, max); + return HA_FAILED; + } - return HA_OK; + return HA_OK; } @@ -259,366 +270,366 @@ int ha_confint(const char* name, const char* conf, int min, int max, int* value) char* ha_uriformat(ha_buffer_t* buf, const ha_uri_t* uri) { - ASSERT(buf && uri); + ASSERT(buf && uri); - /* This creates a new block */ - ha_bufcpy(buf, ""); + /* This creates a new block */ + ha_bufcpy(buf, ""); + + if(uri->host) + { + const char* l = ""; + const char* r = ""; - if(uri->host) - { - const char* l = ""; - const char* r = ""; + ha_bufmcat(buf, uri->scheme ? uri->scheme : "http", + "://", NULL); - ha_bufmcat(buf, uri->scheme ? uri->scheme : "http", - "://", NULL); + if(uri->user) + { + ha_bufjoin(buf); + ha_bufmcat(buf, uri->user, + uri->pw ? ":" : "", + uri->pw ? uri->pw : "", + "@", NULL); + } - if(uri->user) + if(strchr(uri->host, ':')) /* v6 ip */ + { + l = "["; + r = "]"; + } + + ha_bufjoin(buf); + ha_bufmcat(buf, l, uri->host, r, NULL); + } + + if(uri->path) { - ha_bufjoin(buf); - ha_bufmcat(buf, uri->user, - uri->pw ? ":" : "", - uri->pw ? uri->pw : "", - "@", NULL); + ha_bufjoin(buf); + ha_bufmcat(buf, "/", uri->path); } - if(strchr(uri->host, ':')) /* v6 ip */ + if(uri->query) { - l = "["; - r = "]"; + ha_bufjoin(buf); + ha_bufmcat(buf, "?", uri->query); } - ha_bufjoin(buf); - ha_bufmcat(buf, l, uri->host, r, NULL); - } - - if(uri->path) - { - ha_bufjoin(buf); - ha_bufmcat(buf, "/", uri->path); - } - - if(uri->query) - { - ha_bufjoin(buf); - ha_bufmcat(buf, "?", uri->query); - } - - if(uri->fragment) - { - ha_bufjoin(buf); - ha_bufmcat(buf, "#", uri->fragment); - } - - return ha_bufdata(buf); + if(uri->fragment) + { + ha_bufjoin(buf); + ha_bufmcat(buf, "#", uri->fragment); + } + + return ha_bufdata(buf); } int ha_uriparse(ha_buffer_t* buf, const char* suri, ha_uri_t* uri) { - char* s; - char* s1; - char* hostinfo; - char* endstr; - char* str; - int port; - int v6_offset1 = 0; - - ASSERT(buf && suri && uri); + char* s; + char* s1; + char* hostinfo; + char* endstr; + char* str; + int port; + int v6_offset1 = 0; - /* TODO: We need to http decode the uri */ + ASSERT(buf && suri && uri); - /* Copy the memory */ - str = ha_bufcpy(buf, suri); + /* TODO: We need to http decode the uri */ - if(!str) - return HA_CRITERROR; + /* Copy the memory */ + str = ha_bufcpy(buf, suri); - /* Initialize the structure */ - memset(uri, 0, sizeof(*uri)); + if(!str) + return HA_CRITERROR; - /* - * We assume the processor has a branch predictor like most -- - * it assumes forward branches are untaken and backwards are taken. That's - * the reason for the gotos. -djg - */ - - if(str[0] == '/') - { -deal_with_path: - *str == 0; - ++str; + /* Initialize the structure */ + memset(uri, 0, sizeof(*uri)); /* - * we expect uri to point to first character of path ... remember - * that the path could be empty -- http://foobar?query for example + * We assume the processor has a branch predictor like most -- + * it assumes forward branches are untaken and backwards are taken. That's + * the reason for the gotos. -djg */ - s = str; - while(*s && *s != '?' && *s != '#') - ++s; - - if(s != str) - uri->path = str; - if(*s == 0) - return HA_OK; - - if(*s == '?') + if(str[0] == '/') { - *s = 0; - ++s; - uri->query = s; +deal_with_path: + *str == 0; + ++str; - s1 = strchr(s, '#'); - if(s1) - { - *s1 = 0; - ++s1; - uri->fragment = s1; - } + /* + * we expect uri to point to first character of path ... remember + * that the path could be empty -- http://foobar?query for example + */ + s = str; + while(*s && *s != '?' && *s != '#') + ++s; - return HA_OK; - } + if(s != str) + uri->path = str; - *s = 0; - ++s; + if(*s == 0) + return HA_OK; - /* otherwise it's a fragment */ - uri->fragment = s; - return HA_OK; - } + if(*s == '?') + { + *s = 0; + ++s; + uri->query = s; + + s1 = strchr(s, '#'); + if(s1) + { + *s1 = 0; + ++s1; + uri->fragment = s1; + } + + return HA_OK; + } + + *s = 0; + ++s; - /* find the scheme: */ - s = str; + /* otherwise it's a fragment */ + uri->fragment = s; + return HA_OK; + } - while(*s && *s != ':' && *s != '/' && *s != '?' && *s != '#') - s++; + /* find the scheme: */ + s = str; - /* scheme must be non-empty and followed by :// */ - if(s == str || s[0] != ':' || s[1] != '/' || s[2] != '/') - goto deal_with_path; /* backwards predicted taken! */ + while(*s && *s != ':' && *s != '/' && *s != '?' && *s != '#') + s++; - uri->scheme = str; - *s = 0; - s += 3; + /* scheme must be non-empty and followed by :// */ + if(s == str || s[0] != ':' || s[1] != '/' || s[2] != '/') + goto deal_with_path; /* backwards predicted taken! */ - hostinfo = s; + uri->scheme = str; + *s = 0; + s += 3; - while(*s && *s != '/' && *s != '?' && *s != '#') - ++s; + hostinfo = s; - str = s; /* whatever follows hostinfo is start of uri */ + while(*s && *s != '/' && *s != '?' && *s != '#') + ++s; - /* - * If there's a username:password@host:port, the @ we want is the last @... - * too bad there's no memrchr()... For the C purists, note that hostinfo - * is definately not the first character of the original uri so therefore - * &hostinfo[-1] < &hostinfo[0] ... and this loop is valid C. - */ - do - { - --s; - } - while(s >= hostinfo && *s != '@'); + str = s; /* whatever follows hostinfo is start of uri */ - if(s < hostinfo) - { - /* again we want the common case to be fall through */ -deal_with_host: /* - * We expect hostinfo to point to the first character of - * the hostname. If there's a port it is the first colon, - * except with IPv6. + * If there's a username:password@host:port, the @ we want is the last @... + * too bad there's no memrchr()... For the C purists, note that hostinfo + * is definately not the first character of the original uri so therefore + * &hostinfo[-1] < &hostinfo[0] ... and this loop is valid C. */ - if(*hostinfo == '[') + do { - v6_offset1 = 1; - - s = str; - for(;;) - { --s; + } + while(s >= hostinfo && *s != '@'); - if(s < hostinfo) + if(s < hostinfo) + { + /* again we want the common case to be fall through */ +deal_with_host: + /* + * We expect hostinfo to point to the first character of + * the hostname. If there's a port it is the first colon, + * except with IPv6. + */ + if(*hostinfo == '[') { - s = NULL; /* no port */ - break; + v6_offset1 = 1; + + s = str; + for(;;) + { + --s; + + if(s < hostinfo) + { + s = NULL; /* no port */ + break; + } + + else if(*s == ']') + { + *s = 0; + s = NULL; /* no port */; + break; + } + + else if(*s == ':') + { + *s = 0; + ++s; /* found a port */ + break; + } + } } - else if(*s == ']') + else { - *s = 0; - s = NULL; /* no port */; - break; + s = memchr(hostinfo, ':', str - hostinfo); + if(s) + { + *s = 0; + ++s; + } } - else if(*s == ':') + uri->host = hostinfo + v6_offset1; + + if(s == NULL) { - *s = 0; - ++s; /* found a port */ - break; + /* we expect the common case to have no port */ + goto deal_with_path; } - } - } - else - { - s = memchr(hostinfo, ':', str - hostinfo); - if(s) - { - *s = 0; - ++s; - } + if(str != s) + { + port = strtol(s, &endstr, 10); + uri->port = port; + if(*endstr != '\0') + return HA_FAILED; + } + + goto deal_with_path; } - uri->host = hostinfo + v6_offset1; + /* Remove the @ symbol */ + *s = 0; - if(s == NULL) + /* first colon delimits username:password */ + s1 = memchr(hostinfo, ':', s - hostinfo); + if(s1) { - /* we expect the common case to have no port */ - goto deal_with_path; - } + *s1 = 0; + ++s1; - if(str != s) + uri->user = hostinfo; + uri->pw = s1; + } + else { - port = strtol(s, &endstr, 10); - uri->port = port; - if(*endstr != '\0') - return HA_FAILED; + str = hostinfo; } - goto deal_with_path; - } - - /* Remove the @ symbol */ - *s = 0; - - /* first colon delimits username:password */ - s1 = memchr(hostinfo, ':', s - hostinfo); - if(s1) - { - *s1 = 0; - ++s1; - - uri->user = hostinfo; - uri->pw = s1; - } - else - { - str = hostinfo; - } - - hostinfo = s + 1; - goto deal_with_host; + hostinfo = s + 1; + goto deal_with_host; } -int uri_cmp_part_s(const char* s1, const char* s2, const char* def, int cs) +static int uri_cmp_part_s(const char* s1, const char* s2, const char* def, int cs) { - if(def) - { - if(s1 && strcmp(def, s1) == 0) - s1 = NULL; - if(s2 && strcmp(def, s2) == 0) - s2 = NULL; - } - - if(!s1 && !s2) - return 0; + if(def) + { + if(s1 && strcmp(def, s1) == 0) + s1 = NULL; + if(s2 && strcmp(def, s2) == 0) + s2 = NULL; + } + + if(!s1 && !s2) + return 0; - if(!s1) - return -1; + if(!s1) + return -1; - if(!s2) - return 1; + if(!s2) + return 1; - return cs ? strcasecmp(s1, s2) : strcmp(s1, s2); + return cs ? strcasecmp(s1, s2) : strcmp(s1, s2); } -int uri_cmp_part_n(int n1, int n2, int def) +static int uri_cmp_part_n(int n1, int n2, int def) { - if(def) - { - if(n1 == def) - n1 = 0; - if(n2 == def) - n2 = 0; - } - - if(n1 == n2) - return 0; + if(def) + { + if(n1 == def) + n1 = 0; + if(n2 == def) + n2 = 0; + } + + if(n1 == n2) + return 0; - else if(n1 < n2) - return -1; + else if(n1 < n2) + return -1; - else if(n2 > n1) - return 1; + else if(n2 > n1) + return 1; - /* Not reached */ - ASSERT(0); + /* Not reached */ + ASSERT(0); } int ha_uricmp(ha_uri_t* one, ha_uri_t* two) { - int r; + int r; - ASSERT(one && two); + ASSERT(one && two); - /* We don't compare user or password */ + /* We don't compare user or password */ - /* The scheme */ - if((r = uri_cmp_part_s(one->scheme, two->scheme, "http", 0)) != 0 || - (r = uri_cmp_part_s(one->host, two->host, NULL, 1)) != 0 != 0 || - (r = uri_cmp_part_n(one->port, two->port, 80)) != 0 || - (r = uri_cmp_part_s(one->path, two->path, NULL, 0)) != 0 || - (r = uri_cmp_part_s(one->query, two->query, NULL, 0)) != 0 || - (r = uri_cmp_part_s(one->fragment, two->fragment, NULL, 0))) - return r; + /* The scheme */ + if((r = uri_cmp_part_s(one->scheme, two->scheme, "http", 0)) != 0 || + (r = uri_cmp_part_s(one->host, two->host, NULL, 1)) != 0 != 0 || + (r = uri_cmp_part_n(one->port, two->port, 80)) != 0 || + (r = uri_cmp_part_s(one->path, two->path, NULL, 0)) != 0 || + (r = uri_cmp_part_s(one->query, two->query, NULL, 0)) != 0 || + (r = uri_cmp_part_s(one->fragment, two->fragment, NULL, 0))) + return r; - return 0; + return 0; } int ha_genrandom(unsigned char* data, size_t len) { - int r, dd; - - ASSERT(data && len > 0); - - dd = open("/dev/urandom", O_RDONLY); - if(dd == -1) - { - ha_message(LOG_ERR, "couldn't open /dev/urandom"); - return HA_FAILED; - } + int r, dd; - for(;;) - { - r = read(dd, data, len); + ASSERT(data && len > 0); - if(r == -1) + dd = open("/dev/urandom", O_RDONLY); + if(dd == -1) { - switch(errno) - { - case EINTR: - case EAGAIN: - continue; - - default: - ha_message(LOG_ERR, "couldn't read random bytes from /dev/urandom"); - break; - } - - break; + ha_message(NULL, LOG_ERR, "couldn't open /dev/urandom"); + return HA_FAILED; } - else if(r >= 0) + for(;;) { - if(r >= len) - break; + r = read(dd, data, len); + + if(r == -1) + { + switch(errno) + { + case EINTR: + case EAGAIN: + continue; + + default: + ha_message(NULL, LOG_ERR, "couldn't read random bytes from /dev/urandom"); + break; + }; + + break; + } - len -= r; - data += r; + else if(r >= 0) + { + if(r >= len) + break; + + len -= r; + data += r; + } } - } - close(dd); - return r == -1 ? HA_FAILED : HA_OK; + close(dd); + return r == -1 ? HA_FAILED : HA_OK; } diff --git a/daemon/ntlm.c b/daemon/ntlm.c index 031e19d..63d4580 100644 --- a/daemon/ntlm.c +++ b/daemon/ntlm.c @@ -19,7 +19,7 @@ */ #define NTLM_HASH_KEY_LEN MD5_LEN -#define NTLM_ESTABLISHED (void*)1 +#define NTLM_ESTABLISHED (void*)1 /* ------------------------------------------------------------------------------- @@ -29,9 +29,9 @@ /* A pending connection */ typedef struct ntlm_connection { - void* handle; - char nonce[NONCE_LEN]; - unsigned int flags; + void* handle; + char nonce[NONCE_LEN]; + unsigned int flags; } ntlm_connection_t; @@ -39,16 +39,16 @@ ntlm_connection_t; /* The main context */ typedef struct ntlm_context { - /* Settings ---------------------------------------------------------- */ - const char* server; /* Server to authenticate against */ - const char* domain; /* NTLM domain to authenticate against */ - const char* backup; /* Backup server if primary is down */ - int pending_max; /* Maximum number of connections at once */ - int pending_timeout; /* Timeout for authentication (in seconds) */ - - /* Context ----------------------------------------------------------- */ - hsh_t* pending; /* Pending connections */ - hsh_t* established; /* Established connections */ + /* Settings ---------------------------------------------------------- */ + const char* server; /* Server to authenticate against */ + const char* domain; /* NTLM domain to authenticate against */ + const char* backup; /* Backup server if primary is down */ + int pending_max; /* Maximum number of connections at once */ + int pending_timeout; /* Timeout for authentication (in seconds) */ + + /* Context ----------------------------------------------------------- */ + hsh_t* pending; /* Pending connections */ + hsh_t* established; /* Established connections */ } ntlm_context_t; @@ -56,8 +56,8 @@ ntlm_context_t; /* The default context settings */ static const ntlm_context_t ntlm_defaults = { - NULL, NULL, NULL, DEFAULT_PENDING_MAX, DEFAULT_PENDING_TIMEOUT, - NULL, NULL + NULL, NULL, NULL, DEFAULT_PENDING_MAX, DEFAULT_PENDING_TIMEOUT, + NULL, NULL }; @@ -70,467 +70,467 @@ static pthread_mutexattr_t g_smblib_mutexattr; * Internal Functions */ -static ntlm_connection_t* makeconnection(ntlm_context_t* ctx) +static ntlm_connection_t* makeconnection(ha_request_t* rq, ntlm_context_t* ctx) { - ntlm_connection_t* conn; - - ASSERT(ctx); - - conn = (ntlm_connection_t*)malloc(sizeof(ntlm_connection_t)); - if(!conn) - { - ha_messagex(LOG_CRIT, "out of memory"); - return NULL; - } - - memset(conn, 0, sizeof(*conn)); - - /* - * Open a connection to to the domain controller. I don't think - * we can cache these connections or use them again as opening - * a connection here results in an nonce being generated. - */ - conn->handle = ntlmssp_connect(ctx->server, ctx->backup, - ctx->domain, conn->nonce); - if(!conn->handle) - { - ha_messagex(LOG_ERR, "ntlm: couldn't connect to the domain server %s (backup: %s)", - ctx->server, ctx->backup ? ctx->backup : "none"); - free(conn); - return NULL; - } + ntlm_connection_t* conn; + + ASSERT(ctx); + + conn = (ntlm_connection_t*)malloc(sizeof(ntlm_connection_t)); + if(!conn) + { + ha_messagex(NULL, LOG_CRIT, "out of memory"); + return NULL; + } + + memset(conn, 0, sizeof(*conn)); + + /* + * Open a connection to to the domain controller. I don't think + * we can cache these connections or use them again as opening + * a connection here results in an nonce being generated. + */ + conn->handle = ntlmssp_connect(ctx->server, ctx->backup, + ctx->domain, conn->nonce); + if(!conn->handle) + { + ha_messagex(rq, LOG_ERR, "couldn't connect to the domain server %s (backup: %s)", + ctx->server, ctx->backup ? ctx->backup : "none"); + free(conn); + return NULL; + } - ha_messagex(LOG_INFO, "ntlm: established connection to server"); - return conn; + ha_messagex(rq, LOG_INFO, "established connection to server"); + return conn; } -static void freeconnection(ntlm_connection_t* conn) +static void freeconnection(ha_request_t* rq, ntlm_connection_t* conn) { - ASSERT(conn); + ASSERT(conn); - if(conn->handle) - { - ha_messagex(LOG_DEBUG, "ntlm: disconnected from server"); - ntlmssp_disconnect(conn->handle); - conn->handle = NULL; - } + if(conn->handle) + { + ha_messagex(rq, LOG_DEBUG, "disconnected from server"); + ntlmssp_disconnect(conn->handle); + conn->handle = NULL; + } - free(conn); + free(conn); } static void free_hash_object(void* arg, void* val) { - if(val) - { - ASSERT(val != NTLM_ESTABLISHED); - freeconnection((ntlm_connection_t*)val); - } + if(val) + { + ASSERT(val != NTLM_ESTABLISHED); + freeconnection(NULL, (ntlm_connection_t*)val); + } } static ntlm_connection_t* getpending(ntlm_context_t* ctx, const void* key) { - ntlm_connection_t* ret; + ntlm_connection_t* ret; - ASSERT(ctx && key); + ASSERT(ctx && key); - ha_lock(NULL); + ha_lock(NULL); - ret = (ntlm_connection_t*)hsh_rem(ctx->pending, key); + ret = (ntlm_connection_t*)hsh_rem(ctx->pending, key); - ha_unlock(NULL); + ha_unlock(NULL); - return ret; + return ret; } static int putpending(ntlm_context_t* ctx, const void* key, ntlm_connection_t* conn) { - int r = 0; + int r = 0; - ASSERT(ctx && key && conn); - ASSERT(conn->handle); + ASSERT(ctx && key && conn); + ASSERT(conn->handle); - if(!hsh_get(ctx->pending, key)) - { - ha_lock(NULL); + if(!hsh_get(ctx->pending, key)) + { + ha_lock(NULL); - if(!hsh_set(ctx->pending, key, (void*)conn)) - { - free_hash_object(NULL, conn); - ha_messagex(LOG_ERR, "out of memory"); - r = -1; - } + if(!hsh_set(ctx->pending, key, (void*)conn)) + { + free_hash_object(NULL, conn); + ha_messagex(NULL, LOG_ERR, "out of memory"); + r = -1; + } - ha_unlock(NULL); - } + ha_unlock(NULL); + } - return r; + return r; } -int ntlm_auth_basic(ntlm_context_t* ctx, char* key, const char* header, - ha_response_t* resp, ha_buffer_t* buf) +int ntlm_auth_basic(ha_request_t* rq, ntlm_context_t* ctx, char* key, + const char* header) { - ntlm_connection_t* conn; - char* t; - basic_header_t basic; - const char* domain = NULL; - int found = 0; - int r; - - ASSERT(ctx && key && header && resp && buf); - - /* - * We're doing basic authentication on the connection - * which invalidates any NTLM authentication we've started - * or done on this connection. - */ - conn = getpending(ctx, key); - if(conn) - { - ha_messagex(LOG_WARNING, "ntlm: basic auth killed a pending ntlm auth in progress"); - freeconnection(conn); - } - - if((r = basic_parse(header, buf, &basic)) < 0) - return r; - - /* Check and see if this connection is in the cache */ - ha_lock(NULL); - - if(hsh_get(ctx->established, basic.key) == NTLM_ESTABLISHED) - found = 1; - - ha_unlock(NULL); - - if(found) - ha_messagex(LOG_NOTICE, "ntlm: validated basic user against cache: %s", basic.user); + ntlm_connection_t* conn; + char* t; + basic_header_t basic; + const char* domain = NULL; + int found = 0; + int r; - else - { - /* Try to find a domain in the user */ - if((t = strchr(basic.user, '\\')) != NULL || - (t = strchr(basic.user, '/')) != NULL) - { - /* Break at the domain */ - domain = basic.user; - basic.user = t + 1; - *t = 0; - - /* Make sure this is our domain */ - if(strcasecmp(domain, ctx->domain) != 0) - domain = NULL; - } + ASSERT(ctx && key && header && rq); - if(!domain) + /* + * We're doing basic authentication on the connection + * which invalidates any NTLM authentication we've started + * or done on this connection. + */ + conn = getpending(ctx, key); + if(conn) { - /* Use the default domain if none specified */ - domain = ctx->domain; + ha_messagex(rq, LOG_WARNING, "basic auth killed a pending ntlm auth in progress"); + freeconnection(rq, conn); } - /* Make sure above did not fail */ - if(basic.user && basic.user[0] && basic.password && - domain && domain[0]) - { - ha_messagex(LOG_DEBUG, "ntlm: checking user against server: %s", basic.user); - - /* We need to lock to go into smblib */ - ha_lock(&g_smblib_mutex); - - /* Found in smbval/valid.h */ - if(ntlmssp_validuser(basic.user, basic.password, ctx->server, - ctx->backup, domain) == NTV_NO_ERROR) - { - /* If valid then we return */ - found = 1; - } - - ha_unlock(&g_smblib_mutex); - } - - if(found) - ha_messagex(LOG_NOTICE, "ntlm: validated basic user against server: %s", basic.user); - } - - if(found) - { - int r; - resp->code = HA_SERVER_OK; - resp->detail = basic.user; + if((r = basic_parse(header, rq->buf, &basic)) < 0) + return r; + /* Check and see if this connection is in the cache */ ha_lock(NULL); - /* We put this connection into the successful connections */ - r = hsh_set(ctx->established, basic.key, NTLM_ESTABLISHED); + if(hsh_get(ctx->established, basic.key) == NTLM_ESTABLISHED) + found = 1; ha_unlock(NULL); - if(!r) - { - ha_messagex(LOG_CRIT, "out of memory"); - return HA_CRITERROR; - } - - return HA_OK; - } - - return HA_FALSE; -} + if(found) + ha_messagex(rq, LOG_NOTICE, "validated basic user against cache: %s", basic.user); -int ntlm_auth_ntlm(ntlm_context_t* ctx, void* key, const char* header, - ha_response_t* resp, ha_buffer_t* buf) -{ - ntlmssp_info_rec ntlmssp; - ntlm_connection_t* conn = NULL; - unsigned int flags = 0; - int ret = HA_FALSE; - size_t len = 0; - void* d; - int r; - - ASSERT(ctx && key && header && resp && buf); - - /* - * Retrieve and remove the connection from the pending bag. - * We add it back again below if that's necessary. - */ - conn = getpending(ctx, key); - - /* - * We use the flags from an already established connection - * if we've been pending and stuff - */ - - if(conn && conn->flags) - flags = conn->flags; - - /* - * First we figure out what kind of message the client - * is sending us. - */ - - d = ha_bufdec64(buf, header, &len); - - if(!d || len == 0) - goto finally; - - r = ntlmssp_decode_msg(&ntlmssp, d, len, &flags); - if(r != 0) - { - ha_messagex(LOG_WARNING, "ntlm: decoding NTLMSSP message failed (error %d)", r); - resp->code = HA_SERVER_BADREQ; - goto finally; - } - - - switch(ntlmssp.msg_type) - { - - /* An initial NTLM request? */ - case 1: + else { - /* Win9x doesn't seem to send a domain or host */ - int win9x = !ntlmssp.host[0] && !ntlmssp.domain[0]; - - /* - * If we already have a connection to the domain controller - * then we're in trouble. Basically this is the second - * type 1 message we've received over this connection. - * - * TODO: Eventually what we want to do here is wait for the - * other authentication request to complete, or something - * like that. - */ - if(conn) - { - /* - * In this case we also add the connection back into the - * pending stack so that the correct request will complete - * properly when it comes through. - */ - r = putpending(ctx, key, conn); - conn = NULL; - - if(r < 0) + /* Try to find a domain in the user */ + if((t = strchr(basic.user, '\\')) != NULL || + (t = strchr(basic.user, '/')) != NULL) { - ret = HA_CRITERROR; + /* Break at the domain */ + domain = basic.user; + basic.user = t + 1; + *t = 0; + + /* Make sure this is our domain */ + if(strcasecmp(domain, ctx->domain) != 0) + domain = NULL; } - else + + if(!domain) { - ha_messagex(LOG_ERR, "ntlm: received out of order NTLM request from client"); - resp->code = HA_SERVER_BADREQ; + /* Use the default domain if none specified */ + domain = ctx->domain; } - goto finally; - } - + /* Make sure above did not fail */ + if(basic.user && basic.user[0] && basic.password && + domain && domain[0]) + { + ha_messagex(rq, LOG_DEBUG, "checking user against server: %s", basic.user); - /* - * Check how many connections we have to the domain controller - * and if too many then cut off here. - */ - if(ctx->pending_max != -1) - { - ha_lock(NULL); + /* We need to lock to go into smblib */ + ha_lock(&g_smblib_mutex); - if(hsh_count(ctx->pending) >= ctx->pending_max) - hsh_bump(ctx->pending); + /* Found in smbval/valid.h */ + if(ntlmssp_validuser(basic.user, basic.password, ctx->server, + ctx->backup, domain) == NTV_NO_ERROR) + { + /* If valid then we return */ + found = 1; + } - ha_unlock(NULL); - } + ha_unlock(&g_smblib_mutex); + } + if(found) + ha_messagex(rq, LOG_NOTICE, "validated basic user against server: %s", basic.user); + } - /* - * Open a connection to to the domain controller. I don't think - * we can cache these connections or use them again as opening - * a connection here results in an nonce being generated. - */ - conn = makeconnection(ctx); + if(found) + { + int r; + rq->resp_code = HA_SERVER_OK; + rq->resp_detail = basic.user; - if(!conn) - { - ret = HA_FAILED; - goto finally; - } - - /* Save away any flags given us by ntlm_decode_msg */ - conn->flags = flags; - - /* Start building the header */ - ha_bufcpy(buf, HA_PREFIX_NTLM); - - if(win9x) - { - struct ntlm_msg2_win9x msg_win9x; - ntlmssp_encode_msg2_win9x(conn->nonce, &msg_win9x, (char*)ctx->domain, flags); - ha_bufjoin(buf); - ha_bufenc64(buf, (unsigned char*)&msg_win9x, sizeof(msg_win9x)); - } - else - { - struct ntlm_msg2 msg; - ntlmssp_encode_msg2(conn->nonce, &msg); - ha_bufjoin(buf); - ha_bufenc64(buf, (unsigned char*)&msg, sizeof(msg)); - } - - if(ha_buferr(buf)) - goto finally; + ha_lock(NULL); - /* - * TODO: Our callers need to be able to keep alive - * connections that have authentication going on. - */ + /* We put this connection into the successful connections */ + r = hsh_set(ctx->established, basic.key, NTLM_ESTABLISHED); - /* Cache this connection in our pending set ... */ - r = putpending(ctx, key, conn); + ha_unlock(NULL); - /* - * By marking this as null, the cleanup code - * won't free the connection since it's been - * cached above. - */ - conn = NULL; + if(!r) + { + ha_messagex(NULL, LOG_CRIT, "out of memory"); + return HA_CRITERROR; + } - if(r < 0) - { - ret = HA_CRITERROR; - } - else - { - ha_messagex(LOG_DEBUG, "ntlm: sending ntlm challenge"); - ha_addheader(resp, "WWW-Authenticate", ha_bufdata(buf)); - resp->code = HA_SERVER_DECLINE; - } - goto finally; + return HA_OK; } - /* A response to a challenge */ - case 3: - { - /* - * We need to have a connection at this point or this whole thing - * has come in in the wrong order. Actually it's a client error - * for stuff to come in wrong. But since some web servers also - * kill keep-alives and stuff, we forgive and just ask the client - * for the authentication info again. - */ - if(!conn || !conn->handle) - { - ha_messagex(LOG_WARNING, "ntlm: received out of order NTLM response from client"); - resp->code = HA_SERVER_BADREQ; - goto finally; - } + return HA_FALSE; +} - if(!ntlmssp.user) - { - ha_messagex(LOG_WARNING, "ntlm: received NTLM response without user name"); - resp->code = HA_SERVER_BADREQ; - goto finally; - } +int ntlm_auth_ntlm(ha_request_t* rq, ntlm_context_t* ctx, void* key, + const char* header) +{ + ntlmssp_info_rec ntlmssp; + ntlm_connection_t* conn = NULL; + unsigned int flags = 0; + int ret = HA_FALSE; + size_t len = 0; + void* d; + int r; - /* We have to lock while going into smblib */ - ha_lock(&g_smblib_mutex); + ASSERT(ctx && key && header && rq); - /* Now authenticate them against the DC */ - r = ntlmssp_auth(conn->handle, ntlmssp.user, ntlmssp.nt, 1, - ntlmssp.domain[0] ? (char*)ntlmssp.domain : (char*)ctx->domain); + /* + * Retrieve and remove the connection from the pending bag. + * We add it back again below if that's necessary. + */ + conn = getpending(ctx, key); - ha_unlock(&g_smblib_mutex); + /* + * We use the flags from an already established connection + * if we've been pending and stuff + */ - /* The connection gets disconnected below */ + if(conn && conn->flags) + flags = conn->flags; - if(r == NTV_LOGON_ERROR) - { - /* - * Note that we don't set a code here. This causes our - * caller to put in all the proper headers for us. - */ - ha_messagex(LOG_WARNING, "ntlm: failed NTLM logon for user '%s'", ntlmssp.user); - ret = HA_FALSE; - } + /* + * First we figure out what kind of message the client + * is sending us. + */ - /* A successful login ends here */ - else - { - int r; - resp->detail = ntlmssp.user; - ha_messagex(LOG_NOTICE, "ntlm: validated ntlm user against server", ntlmssp.user); + d = ha_bufdec64(rq->buf, header, &len); - ha_lock(NULL); + if(!d || len == 0) + goto finally; - /* We put this connection into the successful connections */ - r = hsh_set(ctx->established, key, NTLM_ESTABLISHED); + r = ntlmssp_decode_msg(&ntlmssp, d, len, &flags); + if(r != 0) + { + ha_messagex(rq, LOG_WARNING, "decoding NTLMSSP message failed (error %d)", r); + rq->resp_code = HA_SERVER_BADREQ; + goto finally; + } - ha_unlock(NULL); - if(!r) + switch(ntlmssp.msg_type) + { + + /* An initial NTLM request? */ + case 1: { - ha_messagex(LOG_CRIT, "out of memory"); - ret = HA_CRITERROR; + /* Win9x doesn't seem to send a domain or host */ + int win9x = !ntlmssp.host[0] && !ntlmssp.domain[0]; + + /* + * If we already have a connection to the domain controller + * then we're in trouble. Basically this is the second + * type 1 message we've received over this connection. + * + * TODO: Eventually what we want to do here is wait for the + * other authentication request to complete, or something + * like that. + */ + if(conn) + { + /* + * In this case we also add the connection back into the + * pending stack so that the correct request will complete + * properly when it comes through. + */ + r = putpending(ctx, key, conn); + conn = NULL; + + if(r < 0) + { + ret = HA_CRITERROR; + } + else + { + ha_messagex(rq, LOG_ERR, "received out of order NTLM request from client"); + rq->resp_code = HA_SERVER_BADREQ; + } + + goto finally; + } + + + /* + * Check how many connections we have to the domain controller + * and if too many then cut off here. + */ + if(ctx->pending_max != -1) + { + ha_lock(NULL); + + if(hsh_count(ctx->pending) >= ctx->pending_max) + hsh_bump(ctx->pending); + + ha_unlock(NULL); + } + + + /* + * Open a connection to to the domain controller. I don't think + * we can cache these connections or use them again as opening + * a connection here results in an nonce being generated. + */ + conn = makeconnection(rq, ctx); + + if(!conn) + { + ret = HA_FAILED; + goto finally; + } + + /* Save away any flags given us by ntlm_decode_msg */ + conn->flags = flags; + + /* Start building the header */ + ha_bufcpy(rq->buf, HA_PREFIX_NTLM); + + if(win9x) + { + struct ntlm_msg2_win9x msg_win9x; + ntlmssp_encode_msg2_win9x(conn->nonce, &msg_win9x, (char*)ctx->domain, flags); + ha_bufjoin(rq->buf); + ha_bufenc64(rq->buf, (unsigned char*)&msg_win9x, sizeof(msg_win9x)); + } + else + { + struct ntlm_msg2 msg; + ntlmssp_encode_msg2(conn->nonce, &msg); + ha_bufjoin(rq->buf); + ha_bufenc64(rq->buf, (unsigned char*)&msg, sizeof(msg)); + } + + if(ha_buferr(rq->buf)) + goto finally; + + /* + * TODO: Our callers need to be able to keep alive + * connections that have authentication going on. + */ + + /* Cache this connection in our pending set ... */ + r = putpending(ctx, key, conn); + + /* + * By marking this as null, the cleanup code + * won't free the connection since it's been + * cached above. + */ + conn = NULL; + + if(r < 0) + { + ret = HA_CRITERROR; + } + else + { + ha_messagex(rq, LOG_DEBUG, "sending ntlm challenge"); + ha_addheader(rq, "WWW-Authenticate", ha_bufdata(rq->buf)); + rq->resp_code = HA_SERVER_DECLINE; + } + goto finally; } - else + + /* A response to a challenge */ + case 3: { - ret = HA_OK; + /* + * We need to have a connection at this point or this whole thing + * has come in in the wrong order. Actually it's a client error + * for stuff to come in wrong. But since some web servers also + * kill keep-alives and stuff, we forgive and just ask the client + * for the authentication info again. + */ + if(!conn || !conn->handle) + { + ha_messagex(rq, LOG_WARNING, "received out of order NTLM response from client"); + rq->resp_code = HA_SERVER_BADREQ; + goto finally; + } + + if(!ntlmssp.user) + { + ha_messagex(rq, LOG_WARNING, "received NTLM response without user name"); + rq->resp_code = HA_SERVER_BADREQ; + goto finally; + } + + /* We have to lock while going into smblib */ + ha_lock(&g_smblib_mutex); + + /* Now authenticate them against the DC */ + r = ntlmssp_auth(conn->handle, ntlmssp.user, ntlmssp.nt, 1, + ntlmssp.domain[0] ? (char*)ntlmssp.domain : (char*)ctx->domain); + + ha_unlock(&g_smblib_mutex); + + /* The connection gets disconnected below */ + + if(r == NTV_LOGON_ERROR) + { + /* + * Note that we don't set a code here. This causes our + * caller to put in all the proper headers for us. + */ + ha_messagex(rq, LOG_WARNING, "failed NTLM logon for user '%s'", ntlmssp.user); + ret = HA_FALSE; + } + + /* A successful login ends here */ + else + { + int r; + rq->resp_detail = ntlmssp.user; + ha_messagex(rq, LOG_NOTICE, "validated ntlm user against server", ntlmssp.user); + + ha_lock(NULL); + + /* We put this connection into the successful connections */ + r = hsh_set(ctx->established, key, NTLM_ESTABLISHED); + + ha_unlock(NULL); + + if(!r) + { + ha_messagex(NULL, LOG_CRIT, "out of memory"); + ret = HA_CRITERROR; + } + else + { + ret = HA_OK; + } + } + + goto finally; } - } - - goto finally; - } - default: - ha_messagex(LOG_WARNING, "ntlm: received invalid NTLM message (type %d)", ntlmssp.msg_type); - resp->code = HA_SERVER_BADREQ; - goto finally; - }; + default: + ha_messagex(rq, LOG_WARNING, "received invalid NTLM message (type %d)", ntlmssp.msg_type); + rq->resp_code = HA_SERVER_BADREQ; + goto finally; + }; finally: - if(ha_buferr(buf)) - ret = HA_CRITERROR; + if(ha_buferr(rq->buf)) + ret = HA_CRITERROR; - if(conn) - freeconnection(conn); + if(conn) + freeconnection(rq, conn); - return ret; + return ret; } @@ -540,245 +540,245 @@ finally: int ntlm_config(ha_context_t* context, const char* name, const char* value) { - ntlm_context_t* ctx = (ntlm_context_t*)(context->ctx_data); + ntlm_context_t* ctx = (ntlm_context_t*)(context->ctx_data); - ASSERT(name && value && value[0]); + ASSERT(name && value && value[0]); - if(strcmp(name, "ntlmserver") == 0) - { - ctx->server = value; - return HA_OK; - } + if(strcmp(name, "ntlmserver") == 0) + { + ctx->server = value; + return HA_OK; + } - else if(strcmp(name, "ntlmbackup") == 0) - { - ctx->backup = value; - return HA_OK; - } + else if(strcmp(name, "ntlmbackup") == 0) + { + ctx->backup = value; + return HA_OK; + } - else if(strcmp(name, "ntlmdomain") == 0) - { - ctx->domain = value; - return HA_OK; - } + else if(strcmp(name, "ntlmdomain") == 0) + { + ctx->domain = value; + return HA_OK; + } - else if(strcmp(name, "pendingmax") == 0) - { - return ha_confint(name, value, 1, 256, &(ctx->pending_max)); - } + else if(strcmp(name, "pendingmax") == 0) + { + return ha_confint(name, value, 1, 256, &(ctx->pending_max)); + } - else if(strcmp(name, "pendingtimeout") == 0) - { - return ha_confint(name, value, 1, 86400, &(ctx->pending_timeout)); - } + else if(strcmp(name, "pendingtimeout") == 0) + { + return ha_confint(name, value, 1, 86400, &(ctx->pending_timeout)); + } - return HA_FALSE; + return HA_FALSE; } int ntlm_init(ha_context_t* context) { - /* Per context initialization */ - if(context) - { - ntlm_context_t* ctx = (ntlm_context_t*)(context->ctx_data); - hsh_table_calls_t htc; + /* Per context initialization */ + if(context) + { + ntlm_context_t* ctx = (ntlm_context_t*)(context->ctx_data); + hsh_table_calls_t htc; - ASSERT(ctx); + ASSERT(ctx); - /* Make sure there are some types of authentication we can do */ - if(!(context->allowed_types & (HA_TYPE_BASIC | HA_TYPE_NTLM))) - { - ha_messagex(LOG_ERR, "NTLM module configured, but does not implement any " - "configured authentication type."); - return HA_FAILED; - } + /* Make sure there are some types of authentication we can do */ + if(!(context->allowed_types & (HA_TYPE_BASIC | HA_TYPE_NTLM))) + { + ha_messagex(NULL, LOG_ERR, "NTLM module configured, but does not implement any " + "configured authentication type."); + return HA_FAILED; + } - /* Check for mandatory configuration */ - if(!(ctx->server) || !(ctx->domain)) - { - ha_messagex(LOG_ERR, "NTLM configuration incomplete. " - "Must have NTLMServer and NTLMDomain configured."); - return HA_FAILED; - } + /* Check for mandatory configuration */ + if(!(ctx->server) || !(ctx->domain)) + { + ha_messagex(NULL, LOG_ERR, "NTLM configuration incomplete. " + "Must have NTLMServer and NTLMDomain configured."); + return HA_FAILED; + } - ASSERT(!ctx->pending); - ASSERT(!ctx->established); + ASSERT(!ctx->pending); + ASSERT(!ctx->established); - /* Initialize our tables */ - if(!(ctx->pending = hsh_create(NTLM_HASH_KEY_LEN)) || - !(ctx->established = hsh_create(NTLM_HASH_KEY_LEN))) - { - ha_messagex(LOG_CRIT, "out of memory"); - return HA_CRITERROR; - } + /* Initialize our tables */ + if(!(ctx->pending = hsh_create(NTLM_HASH_KEY_LEN)) || + !(ctx->established = hsh_create(NTLM_HASH_KEY_LEN))) + { + ha_messagex(NULL, LOG_CRIT, "out of memory"); + return HA_CRITERROR; + } - htc.f_freeval = free_hash_object; - htc.arg = NULL; - hsh_set_table_calls(ctx->pending, &htc); + htc.f_freeval = free_hash_object; + htc.arg = NULL; + hsh_set_table_calls(ctx->pending, &htc); - ha_messagex(LOG_INFO, "ntlm: initialized handler"); - } + ha_messagex(NULL, LOG_INFO, "initialized ntlm handler"); + } - /* Global Initialization */ - else - { - /* Create the smblib mutex */ - if(pthread_mutexattr_init(&g_smblib_mutexattr) != 0 || - pthread_mutexattr_settype(&g_smblib_mutexattr, HA_MUTEX_TYPE) || - pthread_mutex_init(&g_smblib_mutex, &g_smblib_mutexattr) != 0) + /* Global Initialization */ + else { - ha_messagex(LOG_CRIT, "threading problem. can't create mutex"); - return HA_CRITERROR; + /* Create the smblib mutex */ + if(pthread_mutexattr_init(&g_smblib_mutexattr) != 0 || + pthread_mutexattr_settype(&g_smblib_mutexattr, HA_MUTEX_TYPE) || + pthread_mutex_init(&g_smblib_mutex, &g_smblib_mutexattr) != 0) + { + ha_messagex(NULL, LOG_CRIT, "threading problem. can't create mutex"); + return HA_CRITERROR; + } } - } - return HA_OK; + return HA_OK; } void ntlm_destroy(ha_context_t* context) { - /* Per context destroy */ - if(context) - { - /* Note: We don't need to be thread safe here anymore */ - ntlm_context_t* ctx = (ntlm_context_t*)(context->ctx_data); + /* Per context destroy */ + if(context) + { + /* Note: We don't need to be thread safe here anymore */ + ntlm_context_t* ctx = (ntlm_context_t*)(context->ctx_data); - if(ctx->pending) - hsh_free(ctx->pending); + if(ctx->pending) + hsh_free(ctx->pending); - if(ctx->established) - hsh_free(ctx->established); + if(ctx->established) + hsh_free(ctx->established); - ha_messagex(LOG_INFO, "ntlm: uninitialized handler"); - } + ha_messagex(NULL, LOG_INFO, "uninitialized handler"); + } - /* Global Destroy */ - else - { - /* Close the mutex */ - pthread_mutex_destroy(&g_smblib_mutex); - pthread_mutexattr_destroy(&g_smblib_mutexattr); - } + /* Global Destroy */ + else + { + /* Close the mutex */ + pthread_mutex_destroy(&g_smblib_mutex); + pthread_mutexattr_destroy(&g_smblib_mutexattr); + } } -int ntlm_process(const ha_request_t* req, ha_response_t* resp) +int ntlm_process(ha_request_t* rq) { - ntlm_context_t* ctx = (ntlm_context_t*)(req->context->ctx_data); - void* ntlm_connection_t = NULL; - unsigned char key[NTLM_HASH_KEY_LEN]; - const char* header = NULL; - time_t t = time(NULL); - int ret, r; + ntlm_context_t* ctx = (ntlm_context_t*)(rq->context->ctx_data); + void* ntlm_connection_t = NULL; + unsigned char key[NTLM_HASH_KEY_LEN]; + const char* header = NULL; + time_t t = time(NULL); + int ret, r; - ASSERT(req && resp); - ASSERT(req->args[AUTH_ARG_CONN]); + ASSERT(rq); + ASSERT(rq->req_args[AUTH_ARG_CONN]); - resp->code = -1; + rq->resp_code = -1; - /* Hash the unique key */ - md5_string(key, req->args[AUTH_ARG_CONN]); + /* Hash the unique key */ + md5_string(key, rq->req_args[AUTH_ARG_CONN]); - ha_lock(NULL); + ha_lock(NULL); - /* - * Purge out stale connection stuff. This includes - * authenticated connections which have expired as - * well as half open connections which expire. - */ - r = hsh_purge(ctx->pending, t - ctx->pending_timeout); - r += hsh_purge(ctx->established, t - req->context->cache_timeout); + /* + * Purge out stale connection stuff. This includes + * authenticated connections which have expired as + * well as half open connections which expire. + */ + r = hsh_purge(ctx->pending, t - ctx->pending_timeout); + r += hsh_purge(ctx->established, t - rq->context->cache_timeout); - ha_unlock(NULL); + ha_unlock(NULL); - if(r > 0) - ha_messagex(LOG_DEBUG, "ntlm: purged info from cache: %d", r); + if(r > 0) + ha_messagex(rq, LOG_DEBUG, "purged info from cache: %d", r); - /* Look for a NTLM header */ - if(req->context->allowed_types & HA_TYPE_NTLM) - { - header = ha_getheader(req, "Authorization", HA_PREFIX_NTLM); - if(header) + /* Look for a NTLM header */ + if(rq->context->allowed_types & HA_TYPE_NTLM) { - /* Trim off for decoding */ - header = trim_start(header); + header = ha_getheader(rq, "Authorization", HA_PREFIX_NTLM); + if(header) + { + /* Trim off for decoding */ + header = trim_start(header); - ha_messagex(LOG_DEBUG, "ntlm: processing ntlm auth header"); - ret = ntlm_auth_ntlm(ctx, key, header, resp, req->buf); - if(ret < 0) - return ret; + ha_messagex(rq, LOG_DEBUG, "processing ntlm auth header"); + ret = ntlm_auth_ntlm(rq, ctx, key, header); + if(ret < 0) + return ret; + } } - } - - /* If basic is enabled, and no NTLM */ - if(!header && req->context->allowed_types & HA_TYPE_BASIC) - { - /* Look for a Basic header */ - header = ha_getheader(req, "Authorization", HA_PREFIX_BASIC); - if(header) + + /* If basic is enabled, and no NTLM */ + if(!header && rq->context->allowed_types & HA_TYPE_BASIC) { - /* Trim off for decoding */ - header = trim_start(header); + /* Look for a Basic header */ + header = ha_getheader(rq, "Authorization", HA_PREFIX_BASIC); + if(header) + { + /* Trim off for decoding */ + header = trim_start(header); - ha_messagex(LOG_DEBUG, "ntlm: processing basic auth header"); - ret = ntlm_auth_basic(ctx, key, header, resp, req->buf); - if(ret < 0) - return ret; + ha_messagex(rq, LOG_DEBUG, "processing basic auth header"); + ret = ntlm_auth_basic(rq, ctx, key, header); + if(ret < 0) + return ret; + } } - } - /* The authorization header was not found */ - else - { - ha_lock(NULL); - - /* - * NTLM trusts a connection after it's been authenticated - * so just pass success for those. Note that we do this - * in the absence of a authorization header so that we - * allow connections to be re-authenticated. - */ + /* The authorization header was not found */ + else + { + ha_lock(NULL); - if(hsh_get(ctx->established, key) == NTLM_ESTABLISHED) - { - hsh_touch(ctx->established, key); - resp->code = HA_SERVER_OK; - } + /* + * NTLM trusts a connection after it's been authenticated + * so just pass success for those. Note that we do this + * in the absence of a authorization header so that we + * allow connections to be re-authenticated. + */ - ha_unlock(NULL); + if(hsh_get(ctx->established, key) == NTLM_ESTABLISHED) + { + hsh_touch(ctx->established, key); + rq->resp_code = HA_SERVER_OK; + } - if(resp->code == HA_SERVER_OK) - ha_messagex(LOG_NOTICE, "ntlm: validated user against connection cache"); + ha_unlock(NULL); - /* TODO: We need to be able to retrieve the user here somehow */ - } + if(rq->resp_code == HA_SERVER_OK) + ha_messagex(rq, LOG_NOTICE, "validated user against connection cache"); + /* TODO: We need to be able to retrieve the user here somehow */ + } - /* If nobody's set any other response then... */ - if(resp->code != -1) - { - /* If authentication failed tell the browser about it */ - resp->code = HA_SERVER_DECLINE; - if(req->context->allowed_types & HA_TYPE_NTLM) + /* If nobody's set any other response then... */ + if(rq->resp_code != -1) { - ha_addheader(resp, "WWW-Authenticate", HA_PREFIX_NTLM); - ha_messagex(LOG_DEBUG, "ntlm: sent ntlm auth request"); - } + /* If authentication failed tell the browser about it */ + rq->resp_code = HA_SERVER_DECLINE; - if(req->context->allowed_types & HA_TYPE_BASIC) - { - ha_bufmcat(req->buf, HA_PREFIX_BASIC, "realm=\"", req->context->realm, "\"", NULL); + if(rq->context->allowed_types & HA_TYPE_NTLM) + { + ha_addheader(rq, "WWW-Authenticate", HA_PREFIX_NTLM); + ha_messagex(rq, LOG_DEBUG, "sent ntlm auth request"); + } - if(ha_buferr(req->buf)) - return HA_CRITERROR; + if(rq->context->allowed_types & HA_TYPE_BASIC) + { + ha_bufmcat(rq->buf, HA_PREFIX_BASIC, "realm=\"", rq->context->realm, "\"", NULL); - ha_addheader(resp, "WWW-Authenticate", ha_bufdata(req->buf)); - ha_messagex(LOG_DEBUG, "ntlm: sent basic auth request"); + if(ha_buferr(rq->buf)) + return HA_CRITERROR; + + ha_addheader(rq, "WWW-Authenticate", ha_bufdata(rq->buf)); + ha_messagex(rq, LOG_DEBUG, "sent basic auth request"); + } } - } - return ret; + return ret; } @@ -789,12 +789,12 @@ int ntlm_process(const ha_request_t* req, ha_response_t* resp) ha_handler_t ntlm_handler = { - "NTLM", /* The type */ - ntlm_init, /* Initialization function */ - ntlm_destroy, /* Uninitialization routine */ - ntlm_config, /* Config routine */ - ntlm_process, /* Processing routine */ - &ntlm_defaults, /* Default settings */ - sizeof(ntlm_context_t) + "NTLM", /* The type */ + ntlm_init, /* Initialization function */ + ntlm_destroy, /* Uninitialization routine */ + ntlm_config, /* Config routine */ + ntlm_process, /* Processing routine */ + &ntlm_defaults, /* Default settings */ + sizeof(ntlm_context_t) }; diff --git a/daemon/simple.c b/daemon/simple.c index d570a25..bda60c3 100644 --- a/daemon/simple.c +++ b/daemon/simple.c @@ -20,17 +20,17 @@ typedef struct simple_context { - /* Base Handler ------------------------------------------------------ */ - bd_context_t bd; + /* Base Handler ------------------------------------------------------ */ + bd_context_t bd; - /* Settings ---------------------------------------------------------- */ - const char* filename; /* The file name with the user names */ + /* Settings ---------------------------------------------------------- */ + const char* filename; /* The file name with the user names */ } simple_context_t; /* Forward declarations for callbacks */ -static int complete_digest(const ha_request_t* req, const char* user, unsigned char* ha1); -static int validate_basic(const ha_request_t* req, const char* user, const char* password); +static int complete_digest(ha_request_t* rq, const char* user, unsigned char* ha1); +static int validate_basic(ha_request_t* rq, const char* user, const char* password); /* The defaults for the context */ static const simple_context_t simple_defaults = @@ -43,9 +43,9 @@ static const simple_context_t simple_defaults = * Internal Functions */ -static int complete_digest(const ha_request_t* req, const char* user, unsigned char* ha1) +static int complete_digest(ha_request_t* rq, const char* user, unsigned char* ha1) { - simple_context_t* ctx = (simple_context_t*)req->context->ctx_data; + simple_context_t* ctx = (simple_context_t*)rq->context->ctx_data; FILE* f; char* t; char* t2; @@ -53,13 +53,13 @@ static int complete_digest(const ha_request_t* req, const char* user, unsigned c char line[SIMPLE_MAXLINE]; int ret = HA_FALSE; - ASSERT(ctx && req && user && user[0]); - ha_messagex(LOG_DEBUG, "searching password file for user's ha1: %s", user); + ASSERT(ctx && rq && user && user[0]); + ha_messagex(rq, LOG_DEBUG, "searching password file for user's ha1: %s", user); f = fopen(ctx->filename, "r"); if(!f) { - ha_message(LOG_ERR, "simple: can't open file for basic auth: %s", ctx->filename); + ha_message(rq, LOG_ERR, "can't open file for basic auth: %s", ctx->filename); return HA_FAILED; } @@ -75,7 +75,7 @@ static int complete_digest(const ha_request_t* req, const char* user, unsigned c if(ferror(f)) { - ha_message(LOG_ERR, "simple: error reading basic password file"); + ha_message(rq, LOG_ERR, "error reading basic password file"); ret = HA_FAILED; break; } @@ -98,15 +98,15 @@ static int complete_digest(const ha_request_t* req, const char* user, unsigned c t2++; /* Check the realm */ - if(strcmp(t, req->context->realm) == 0) + if(strcmp(t, rq->context->realm) == 0) { len = MD5_LEN; /* Now try and decode the ha1 */ - t = ha_bufdechex(req->buf, t2, &len); + t = ha_bufdechex(rq->buf, t2, &len); if(t && len == MD5_LEN) { - ha_messagex(LOG_DEBUG, "simple: found ha1 for user: %s", user); + ha_messagex(rq, LOG_DEBUG, "found ha1 for user: %s", user); memcpy(ha1, t, MD5_LEN); ret = HA_OK; break; @@ -115,22 +115,22 @@ static int complete_digest(const ha_request_t* req, const char* user, unsigned c } if(!t2 || ret != HA_OK) - ha_messagex(LOG_WARNING, "simple: user '%s' found in file, but password not in digest format", user); + ha_messagex(rq, LOG_WARNING, "user '%s' found in file, but password not in digest format", user); } } } fclose(f); - if(ha_buferr(req->buf)) + if(ha_buferr(rq->buf)) return HA_CRITERROR; return ret; } -static int validate_basic(const ha_request_t* req, const char* user, const char* password) +static int validate_basic(ha_request_t* rq, const char* user, const char* password) { - simple_context_t* ctx = (simple_context_t*)req->context->ctx_data; + simple_context_t* ctx = (simple_context_t*)rq->context->ctx_data; FILE* f; char line[SIMPLE_MAXLINE]; unsigned char ha1[MD5_LEN]; @@ -139,18 +139,18 @@ static int validate_basic(const ha_request_t* req, const char* user, const char* size_t len; int ret = HA_FALSE; - ASSERT(ctx && req); + ASSERT(ctx && rq); ASSERT(user && user[0] && password); - ha_messagex(LOG_DEBUG, "simple: validating user against password file: %s", user); + ha_messagex(rq, LOG_DEBUG, "validating user against password file: %s", user); f = fopen(ctx->filename, "r"); if(!f) { - ha_message(LOG_ERR, "simple: can't open file for basic auth: %s", ctx->filename); + ha_message(rq, LOG_ERR, "can't open file for basic auth: %s", ctx->filename); return HA_FAILED; } - digest_makeha1(ha1, user, req->context->realm, password); + digest_makeha1(ha1, user, rq->context->realm, password); /* * Note: There should be no returns or jumps between @@ -164,7 +164,7 @@ static int validate_basic(const ha_request_t* req, const char* user, const char* if(ferror(f)) { - ha_message(LOG_ERR, "simple: error reading basic password file"); + ha_message(rq, LOG_ERR, "error reading basic password file"); ret = HA_FAILED; break; } @@ -192,7 +192,7 @@ static int validate_basic(const ha_request_t* req, const char* user, const char* if(strcmp(t2, t) == 0) { - ha_messagex(LOG_DEBUG, "simple: found valid crypt password for user: %s", user); + ha_messagex(rq, LOG_DEBUG, "found valid crypt password for user: %s", user); ret = HA_OK; break; } @@ -205,22 +205,22 @@ static int validate_basic(const ha_request_t* req, const char* user, const char* t2++; /* Check the realm */ - if(strcmp(t, req->context->realm) == 0) + if(strcmp(t, rq->context->realm) == 0) { len = MD5_LEN; /* Now try antd decode the ha1 */ - t = ha_bufdechex(req->buf, t2, &len); + t = ha_bufdechex(rq->buf, t2, &len); if(t && len == MD5_LEN && memcmp(ha1, t, MD5_LEN) == 0) { - ha_messagex(LOG_DEBUG, "simple: found valid ha1 for user: %s", user); + ha_messagex(rq, LOG_DEBUG, "found valid ha1 for user: %s", user); ret = HA_OK; break; } } } - if(ha_buferr(req->buf)) + if(ha_buferr(rq->buf)) break; } } @@ -228,7 +228,7 @@ static int validate_basic(const ha_request_t* req, const char* user, const char* fclose(f); - if(ha_buferr(req->buf)) + if(ha_buferr(rq->buf)) return HA_CRITERROR; return ret; @@ -270,21 +270,21 @@ int simple_init(ha_context_t* context) /* Check to make sure the file exists */ if(!ctx->filename) { - ha_messagex(LOG_ERR, "simple: configuration incomplete. " - "Must have a PasswordFile configured."); + ha_messagex(NULL, LOG_ERR, "configuration incomplete. " + "Must have a PasswordFile configured."); return HA_FAILED; } fd = open(ctx->filename, O_RDONLY); if(fd == -1) { - ha_message(LOG_ERR, "simple: can't open file for authentication: %s", ctx->filename); + ha_message(NULL, LOG_ERR, "can't open file for authentication: %s", ctx->filename); return HA_FAILED; } close(fd); - ha_messagex(LOG_INFO, "simple: initialized handler"); + ha_messagex(NULL, LOG_INFO, "initialized simple handler"); } return HA_OK; @@ -297,12 +297,12 @@ int simple_init(ha_context_t* context) ha_handler_t simple_handler = { - "SIMPLE", /* The type */ - simple_init, /* Initialization function */ - bd_destroy, /* Uninitialization routine */ - simple_config, /* Config routine */ - bd_process, /* Processing routine */ - NULL, /* A default context */ - sizeof(simple_context_t) /* Size of the context */ + "SIMPLE", /* The type */ + simple_init, /* Initialization function */ + bd_destroy, /* Uninitialization routine */ + simple_config, /* Config routine */ + bd_process, /* Processing routine */ + NULL, /* A default context */ + sizeof(simple_context_t) /* Size of the context */ }; diff --git a/daemon/usuals.h b/daemon/usuals.h index e14ecf5..97d355b 100644 --- a/daemon/usuals.h +++ b/daemon/usuals.h @@ -29,10 +29,10 @@ #define countof(x) (sizeof(x) / sizeof(x[0])) #ifdef _DEBUG - #include "assert.h" - #define ASSERT assert + #include "assert.h" + #define ASSERT assert #else - #define ASSERT + #define ASSERT #endif #endif /* __USUALS_H__ */ diff --git a/doc/protocol.txt b/doc/protocol.txt index b6bc0ba..c409c8c 100644 --- a/doc/protocol.txt +++ b/doc/protocol.txt @@ -19,15 +19,12 @@ will be accepted on the connection. REQUESTS ------------------------------------------------------------------- -AUTH authmethod connid method uri +AUTH connid method uri The AUTH command asks the daemon to perform authentication for a given set of header from the client. None of the arguments should contain spaces. - authmethod: is the authentication method. Methods are - defined by the daemon in it's config file. - connid: a unique string identifying the connection from the client. This is only important when NTLM is being used. If not, pass a random string. @@ -44,6 +41,15 @@ AUTH authmethod connid method uri Headers should be specified on one line, not 'wrapped' as is permissible in HTTP. +SET name value + + Sets a given value for the connection. Examples are listed below: + + Handler: The name of handler to use for authentication (as + configured in httpauthd.conf). + + Domain: The domains for digest authentication. + QUIT This closes the connection to the daemon. @@ -64,6 +70,8 @@ The codes are similar to HTTP: 200 Successful Request (detail is described below) + 202 Accepted + 4xx Request Error (detail is an error message) |