Files
bongo/src/libs/nmap/nmap.c
T

1699 lines
49 KiB
C

/****************************************************************************
* <Novell-copyright>
* Copyright (c) 2001 Novell, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public License
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, contact Novell, Inc.
*
* To contact Novell about this file by physical or electronic mail, you
* may find current contact information at www.novell.com.
* </Novell-copyright>
****************************************************************************/
// Parts Copyright (C) 2007 Alex Hudson. See COPYING for details.
/** \file nmap.c
*/
#include <config.h>
#include <xpl.h>
#include <bongoutil.h>
#include <memmgr.h>
#include <nmlib.h>
#include <msgapi.h>
#include <nmap.h>
#include <bongostore.h>
struct {
RegistrationStates state;
unsigned char access[NMAP_HASH_SIZE];
bongo_ssl_context *context;
BOOL debug;
} NMAPLibrary = {
REGISTRATION_LOADING,
{ '\0' },
NULL,
NULL,
FALSE
};
int
NMAPSendCommand(Connection *conn, const unsigned char *command, size_t length)
{
int written;
written = ConnWrite(conn, command, length);
if (written < 0 || (size_t)written != length) {
return -1;
}
if (ConnFlush(conn) < 0) {
return -1;
}
return 0;
}
int
NMAPSendCommandF(Connection *conn, const char *format, ...)
{
va_list ap;
int written;
va_start(ap, format);
written = ConnWriteVF(conn, format, ap);
va_end(ap);
if (written < 0) {
return written;
}
if (ConnFlush(conn) < 0) {
return -1;
} else {
return written;
}
}
__inline static unsigned char *
FindNewLineChar(unsigned char *Buffer, unsigned char *EndPtr) {
register unsigned char *ptr = Buffer;
register unsigned char *endPtr = EndPtr;
do {
if (ptr < endPtr) {
if (*ptr != '\n') {
ptr++;
continue;
}
return(ptr);
}
break;
} while(TRUE);
return(NULL);
}
__inline static unsigned char *
FindEndOfLine(Connection *conn)
{
int count;
char *newLine;
Connection *c = conn;
do {
if ((newLine = FindNewLineChar(c->receive.read, c->receive.write)) != NULL) {
return(newLine);
}
count = c->receive.write - c->receive.read;
if (count < CONN_TCP_MTU) {
if (count == 0) {
CONN_TCP_RECEIVE(c, c->receive.buffer, CONN_TCP_MTU, count);
if (count > 0) {
c->receive.read = c->receive.buffer;
c->receive.write = c->receive.buffer + count;
c->receive.remaining = CONN_TCP_MTU - count;
c->receive.write[0] = '\0';
continue;
}
break;
}
/* preserve unread data in the buffer */
memcpy(c->receive.buffer, c->receive.read, count);
c->receive.read = c->receive.buffer;
c->receive.write = c->receive.buffer + count;
c->receive.remaining = CONN_TCP_MTU - count;
CONN_TCP_RECEIVE(c, c->receive.write, c->receive.remaining, count);
if (count > 0) {
c->receive.write += count;
c->receive.remaining -= count;
c->receive.write[0] = '\0';
continue;
}
break;
}
/* This line is longer than MTU size, NMAP is not supposed to do that on a response line */
return(c->receive.write - 1);
} while (TRUE);
return(NULL);
}
__inline static int
NMAPReadDataAfterResponseCode(Connection *conn, unsigned char *response, size_t length, BOOL RemoveCRLF)
{
int ccode;
int count;
char *newLine;
do {
newLine = FindEndOfLine(conn);
if (newLine) {
if (*newLine == '\n') {
newLine++;
ccode = atol(conn->receive.read);
if (ccode != 6000) {
if ((ccode > 999) && (ccode < 10000) && ((conn->receive.read[4] == ' ') || (conn->receive.read[4] == '-'))) {
if (RemoveCRLF) {
if (newLine[-2] == '\r') {
count = newLine - conn->receive.read - 7;
} else {
count = newLine - conn->receive.read - 6;
}
} else {
count = newLine - conn->receive.read - 5;
}
if ((unsigned long)count < length) {
memcpy(response, conn->receive.read + 5, count);
response[count] = '\0';
conn->receive.read = newLine;
return(ccode);
}
return(NMAP_ERROR_BUFFER_TOO_SHORT);
}
return(NMAP_ERROR_INVALID_RESPONSE_CODE);
}
if (conn->client.cb) {
if (((NMAPOutOfBoundsCallback)conn->client.cb)(conn->client.data, conn->receive.read + 5, newLine)) {
conn->receive.read = newLine;
continue;
}
return(NMAP_ERROR_CALLBACK_FUNCTION_FAILED);
}
return(NMAP_ERROR_CALLBACK_FUNCTION_NOT_DEFINED);
}
return(NMAP_ERROR_LINE_TOO_LONG);
}
break;
} while (TRUE);
return(NMAP_ERROR_COMM);
}
__inline static int
NMAPReadFullLine(Connection *conn, unsigned char *response, size_t length, BOOL RemoveCRLF)
{
int ccode;
int count;
char *newLine;
do {
newLine = FindEndOfLine(conn);
if (newLine) {
if (*newLine == '\n') {
newLine++;
ccode = atol(conn->receive.read);
if (ccode > -1) {
if (ccode != 6000) {
if (RemoveCRLF) {
if (newLine[-2] == '\r') {
count = newLine - conn->receive.read - 2;
} else {
count = newLine - conn->receive.read - 1;
}
} else {
count = newLine - conn->receive.read;
}
if ((unsigned long)count < length) {
memcpy(response, conn->receive.read, count);
response[count] = '\0';
conn->receive.read = newLine;
return(ccode);
}
return(NMAP_ERROR_BUFFER_TOO_SHORT);
}
if (conn->client.cb) {
if (((NMAPOutOfBoundsCallback)conn->client.cb)(conn->client.data, conn->receive.read + 5, newLine)) {
conn->receive.read = newLine;
continue;
}
return(NMAP_ERROR_CALLBACK_FUNCTION_FAILED);
}
return(NMAP_ERROR_CALLBACK_FUNCTION_NOT_DEFINED);
}
return(NMAP_ERROR_INVALID_RESPONSE_CODE);
}
return(NMAP_ERROR_LINE_TOO_LONG);
}
break;
} while (TRUE);
return(NMAP_ERROR_COMM);
}
__inline static int
NMAPReadJustResponseCode(Connection *conn)
{
int ccode;
char *newLine;
do {
newLine = FindEndOfLine(conn);
if (newLine) {
if (*newLine == '\n') {
newLine++;
ccode = atol(conn->receive.read);
if (ccode != 6000) {
if ((ccode > 999) && (ccode < 10000) && ((conn->receive.read[4] == ' ') || (conn->receive.read[4] == '-'))) {
conn->receive.read = newLine;
return(ccode);
}
return(NMAP_ERROR_INVALID_RESPONSE_CODE);
}
if (conn->client.cb) {
if (((NMAPOutOfBoundsCallback)conn->client.cb)(conn->client.data, conn->receive.read + 5, newLine)) {
conn->receive.read = newLine;
continue;
}
return(NMAP_ERROR_CALLBACK_FUNCTION_FAILED);
}
return(NMAP_ERROR_CALLBACK_FUNCTION_NOT_DEFINED);
}
return(NMAP_ERROR_LINE_TOO_LONG);
}
break;
} while (TRUE);
return(NMAP_ERROR_COMM);
}
/** Used to read response lines from NMAP.
Remarks
- will block until a line can be read from the network
- for every 6000 line encountered the callback function is called and the next line is found
- copies the first non 6000 line excluding the \\r\\n into the response buffer
- advances read pointer to the beginning of the next line on success
@return
- positive numeric equivalent of the first characters on the line on success
- negative number on failure
@param conn the network connection to read the line from
@param response is either a pointer to a buffer or NULL.
- \<destination buffer\>
- the response code will be returned
- the line will be copied to the destination buffer
- NULL
- the response code will be returned
@param length the length of the destination buffer
@param check is a boolean value with the following effects:
- TRUE
- the NMAP response code will be validated
- only the data after the response code will be copied to the destination buffer
- FALSE
- will not require the first characters read to be an NMAP response code
- the entire line will be copied to the destination buffer
*/
int
NMAPReadResponse(Connection *conn, unsigned char *response, size_t length, BOOL check)
{
if (response) {
if (check) {
return(NMAPReadDataAfterResponseCode(conn, response, length, TRUE));
} else {
return(NMAPReadFullLine(conn, response, length, TRUE));
}
} else {
return(NMAPReadJustResponseCode(conn));
}
}
/* NMAPReadResponseLine
Same as NMAPReadResponse except that it does not strip the \r\n
*/
int
NMAPReadResponseLine(Connection *conn, unsigned char *response, size_t length, BOOL check)
{
if (response) {
if (check) {
return(NMAPReadDataAfterResponseCode(conn, response, length, FALSE));
} else {
return(NMAPReadFullLine(conn, response, length, FALSE));
}
} else {
return(NMAPReadJustResponseCode(conn));
}
}
/* NMAPReadResponseAndCount
Remarks
This function is designed for reading NMAP responses that take the form:
<response code><' ' | '-'><count>
2021 374 (for example)
This function:
- will block until a line can be read from the network
- for every 6000 line encountered the callback function is called and the next line is found
- evaluates the first non 6000 line
- advances read pointer to the beginning of the next line on success
Return Value
- the NMAP response code on success
- negative number on failure
Parameters
conn - the network connection to read the line from
count - this variable will be assigned the numberic equivalent of
the string following the NMAP response code.
*/
int
NMAPReadResponseAndCount(Connection *conn, unsigned long *count)
{
int ccode;
char *newLine;
do {
newLine = FindEndOfLine(conn);
if (newLine) {
if (*newLine == '\n') {
newLine++;
ccode = atol(conn->receive.read);
if (ccode != 6000) {
if ((ccode > 999) && (ccode < 10000) && ((conn->receive.read[4] == ' ') || (conn->receive.read[4] == '-'))) {
*count = atol(conn->receive.read + 5);
conn->receive.read = newLine;
return(ccode);
}
return(NMAP_ERROR_INVALID_RESPONSE_CODE);
}
if (conn->client.cb) {
if (((NMAPOutOfBoundsCallback)conn->client.cb)(conn->client.data, conn->receive.read + 5, newLine)) {
conn->receive.read = newLine;
continue;
}
return(NMAP_ERROR_CALLBACK_FUNCTION_FAILED);
}
return(NMAP_ERROR_CALLBACK_FUNCTION_NOT_DEFINED);
}
return(NMAP_ERROR_LINE_TOO_LONG);
}
break;
} while (TRUE);
return(NMAP_ERROR_COMM);
}
__inline static int
ReadPropertyValueLen(Connection *conn, const char *propertyName, unsigned long *len)
{
int ccode;
long count;
char *newLine;
do {
newLine = FindEndOfLine(conn);
if (newLine) {
if (*newLine == '\n') {
newLine++;
ccode = atol(conn->receive.read);
if (ccode != 6000) {
if ((ccode > 999) && (ccode < 10000) && ((conn->receive.read[4] == ' ') || (conn->receive.read[4] == '-'))) {
if (ccode == 2001) {
char *ptr = conn->receive.read + 5;
size_t propertyNameLen = strlen(propertyName);
if (XplStrNCaseCmp(ptr, propertyName, propertyNameLen) == 0) {
ptr += propertyNameLen;
if (*ptr == ' ') {
ptr++;
count = atol(ptr);
if (count > -1) {
conn->receive.read = newLine;
*len = (unsigned long)count;
return(2001);
}
}
}
return(NMAP_ERROR_BAD_PROPERTY);
}
conn->receive.read = newLine;
return(ccode);
}
return(NMAP_ERROR_INVALID_RESPONSE_CODE);
}
if (conn->client.cb) {
if (((NMAPOutOfBoundsCallback)conn->client.cb)(conn->client.data, conn->receive.read + 5, newLine)) {
conn->receive.read = newLine;
continue;
}
return(NMAP_ERROR_CALLBACK_FUNCTION_FAILED);
}
return(NMAP_ERROR_CALLBACK_FUNCTION_NOT_DEFINED);
}
return(NMAP_ERROR_LINE_TOO_LONG);
}
break;
} while (TRUE);
return(NMAP_ERROR_COMM);
}
__inline static int
ReadCrLf(Connection *conn)
{
char *newLine;
if (conn->receive.write > (conn->receive.read + 1)) {
if ((conn->receive.read[0] == '\r') && (conn->receive.read[1] == '\n')) {
conn->receive.read += 2;
return(2);
}
return(NMAP_ERROR_PROTOCOL);
}
/* go to the wire */
newLine = FindEndOfLine(conn);
if (newLine) {
if ((newLine == (conn->receive.read + 1)) && (conn->receive.read[0] == '\r')) {
newLine++;
conn->receive.read = newLine;
return(2);
}
return(NMAP_ERROR_PROTOCOL);
}
return(NMAP_ERROR_COMM);
}
__inline static int
ReadPropertyValue(Connection *conn, char *property, long propertyLen)
{
long ccode;
property[propertyLen] = '\0';
if (propertyLen > 0) {
if (NMAPReadCount(conn, property, propertyLen) == propertyLen) {
;
} else {
return(NMAP_ERROR_COMM);
}
}
/* eat the extra CR LF */
if ((ccode = ReadCrLf(conn)) == 2) {
return(propertyLen);
}
return(ccode);
}
__inline static int
ReadProperty(Connection *conn, const char *propertyName, char *propertyBuffer, size_t propertyBufferLen)
{
int ccode;
unsigned long len;
if ((ccode = ReadPropertyValueLen(conn, propertyName, &len)) == 2001) {
if (len < propertyBufferLen) {
if (((ccode = ReadPropertyValue(conn, propertyBuffer, len)) > -1) && ((unsigned long)ccode == len)) {
return(2001);
}
return(ccode);
}
return(NMAP_ERROR_BUFFER_TOO_SHORT);
}
return(ccode);
}
/* Used to read and toss CRLFs that are part of the protocol
Remarks
- will block until a line can be read from the network
- for every 6000 line encountered the callback function is called and the next line is found
- copies the first non 6000 line excluding the \\r\\n into the response buffer
- advances read pointer to the beginning of the next line on success
@return
- positive numeric is the length of the text written to the response buffer.
- negative number on failure
@param conn the network connection to read the line from
*/
int
NMAPReadCrLf(Connection *conn)
{
return(ReadCrLf(conn));
}
/** Used to read the initial response from the GETPROP and READ commands
Remarks
- will block until a line can be read from the network
- for every 6000 line encountered the callback function is called and the next line is found
- copies the first non 6000 line excluding the \\r\\n into the response buffer
- advances read pointer to the beginning of the next line on success
@return
- positive numeric is the length of the text written to the response buffer.
- negative number on failure
@param conn the network connection to read the line from
@param propertyName is the property name expected
@param propertyValueLen the length of the value to be read
*/
int
NMAPReadPropertyValueLength(Connection *conn, const char *propertyName, size_t *propertyValueLen)
{
return(ReadPropertyValueLen(conn, propertyName, (unsigned long *)propertyValueLen));
}
/** Used to read text properties responses from NMAP.
Remarks
- will block until a line can be read from the network
- for every 6000 line encountered the callback function is called and the next line is found
- copies the first non 6000 line excluding the \\r\\n into the response buffer
- advances read pointer to the beginning of the next line on success
@return
- positive numeric is the length of the text written to the response buffer.
- negative number on failure
@param conn the network connection to read the line from
@param propertyName is the property name expected
@param propertyBuffer is a pointer to a buffer where the property value will be copied
@param propertyBufferLen the length of the property buffer
*/
int
NMAPReadTextPropertyResponse(Connection *conn, const char *propertyName, char *propertyBuffer, size_t propertyBufferLen)
{
return(ReadProperty(conn, propertyName, propertyBuffer, propertyBufferLen));
}
/** Used to read text properties responses from NMAP.
Remarks
- will block until a line can be read from the network
- for every 6000 line encountered the callback function is called and the next line is found
- copies the first non 6000 line excluding the \\r\\n into the response buffer
- advances read pointer to the beginning of the next line on success
@return
- positive numeric is the length of the text written to the response buffer.
- negative number on failure
@param conn the network connection to read the line from
@param guid the object where the property will be read
@param propertyName is the property name expected
@param propertyBuffer is a pointer to a buffer where the property value will be copied
@param propertyBufferLen the length of the property buffer
*/
int
NMAPGetTextProperty(Connection *conn, uint64_t guid, const char *propertyName, char *propertyBuffer, size_t propertyBufferLen)
{
if (NMAPSendCommandF(conn, "PROPGET %llx %s\r\n", guid, propertyName) != -1) {
return(ReadProperty(conn, propertyName, propertyBuffer, propertyBufferLen));
}
return(-1);
}
/** Used to write text properties to NMAP.
Remarks
- Sends the PROPSET command to NMAP and processes the response
- processes 6000 response lines encountered
@return
- 1000 on success
- other values between 1001 and 9999 indicate protocol error
- negative value indicates a network error
@param conn the network connection to read the line from
@param guid the object where the property will be applied
@param propertyName is the property name to be set
@param propertyValue is the property value to be set
@param propertyValueLen is the length of the property value to be set
*/
int
NMAPSetTextProperty(Connection *conn, uint64_t guid, const char *propertyName, const char *propertyValue, unsigned long propertyValueLen)
{
long ccode;
if (NMAPSendCommandF(conn, "PROPSET %llx %s %lu\r\n", guid, propertyName, propertyValueLen) != -1) {
ccode = NMAPReadResponse(conn, NULL, 0, 0);
if (ccode == 2002) {
ConnWrite(conn, propertyValue, propertyValueLen);
if (ConnFlush(conn) != -1) {
return(NMAPReadResponse(conn, NULL, 0, 0));
}
return(-1);
}
return(ccode);
}
return(-1);
}
int
NMAPSetTextPropertyFilename(Connection *conn, const char *filename, const char *propertyName, const char *propertyValue, unsigned long propertyValueLen)
{
long ccode;
if (NMAPSendCommandF(conn, "PROPSET \"%s\" %s %lu\r\n", filename, propertyName, propertyValueLen) != -1) {
ccode = NMAPReadResponse(conn, NULL, 0, 0);
if (ccode == 2002) {
ConnWrite(conn, propertyValue, propertyValueLen);
if (ConnFlush(conn) != -1) {
return(NMAPReadResponse(conn, NULL, 0, 0));
}
return(-1);
}
return(ccode);
}
return(-1);
}
#define MAX_DIGITS 25
/** Used to read decimal property responses from NMAP.
Remarks
- will block until a line can be read from the network
- for every 6000 line encountered the callback function is called and the next line is found
- copies the first non 6000 line excluding the \\r\\n into the response buffer
- advances read pointer to the beginning of the next line on success
@return
- 2001 on success
- other values between 1000 and 9999 indicate protocol error
- negative value indicates a network error
@param conn the network connection to read the line from
@param propertyName is the property name expected
@param propertyValue is a pointer where the property value will be set
*/
int
NMAPReadDecimalPropertyResponse(Connection *conn, const char *propertyName, long *propertyValue)
{
long ccode;
char propertyBuffer[MAX_DIGITS];
ccode = ReadProperty(conn, propertyName, propertyBuffer, sizeof(propertyBuffer));
if (ccode == 2001) {
*propertyValue = atol(propertyBuffer);
return(2001);
}
return(ccode);
}
/** Used to read decimal properties from NMAP.
Remarks
- will block until a line can be read from the network
- for every 6000 line encountered the callback function is called and the next line is found
- copies the first non 6000 line excluding the \\r\\n into the response buffer
- advances read pointer to the beginning of the next line on success
@return
- 2001 on success
- other values between 1000 and 9999 indicate protocol error
- negative value indicates a network error
@param conn the network connection to read the line from
@param guid the object where the property will be read
@param propertyName is the property name expected
@param propertyValue is a pointer where the property value will be set
*/
int
NMAPGetDecimalProperty(Connection *conn, uint64_t guid, const char *propertyName, long *propertyValue)
{
if (NMAPSendCommandF(conn, "PROPGET %llx %s\r\n", guid, propertyName) != -1) {
return(NMAPReadDecimalPropertyResponse(conn, propertyName, propertyValue));
}
return(-1);
}
/** Used to read hex properties response from NMAP.
Remarks
- will block until a line can be read from the network
- for every 6000 line encountered the callback function is called and the next line is found
- copies the first non 6000 line excluding the \\r\\n into the response buffer
- advances read pointer to the beginning of the next line on success
@return
- 2001 on success
- other values between 1000 and 9999 indicate protocol error
- negative value indicates a network error
@param conn the network connection to read the line from
@param guid the object where the property will be read
@param propertyName is the property name expected
@param propertyValue is a pointer where the property value will be set
*/
int
NMAPReadHexadecimalPropertyResponse(Connection *conn, const char *propertyName, unsigned long *propertyValue)
{
long ccode;
char propertyBuffer[MAX_DIGITS];
ccode = ReadProperty(conn, propertyName, propertyBuffer, sizeof(propertyBuffer));
if (ccode == 2001) {
*propertyValue = (unsigned long)HexToUInt64(propertyBuffer, NULL);
return(2001);
}
return(ccode);
}
/** Used to read hex properties from NMAP.
Remarks
- will block until a line can be read from the network
- for every 6000 line encountered the callback function is called and the next line is found
- copies the first non 6000 line excluding the \\r\\n into the response buffer
- advances read pointer to the beginning of the next line on success
@return
- 2001 on success
- other values between 1000 and 9999 indicate protocol error
- negative value indicates a network error
@param conn the network connection to read the line from
@param guid the object where the property will be read
@param propertyName is the property name expected
@param propertyValue is a pointer where the property value will be set
*/
int
NMAPGetHexadecimalProperty(Connection *conn, uint64_t guid, const char *propertyName, unsigned long *propertyValue)
{
if (NMAPSendCommandF(conn, "PROPGET %llx %s\r\n", guid, propertyName) != -1) {
return(NMAPReadHexadecimalPropertyResponse(conn, propertyName, propertyValue));
}
return(-1);
}
/** Used to write decimal properties to NMAP.
Remarks
- Sends the PROPSET command to NMAP and processes the response
- processes 6000 response lines encountered
@return
- 1000 on success
- other values between 1001 and 9999 indicate protocol error
- negative value indicates a network error
@param conn the network connection to read the line from
@param guid the object where the property will be applied
@param propertyName is the property name to be set
@param propertyValue is the property value to be set
*/
int
NMAPSetDecimalProperty(Connection *conn, uint64_t guid, const char *propertyName, long propertyValue)
{
long ccode;
char propertyBuffer[MAX_DIGITS];
unsigned long len;
len = snprintf(propertyBuffer, sizeof(propertyBuffer), "%d", (int)propertyValue);
if (NMAPSendCommandF(conn, "PROPSET %llx %s %lu\r\n", guid, propertyName, len) != -1) {
ccode = NMAPReadResponse(conn, NULL, 0, 0);
if (ccode == 2002) {
ConnWrite(conn, propertyBuffer, len);
if (ConnFlush(conn) != -1) {
return(NMAPReadResponse(conn, NULL, 0, 0));
}
return(-1);
}
return(ccode);
}
return(-1);
}
/** Used to write hexadecimal properties to NMAP.
Remarks
- Sends the PROPSET command to NMAP and processes the response
- processes 6000 response lines encountered
@return
- 1000 on success
- other values between 1001 and 9999 indicate protocol error
- negative value indicates a network error
@param conn the network connection to read the line from
@param guid the object where the property will be applied
@param propertyName is the property name to be set
@param propertyValue is the property value to be set
*/
int
NMAPSetHexadecimalProperty(Connection *conn, uint64_t guid, const char *propertyName, unsigned long propertyValue)
{
long ccode;
char propertyBuffer[MAX_DIGITS];
unsigned long len;
len = snprintf(propertyBuffer, sizeof(propertyBuffer), "%x", (unsigned int)propertyValue);
if (NMAPSendCommandF(conn, "PROPSET %llx %s %lu\r\n", guid, propertyName, len) != -1) {
ccode = NMAPReadResponse(conn, NULL, 0, 0);
if (ccode == 2002) {
ConnWrite(conn, propertyBuffer, len);
if (ConnFlush(conn) != -1) {
return(NMAPReadResponse(conn, NULL, 0, 0));
}
return(-1);
}
return(ccode);
}
return(-1);
}
BongoCalObject *
NMAPGetEvents(Connection *conn, const char *calendar, BongoCalTime start, BongoCalTime end)
{
int ccode;
char *split[2];
int n;
int num;
char *data;
char starts[BONGO_CAL_TIME_BUFSIZE];
char ends[BONGO_CAL_TIME_BUFSIZE];
char buffer[CONN_BUFSIZE];
BongoJsonNode *node;
BongoJsonObject *calJson;
BOOL done;
printf("Before, hour is %d, tzid is %s\n", start.hour, BongoCalTimezoneGetTzid(start.tz));
start = BongoCalTimezoneConvertTime(start, BongoCalTimezoneGetUtc());
BongoCalTimeToIcal(start, starts, BONGO_CAL_TIME_BUFSIZE);
printf("after, hour is %d\n", start.hour);
end = BongoCalTimezoneConvertTime(end, BongoCalTimezoneGetUtc());
BongoCalTimeToIcal(end, ends, BONGO_CAL_TIME_BUFSIZE);
calJson = NULL;
done = FALSE;
ccode = NMAPRunCommandF(conn, buffer, CONN_BUFSIZE, "EVENTS %s%s D%s-%s Pnmap.document\r\n",
calendar ? "C" : "",
calendar ? calendar : "",
starts, ends);
do {
switch (ccode) {
case 2001 :
ccode = NMAPReadAnswer(conn, buffer, CONN_BUFSIZE, TRUE);
if (ccode != 2001) {
continue;
}
n = BongoStringSplit(buffer, ' ', split, 2);
if (n != 2 || strcmp(split[0], "nmap.document") != 0) {
continue;
}
num = atoi(split[1]);
data = MemMalloc(num);
ccode = NMAPReadCount(conn, data, num);
if (ccode != num) {
MemFree(data);
continue;
}
ccode = NMAPReadCount(conn, buffer, 2);
if (ccode != 2) {
MemFree(data);
continue;
}
if (BongoJsonParseString(data, &node) == BONGO_JSON_OK &&
node->type == BONGO_JSON_OBJECT) {
if (calJson) {
BongoCalMerge(calJson, BongoJsonNodeAsObject(node));
} else {
calJson = BongoJsonNodeAsObject(node);
}
BongoJsonNodeFreeSteal(node);
}
MemFree(data);
break;
case 1000 :
done = TRUE;
break;
default :
if (ccode < 0) {
done = TRUE;
}
}
if (!done) {
ccode = NMAPReadAnswer(conn, buffer, CONN_BUFSIZE, TRUE);
}
} while (!done && ccode > 0);
if (calJson) {
return BongoCalObjectNew(calJson);
} else {
return NULL;
}
}
int
NMAPCreateCollection(Connection *conn,
const char *collectionName,
uint64_t *guid)
{
int ccode;
char buffer[CONN_BUFSIZE];
ccode = NMAPRunCommandF(conn,
buffer,
CONN_BUFSIZE, "CREATE %s\r\n",
collectionName);
if (ccode != 2002) {
return ccode;
}
ccode = NMAPReadAnswer(conn, buffer, CONN_BUFSIZE, TRUE);
if (guid) {
if (ccode == 1000) {
char *p = strchr(buffer, ' ');
if (p) {
*p = '\0';
}
*guid = HexToUInt64(buffer, &p);
} else if (ccode == 4226) {
char *p = strchr(buffer, ' ');
if (p) {
p = strchr(p, ' ');
}
if (p) {
*p = '\0';
}
*guid = HexToUInt64(buffer, &p);
}
}
return ccode;
}
int
NMAPCreateCalendar(Connection *conn,
const char *calendarName,
uint64_t *guid)
{
char buffer[CONN_BUFSIZE];
int ccode;
ccode = NMAPRunCommandF(conn,
buffer,
CONN_BUFSIZE, "WRITE /calendars %d 0 \"F%s\"\r\n",
STORE_DOCTYPE_CALENDAR,
calendarName);
if (ccode != 2002) {
return ccode;
}
ccode = NMAPReadAnswer(conn, buffer, CONN_BUFSIZE, TRUE);
if (ccode == 1000) {
char *p = strchr(buffer, ' ');
if (p) {
*p = '\0';
}
if (guid) {
*guid = HexToUInt64(buffer, &p);
}
}
return ccode;
}
BOOL
NMAPAddEvent(Connection *conn, BongoCalObject *cal, const char *calendar, char *uid, int uidLen)
{
char *data;
int len;
int ccode;
BOOL ret;
char buffer[CONN_BUFSIZE];
char *p;
ret = FALSE;
data = BongoJsonObjectToString(BongoCalObjectGetJson(cal));
if (!data) {
goto done;
}
len = strlen(data);
ccode = NMAPRunCommandF(conn, buffer, CONN_BUFSIZE, "WRITE /events %d %d \"L/calendars/\"%s\r\n", STORE_DOCTYPE_EVENT, len, calendar);
if (ccode != 2002) {
goto done;
}
ConnWrite(conn, data, len);
ConnFlush(conn);
ccode = NMAPReadAnswer(conn, buffer, CONN_BUFSIZE, TRUE);
if (ccode != 1000) {
goto done;
}
p = strchr(buffer, ' ');
if (p) {
*p = '\0';
}
if (uid) {
BongoStrNCpy(uid, buffer, uidLen);
}
done :
if (data) {
MemFree(data);
}
return ret;
}
/** NMAPRunCommandF
*
* Equivalent to NMAPSendCommandF() followed by NMAPReadResponse().
*
* Return Value
* - server response code
* - -1 upon connection error
*/
int
NMAPRunCommandF(Connection *conn, char *response, size_t length, const char *format, ...)
{
int written;
va_list ap;
va_start(ap, format);
written = ConnWriteVF(conn, format, ap);
va_end(ap);
if (written < 0) {
return -1;
}
if (ConnFlush(conn) < 0) {
return -1;
}
return NMAPReadResponse(conn, response, length, TRUE);
}
/** Read answer from NMAP connection. Optionally parses and returns the NMAP response number.
* \param[in] conn The NMAP Connection struct.
* \param[out] response The buffer to read the response into.
* \param[in] length The maximum number of characters to read into the \c response buffer.
* \param[in] checkForResult Enables or disables parsing out the response number.
* \return If the response number was requested and correctly parsed, then it returns
* that; -1 otherwise.
*/
int
NMAPReadAnswer(Connection *conn, unsigned char *response, size_t length, BOOL checkForResult)
{
int len;
int result = -1;
size_t count;
unsigned char *cur;
len = ConnReadAnswer(conn, response, length);
if (len > 0) {
cur = response + 4;
if (checkForResult && ((*cur == ' ') || (*cur == '-') || ((cur = strchr(response, ' ')) != NULL))) {
*cur++ = '\0';
result = atoi(response);
count = len - (cur - response);
memmove(response, cur, count);
response[count] = '\0';
} else {
result = atoi(response);
}
}
return(result);
}
BOOL
NMAPReadConfigFile(const unsigned char *file, unsigned char **output)
{
Connection *conn;
char buffer[CONN_BUFSIZE + 1];
CCode ccode;
BOOL retcode = FALSE;
int tries;
/* FIXME: caller should be notified when store is ready */
for (tries = 0; tries < 5; tries++) {
conn = NMAPConnect("127.0.0.1", NULL);
if (conn) {
break;
}
XplDelay(1000);
}
if (!conn) {
printf("could not connect to store\n");
return FALSE;
}
if (!NMAPAuthenticate(conn, buffer, sizeof(buffer))) {
printf("could not authenticate to the store\n");
goto nmapfinish;
}
NMAPSendCommandF(conn, "STORE _system\r\n");
ccode = NMAPReadAnswer(conn, buffer, sizeof(buffer), TRUE);
if (ccode != 1000) {
printf("cannot access _system collection\n");
goto nmapfinish;
}
if (-1 != NMAPSendCommandF(conn, "READ /config/%s\r\n", file)) {
size_t count, written;
ccode = NMAPReadPropertyValueLength(conn, "nmap.document", &count);
if (ccode != 2001) {
printf("couldn't load config from store\n");
goto nmapfinish;
}
*output = malloc(sizeof(unsigned char) * (count+1));
written = NMAPReadCount(conn, *output, count);
NMAPReadCrLf(conn);
if (written != count) {
printf("couldn't read config from store\n");
goto nmapfinish;
}
}
retcode = TRUE;
nmapfinish:
NMAPQuit(conn);
ConnFree(conn);
return retcode;
}
int
NMAPReadAnswerLine(Connection *conn, unsigned char *response, size_t length, BOOL checkForResult)
{
int len;
int result = -1 ;
size_t count;
unsigned char *cur;
len = ConnReadLine(conn, response, length);
if (len > 0) {
cur = response + 4;
if (checkForResult && ((*cur == ' ') || (*cur == '-') || ((cur = strchr(response, ' ')) != NULL))) {
*cur++ = '\0';
result = atoi(response);
count = len - (cur - response);
memmove(response, cur, count);
response[count] = '\0';
} else {
result = atoi(response);
}
}
return(result);
}
__inline static Connection *
NmapConnect(unsigned char *address, struct sockaddr_in *addr, int port, TraceDestination *destination)
{
int ccode;
Connection *conn;
if (address || addr) {
conn = ConnAlloc(TRUE);
} else {
return(NULL);
}
if (conn) {
memset(&conn->socketAddress, 0, sizeof(struct sockaddr_in));
if (address) {
conn->socketAddress.sin_family = AF_INET;
conn->socketAddress.sin_addr.s_addr = inet_addr(address);
conn->socketAddress.sin_port = htons(port);
} else {
conn->socketAddress.sin_family = addr->sin_family;
conn->socketAddress.sin_addr.s_addr = addr->sin_addr.s_addr;
conn->socketAddress.sin_port = addr->sin_port;
}
conn->socket = IPsocket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (conn->socket != -1) {
ccode = IPconnect(conn->socket, (struct sockaddr *)&(conn->socketAddress), sizeof(struct sockaddr_in));
CONN_TRACE_BEGIN(conn, CONN_TYPE_NMAP, destination);
CONN_TRACE_EVENT(conn, CONN_TRACE_EVENT_CONNECT);
if (!ccode) {
/* Set TCP non blocking io */
ccode = 1;
setsockopt(conn->socket, IPPROTO_TCP, 1, (unsigned char *)&ccode, sizeof(ccode));
return(conn);
}
CONN_TRACE_ERROR(conn, "connect", ccode);
CONN_TRACE_EVENT(conn, CONN_TRACE_EVENT_CLOSE);
CONN_TRACE_END(conn);
IPclose(conn->socket);
conn->socket = -1;
}
ConnFree(conn);
}
return(NULL);
}
Connection *
NMAPConnect(unsigned char *address, struct sockaddr_in *addr)
{
return(NmapConnect(address, addr, NMAP_PORT, NULL));
}
Connection *
NMAPConnectEx(unsigned char *address, struct sockaddr_in *addr, TraceDestination *destination)
{
return(NmapConnect(address, addr, NMAP_PORT, destination));
}
Connection *
NMAPConnectQueue(unsigned char *address, struct sockaddr_in *addr)
{
return(NmapConnect(address, addr, BONGO_QUEUE_PORT, NULL));
}
Connection *
NMAPConnectQueueEx(unsigned char *address, struct sockaddr_in *addr, TraceDestination *destination)
{
return(NmapConnect(address, addr, BONGO_QUEUE_PORT, NULL));
}
BOOL
NMAPEncrypt(Connection *conn, unsigned char *response, int length, BOOL force)
{
int ccode;
BOOL result;
Connection *c = conn;
result = c->ssl.enable = FALSE;
if (!force && XplIsLocalIPAddress(conn->socketAddress.sin_addr.s_addr)) {
return(TRUE);
}
if (NMAPLibrary.context) {
setsockopt(c->socket, IPPROTO_TCP, 1, (unsigned char *)&ccode, sizeof(ccode));
if (((ccode = ConnWrite(c, "CAPA\r\n", 6)) != -1)
&& ((ccode = ConnFlush(c)) != -1)) {
while ((ccode = NMAPReadAnswer(c, response, length, TRUE)) == 2001) {
if (strcmp(response, "TLS Encryption Extension") != 0) {
continue;
}
result = TRUE;
}
if (ccode != 1000) {
result = FALSE;
}
}
if (result) {
ConnWrite(c, "TLS\r\n", 5);
ConnFlush(c);
if ((NMAPReadAnswer(c, response, length, TRUE)) == 1000) {
c->ssl.enable = TRUE;
NMAPLibrary.context = NMAPSSLContextAlloc();
if (NMAPLibrary.context) {
if (ConnNegotiate(c, NMAPLibrary.context)) {
CONN_TRACE_EVENT(c, CONN_TRACE_EVENT_SSL_CONNECT);
return(TRUE);
}
ConnSSLContextFree(NMAPLibrary.context);
}
NMAPLibrary.context = NULL;
}
}
}
return(FALSE);
}
int
NMAPAuthenticateWithCookie(Connection *conn, const char *user, const char *cookie,
unsigned char *buffer, int length)
{
int ccode;
ccode = NMAPReadAnswer(conn, buffer, length, TRUE);
switch(ccode) {
case 1000:
case 4242:
return NMAPRunCommandF(conn, buffer, length, "AUTH USER %s %s NOSTORE\r\n",
user, cookie);
default:
return ccode;
}
}
/**
* AUTH SYSTEM with the Store agent, but then change to a user and
* go into their store.
* \param conn Connection to the Queue agent
* \param response Buffer to use talking to the agent
* \param length Size of the 'response' buffer
* \return Whether or not we succeeded
*/
BOOL
NMAPAuthenticateThenUserAndStore(Connection *conn, unsigned char *user)
{
char buffer[CONN_BUFSIZE+1];
if (!NMAPAuthenticateToStore(conn, buffer, CONN_BUFSIZE))
return FALSE;
if (NMAPRunCommandF(conn, buffer, CONN_BUFSIZE, "USER %s\r\n", user) != 1000)
return FALSE;
if (NMAPRunCommandF(conn, buffer, CONN_BUFSIZE, "STORE %s\r\n", user) != 1000)
return FALSE;
return TRUE;
}
/**
* AUTH SYSTEM with the Store agent.
* \param conn Connection to the Queue agent
* \param response Buffer to use talking to the agent
* \param length Size of the 'response' buffer
* \return Whether or not we succeeded
*/
BOOL
NMAPAuthenticateToStore(Connection *conn, unsigned char *response, int length)
{
return NMAPAuthenticate(conn, response, length);
}
/**
* AUTH SYSTEM with the Queue agent.
* \param conn Connection to the Queue agent
* \param response Buffer to use talking to the agent
* \param length Size of the 'response' buffer
* \return Whether or not we succeeded
*/
BOOL
NMAPAuthenticateToQueue(Connection *conn, unsigned char *response, int length)
{
return NMAPAuthenticate(conn, response, length);
}
BOOL
NMAPAuthenticate(Connection *conn, unsigned char *response, int length)
{
int ccode;
ccode = NMAPReadAnswer(conn, response, length, TRUE);
switch (ccode) {
case 1000: {
NMAPEncrypt(conn, response, length, FALSE);
return(TRUE);
}
case 4242: {
unsigned char *ptr;
unsigned char *salt;
unsigned char message[XPLHASH_MD5_LENGTH];
xpl_hash_context ctx;
ptr = strchr(response, '<');
if (ptr) {
salt = ++ptr;
if ((ptr = strchr(ptr, '>')) != NULL) {
*ptr = '\0';
}
XplHashNew(&ctx, XPLHASH_MD5);
XplHashWrite(&ctx, salt, strlen(salt));
XplHashWrite(&ctx, NMAPLibrary.access, NMAP_HASH_SIZE);
XplHashFinal(&ctx, XPLHASH_LOWERCASE, message, XPLHASH_MD5_LENGTH);
NMAPEncrypt(conn, response, length, FALSE);
ConnWrite(conn, "AUTH SYSTEM ", 12);
ConnWrite(conn, message, 32);
ConnWrite(conn, "\r\n", 2);
if ((ccode = ConnFlush(conn)) == 46) {
if ((ccode = NMAPReadAnswer(conn, response, length, TRUE)) == 1000) {
return(TRUE);
}
}
}
/*
Fall through to the default case statement.
*/
}
default: {
break;
}
}
return(FALSE);
}
void
NMAPQuit(Connection *conn)
{
ConnWrite(conn, "QUIT\r\n", 6);
CONN_TCP_CLOSE(conn);
return;
}
__inline static RegistrationStates
RegisterWithQueueServer(char *queueServerIpAddress, unsigned short queueServerPort, unsigned long queueNumber, const char *queueAgentServerDn, const char *queueAgentCn, unsigned long queueAgentPort)
{
unsigned long j;
Connection *conn = NULL;
unsigned char response[CONN_BUFSIZE + 1];
NMAPLibrary.state = REGISTRATION_CONNECTING;
do {
conn = NmapConnect(queueServerIpAddress, NULL, queueServerPort, NULL);
if (conn) {
NMAPLibrary.state = REGISTRATION_REGISTERING;
break;
}
for (j = 0; (j < 15) && (NMAPLibrary.state == REGISTRATION_CONNECTING); j++) {
XplDelay(1000);
}
} while (NMAPLibrary.state == REGISTRATION_CONNECTING);
if (NMAPLibrary.state == REGISTRATION_REGISTERING) {
if (NMAPAuthenticate(conn, response, CONN_BUFSIZE)) {
if (ConnWriteF(conn, "QWAIT %lu %d %s%s%lu\r\n", queueNumber, ntohs(queueAgentPort), queueAgentServerDn, queueAgentCn, queueNumber) > 0) {
if (ConnFlush(conn) > -1) {
if (NMAPReadAnswer(conn, response, CONN_BUFSIZE, TRUE) == 1000) {
NMAPLibrary.state = REGISTRATION_COMPLETED;
}
}
}
}
NMAPQuit(conn);
}
if (conn) {
ConnFree(conn);
}
return(NMAPLibrary.state);
}
RegistrationStates
QueueRegister(const unsigned char *queueAgentCn, unsigned long queueNumber, unsigned short queueAgentPort)
{
if (!queueAgentCn) {
NMAPLibrary.state = REGISTRATION_FAILED;
return(NMAPLibrary.state);
}
NMAPLibrary.state = REGISTRATION_ALLOCATING;
RegisterWithQueueServer("127.0.0.1", BONGO_QUEUE_PORT, queueNumber, MsgGetServerDN(NULL), queueAgentCn, queueAgentPort);
if (NMAPLibrary.state != REGISTRATION_COMPLETED) {
NMAPLibrary.state = REGISTRATION_FAILED;
}
return(NMAPLibrary.state);
}
void
NMAPSetEncryption(bongo_ssl_context *context)
{
NMAPLibrary.context = context;
return;
}
bongo_ssl_context *
NMAPSSLContextAlloc(void)
{
ConnSSLConfiguration config;
config.certificate.file = MsgGetTLSCertPath(NULL);
config.key.type = GNUTLS_X509_FMT_PEM;
config.key.file = MsgGetTLSKeyPath(NULL);
return ConnSSLContextAlloc(&config);
}
BOOL
NMAPInitialize(void)
{
// single cred for both store and queue atm...
return MsgGetServerCredential(NMAPLibrary.access);
}