Browse Source

Implemented most functional

Ivan Arkhipov 5 years ago
parent
commit
01a1a62261
5 changed files with 1004 additions and 91 deletions
  1. 155 0
      base64.c
  2. 17 0
      base64.h
  3. 34 0
      includes.h
  4. 259 91
      main.c
  5. 539 0
      os.h

+ 155 - 0
base64.c

@@ -0,0 +1,155 @@
+/*
+ * Base64 encoding/decoding (RFC1341)
+ * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "os.h"
+#include "base64.h"
+
+static const unsigned char base64_table[65] =
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/**
+ * base64_encode - Base64 encode
+ * @src: Data to be encoded
+ * @len: Length of the data to be encoded
+ * @out_len: Pointer to output length variable, or %NULL if not used
+ * Returns: Allocated buffer of out_len bytes of encoded data,
+ * or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer. Returned buffer is
+ * nul terminated to make it easier to use as a C string. The nul terminator is
+ * not included in out_len.
+ */
+unsigned char * base64_encode(const unsigned char *src, size_t len,
+			      size_t *out_len)
+{
+	unsigned char *out, *pos;
+	const unsigned char *end, *in;
+	size_t olen;
+	int line_len;
+
+	olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
+	olen += olen / 72; /* line feeds */
+	olen++; /* nul termination */
+	if (olen < len)
+		return NULL; /* integer overflow */
+	out = os_malloc(olen);
+	if (out == NULL)
+		return NULL;
+
+	end = src + len;
+	in = src;
+	pos = out;
+	line_len = 0;
+	while (end - in >= 3) {
+		*pos++ = base64_table[in[0] >> 2];
+		*pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
+		*pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
+		*pos++ = base64_table[in[2] & 0x3f];
+		in += 3;
+		line_len += 4;
+		if (line_len >= 72) {
+			*pos++ = '\n';
+			line_len = 0;
+		}
+	}
+
+	if (end - in) {
+		*pos++ = base64_table[in[0] >> 2];
+		if (end - in == 1) {
+			*pos++ = base64_table[(in[0] & 0x03) << 4];
+			*pos++ = '=';
+		} else {
+			*pos++ = base64_table[((in[0] & 0x03) << 4) |
+					      (in[1] >> 4)];
+			*pos++ = base64_table[(in[1] & 0x0f) << 2];
+		}
+		*pos++ = '=';
+		line_len += 4;
+	}
+
+	if (line_len)
+		*pos++ = '\n';
+
+	*pos = '\0';
+	if (out_len)
+		*out_len = pos - out;
+	return out;
+}
+
+
+/**
+ * base64_decode - Base64 decode
+ * @src: Data to be decoded
+ * @len: Length of the data to be decoded
+ * @out_len: Pointer to output length variable
+ * Returns: Allocated buffer of out_len bytes of decoded data,
+ * or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer.
+ */
+unsigned char * base64_decode(const unsigned char *src, size_t len,
+			      size_t *out_len)
+{
+	unsigned char dtable[256], *out, *pos, block[4], tmp;
+	size_t i, count, olen;
+	int pad = 0;
+
+	os_memset(dtable, 0x80, 256);
+	for (i = 0; i < sizeof(base64_table) - 1; i++)
+		dtable[base64_table[i]] = (unsigned char) i;
+	dtable['='] = 0;
+
+	count = 0;
+	for (i = 0; i < len; i++) {
+		if (dtable[src[i]] != 0x80)
+			count++;
+	}
+
+	if (count == 0 || count % 4)
+		return NULL;
+
+	olen = count / 4 * 3;
+	pos = out = os_malloc(olen);
+	if (out == NULL)
+		return NULL;
+
+	count = 0;
+	for (i = 0; i < len; i++) {
+		tmp = dtable[src[i]];
+		if (tmp == 0x80)
+			continue;
+
+		if (src[i] == '=')
+			pad++;
+		block[count] = tmp;
+		count++;
+		if (count == 4) {
+			*pos++ = (block[0] << 2) | (block[1] >> 4);
+			*pos++ = (block[1] << 4) | (block[2] >> 2);
+			*pos++ = (block[2] << 6) | block[3];
+			count = 0;
+			if (pad) {
+				if (pad == 1)
+					pos--;
+				else if (pad == 2)
+					pos -= 2;
+				else {
+					/* Invalid padding */
+					os_free(out);
+					return NULL;
+				}
+				break;
+			}
+		}
+	}
+
+	*out_len = pos - out;
+	return out;
+}

+ 17 - 0
base64.h

@@ -0,0 +1,17 @@
+/*
+ * Base64 encoding/decoding (RFC1341)
+ * Copyright (c) 2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BASE64_H
+#define BASE64_H
+
+unsigned char * base64_encode(const unsigned char *src, size_t len,
+			      size_t *out_len);
+unsigned char * base64_decode(const unsigned char *src, size_t len,
+			      size_t *out_len);
+
+#endif /* BASE64_H */

+ 34 - 0
includes.h

@@ -0,0 +1,34 @@
+/*
+ * wpa_supplicant/hostapd - Default include files
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This header file is included into all C files so that commonly used header
+ * files can be selected with OS specific ifdef blocks in one place instead of
+ * having to have OS/C library specific selection in many files.
+ */
+
+#ifndef INCLUDES_H
+#define INCLUDES_H
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+#endif

+ 259 - 91
main.c

@@ -1,21 +1,9 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <time.h>
-#include <ctype.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <pthread.h>
-#include <signal.h>
+#include "includes.h"
+#include "base64.h"
 
 #define SERVER_PORT 12345
 #define MAX_CONNECTIONS 1000
+#define MAX_DIFFERENT_USERS 1024
 
 #define LOCK_FILE_PATH "/tmp/pid.lock"
 #define m_string char*
@@ -78,19 +66,20 @@ typedef struct {
 
 typedef struct {
     void *access_semaphore;
-    char login[256];
-    char password[256];
-    char bound_ip[64];
-    char message[4096];
+    char login[65];
+    char password[65];
+    char bound_ip[17];
+    char message[2049];
 } dbElem;
 
 typedef struct {
     int sockd;
     struct sockaddr_in client_sockaddr;
     int client_sockaddr_size;
+    void *database;
 } clientData;
 
-// DAEMON BASE FUNCTIONS
+// === DAEMON BASE FUNCTIONS ===
 
 // Starts server daemon, returns 1 on success, otherwise 0
 void start_server();
@@ -105,29 +94,35 @@ void show_help();
 void process_server();
 
 
-// SERVER BASE FUNCTIONS
+// === SERVER BASE FUNCTIONS ===
 
 // Creates socket, binds it to defined port and makes ready to listen for connections.
 int create_socket();
 
-// Opens (and creates, if necessary) file for user data and maps it to pointer in shared mode via memory-mapping.
-void *open_database();
+dbElem *getDbElementByUserName(m_string username, dbElem *database);
 
-// Creates worker subprocess for connection, which lives while connection is established and communicates with client.
-// Returns worker pid to parent soon after creation (non-blocking communication).
-int process_request(int client_d, struct sockaddr *addr, void *database);
+dbElem *createNewElement(dbElem *database) {
+    for (int i = 0; i < MAX_DIFFERENT_USERS; ++i) {
+        if (database[i].login[0] == '\0')
+            return &database[i];
+    }
+    return NULL;
+}
 
+dbElem *getDbElementByAssignedIP(m_string ipv4, dbElem *database);
 
-// WORKER BASE FUNCTIONS
+// === WORKER BASE FUNCTIONS ===
 
-// Waits until user request, then returns path, client_ip and header information
-void receive_request(m_string*path, m_string*client_ip, m_string*http_header);
+// Checking user authentification based on bound ip address to database item or matching login and password;
+// Returns 1 and pointer to user dbElem, if auth successfull
+// Returns 0 if there's no user with such login
+// Returns -1 if credentials are incorrect or there's a user with such login, but passwords don't match
+int check_user_authorisation(m_string client_ip, dbElem *database, m_string login, m_string password, dbElem **element);
 
-// Checks if user ip is bound to any login in database. Returns username, if bound and nullptr - if not.
-m_string check_user_authorisation(m_string client_ip);
+int getLoginAndPasswordFromRequest(m_string request, m_string*login, m_string*password);
 
 // Tries to update user message. Returns 1, if successfull, or 0 - if not;
-int update_user_message(m_string username, m_string msg);
+int update_user_message(dbElem *user_data, m_string msg, int len);
 
 void send_404_not_found(int sockd);
 
@@ -135,26 +130,24 @@ void send_401_not_authorised(int sockd);
 
 void send_403_forbidden(int sockd);
 
-void send_200_user_message(int sockd);
-
-void send_error_invalid_message(int sockd);
+// Sends normal message
+void send_200_message(int sockd, m_string message);
 
-// WORKER ADDITIONAL FUNCTIONS
 
-// Sends message
-void send_message(int sockd, const m_string msg);
+// === WORKER ADDITIONAL FUNCTIONS ===
 
 // Returns client address depending on ipv4/ipv6 protocol
 void *get_client_addr(struct sockaddr *);
 
-// Parses http request
-void* handle_request(void* data);
+// Handles request and answers
+void *handle_request(void *data);
 
+// Splits http header and returns type and path
 void parse_http_request(const char *, sHTTPHeader *);
 
 // ============================================================================================= //
 
-int main(int argc, char** argv) {
+int main(int argc, char **argv) {
     if (argc < 2) {
         show_help();
         return 0;
@@ -213,7 +206,8 @@ void stop_server() {
     }
 
     if (kill(pid, SIGTERM) != 0) {
-        fprintf(stderr, "Warning: server pid is incorrect, server might be already stopped (exited), but lock file still exists.\n");
+        fprintf(stderr,
+                "Warning: server pid is incorrect, server might be already stopped (exited), but lock file still exists.\n");
     }
 
     fclose(lock_file);
@@ -236,17 +230,63 @@ void show_help() {
            "");
 }
 
-void * get_client_addr(struct sockaddr * sa) {
-    if (sa -> sa_family == AF_INET) {
-        return &(((struct sockaddr_in * ) sa) -> sin_addr);
+int create_socket() {
+    printf("Creating socket\n");
+    int sock = socket(PF_INET, SOCK_STREAM, 0);
+
+    int on = 1;
+    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+
+    /* initialize the server's sockaddr */
+    struct sockaddr_in server_sockaddr;
+    memset(&server_sockaddr, 0, sizeof(server_sockaddr));
+    server_sockaddr.sin_family = AF_INET;
+    server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+    server_sockaddr.sin_port = htons(SERVER_PORT);
+
+    printf("Binding socket %d to sockaddr %p with size %d\n", sock, (struct sockaddr *) &server_sockaddr,
+           sizeof(server_sockaddr));
+    int bind_result = bind(sock, (struct sockaddr *) &server_sockaddr, sizeof(server_sockaddr));
+    if (bind_result < 0) {
+        fprintf(stderr, "Server: Error: bind failed!");
+        return -1;
+    }
+
+    listen(sock, MAX_CONNECTIONS);
+
+    return sock;
+}
+
+dbElem *getDbElementByUserName(m_string username, dbElem *database) {
+    for (int i = 0; i < MAX_DIFFERENT_USERS; ++i) {
+        if (strcmp(database[i].login, username) == 0)
+            return &database[i];
+    }
+    return NULL;
+}
+
+dbElem *getDbElementByAssignedIP(m_string ipv4, dbElem *database) {
+    for (int i = 0; i < MAX_DIFFERENT_USERS; ++i) {
+        if (strcmp(database[i].bound_ip, ipv4) == 0)
+            return &database[i];
+    }
+    return NULL;
+}
+
+void *get_client_addr(struct sockaddr *sa) {
+    if (sa->sa_family == AF_INET) {
+        return &(((struct sockaddr_in *) sa)->sin_addr);
     }
 
-    return &(((struct sockaddr_in6 * ) sa) -> sin6_addr);
+    return &(((struct sockaddr_in6 *) sa)->sin6_addr);
 }
 
 void process_server() {
     int sock = create_socket();
 
+    dbElem *database = malloc(sizeof(dbElem) * MAX_DIFFERENT_USERS);
+    memset(database, 0, sizeof(dbElem) * MAX_DIFFERENT_USERS);
+
     if (sock < 0) {
         fprintf(stderr, "Server: Error, cannot create socket!\n");
         return;
@@ -257,7 +297,7 @@ void process_server() {
     while (1) {
         clientData *data = malloc(sizeof(clientData)); // would be freed in thread after its finishing
         data->sockd = accept(sock, (struct sockaddr *) &data->client_sockaddr, &data->client_sockaddr_size);
-
+        data->database = database;
         pthread_t thread_id;
         pthread_attr_t attr;
         pthread_attr_init(&attr);
@@ -268,40 +308,96 @@ void process_server() {
     }
 }
 
-int create_socket() {
-    printf("Creating socket\n");
-    int sock = socket(PF_INET, SOCK_STREAM, 0);
+int
+check_user_authorisation(m_string client_ip, dbElem *database, m_string login, m_string password, dbElem **element) {
+    *element = getDbElementByAssignedIP(client_ip, database);
+    if (*element != NULL) {
+        return 1;
+    } else {
+        if (!login || !password)
+            return -1;
+        *element = getDbElementByUserName(login, database);
+        if (*element == NULL)
+            return 0;
 
-    int on = 1;
-    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+        if (strcmp((*element)->password, password) != 0)
+            return -1;
 
-    /* initialize the server's sockaddr */
-    struct sockaddr_in server_sockaddr;
-    memset(&server_sockaddr, 0, sizeof(server_sockaddr));
-    server_sockaddr.sin_family = AF_INET;
-    server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
-    server_sockaddr.sin_port = htons(SERVER_PORT);
+        strcpy((*element)->bound_ip, login);
+    }
+    return 1;
+}
 
-    printf("Binding socket %d to sockaddr %p with size %d\n", sock, (struct sockaddr *)&server_sockaddr, sizeof(server_sockaddr));
-    int bind_result = bind(sock, (struct sockaddr *)&server_sockaddr, sizeof(server_sockaddr));
-    if (bind_result < 0) {
-        fprintf(stderr, "Server: Error: bind failed!");
-        return -1;
+int getLoginAndPasswordFromRequest(m_string request, m_string*login_ptr, m_string*password_ptr) {
+    *login_ptr = *password_ptr = NULL;
+
+    char *auth_ptr = strstr(request, "Authorization: Basic ");
+
+    if (auth_ptr == NULL) {
+        return 0;
     }
 
-    listen(sock, MAX_CONNECTIONS);
+    char *login_data = auth_ptr + strlen("Authorization: Basic ");
+    size_t decoded_login_and_pass_len = 0;
 
-    return sock;
+    char *data_end = strchr(login_data, '\n');
+    if (data_end == NULL) {
+        return 0;
+    }
+
+    char *login_and_password = base64_decode(login_data, data_end - login_data,
+                                             &decoded_login_and_pass_len);
+
+    if (!login_and_password)
+        return 0;
+
+    char *login = malloc(65);
+    memset(login, 0, 65);
+    char *password = malloc(65);
+    memset(password, 0, 65);
+
+    char *delimiter = strchr(login_and_password, ':');
+    if (delimiter == NULL) {
+        free(login_and_password);
+        return 0;
+    }
+
+    if (delimiter - login_and_password > 64) {
+        free(login_and_password);
+        return -1; // login is too long!
+    }
+
+    if (decoded_login_and_pass_len - (delimiter + 1 - login_and_password) > 64) {
+        free(login_and_password);
+        return -2; // password is too long!
+    }
+
+    memcpy(login, login_and_password, delimiter - login_and_password);
+    memcpy(password, delimiter + 1, decoded_login_and_pass_len);
+
+    printf("USER LOGIN: %s, PASSWORD: %s\n", login, password);
+    *login_ptr = login;
+    *password_ptr = password;
+    return 1; // SUCCESS
 }
 
-void* handle_request(void* data) {
+int update_user_message(dbElem *user_data, m_string msg, int len) {
+    if (!msg || strlen(msg) == 0)
+        return 0;
+
+    if (strlen(msg) > 2048)
+        return -1;
+    memset(user_data->message, 0, 2049);
+    memcpy(user_data->message, msg, len);
+}
 
-    clientData* client_data = data;
+void *handle_request(void *data) {
+    clientData *client_data = data;
 
-    char ip[INET_ADDRSTRLEN];
+    char ip[17];
     inet_ntop(AF_INET, get_client_addr((struct sockaddr *) &client_data->client_sockaddr), ip, sizeof(ip));
 
-    printf("Worker %d: Established connection with %s beginning work.\n", pthread_self(), ip);
+    printf("Worker %u: Established connection with %s beginning work.\n", pthread_self(), ip);
 
     const int request_buffer_size = 65536;
     char request[request_buffer_size];
@@ -316,19 +412,93 @@ void* handle_request(void* data) {
 
     printf("request:\n%s\n", request);
 
+
+    char *login, *password;
+    int result = getLoginAndPasswordFromRequest(request, &login, &password);
+    printf("Worker: received login = %s; password = %s\n", login, password);
+    if (result == -1 || result == -2) {
+        send_200_message(client_data->sockd, "<h1>Некорректно введены данные пользователя!<br>"
+                                             "Максимальная длина логина и пароля - 64 символа!");
+
+        close(client_data->sockd);
+        return NULL;
+    }
+
+    dbElem *element = NULL;
+    result = check_user_authorisation(ip, client_data->database, login, password, &element);
+
+    // This result means that there's record with such login, but password is incorrect
+    if (result == -1) {
+        printf("DEBUG: USER AUTH RETURNED -1\n");
+        send_401_not_authorised(client_data->sockd);
+        close(client_data->sockd);
+        return NULL;
+    }
+
+    // This result means that there's no element in database with such credentials - so creating new one.
+    if (result == 0) {
+        if (!login || !password) {
+            printf("DEBUG: USER AUTH RETURNED 0, but NO LOGIN OR PASSWORD\n");
+            send_401_not_authorised(client_data->sockd);
+            close(client_data->sockd);
+            return NULL;
+        }
+        element = createNewElement(client_data->database);
+
+        if (!element) {
+            printf("Worker: Warning! Database is full, cannot create more users!\n");
+            send_401_not_authorised(client_data->sockd);
+            close(client_data->sockd);
+            return NULL;
+        }
+
+        printf("Beginning creating element for new user %s with pass %s\n", login, password);
+        strcpy(element->bound_ip, ip);
+        strcpy(element->login, login);
+        strcpy(element->password, password);
+        strcpy(element->message, "Hello, ");
+        strcat(element->message, login);
+        printf("Created element for user %s with password %s and msg %s\n", element->login, element->password, element->message);
+    }
+
+    if (!element) {
+        printf("DEBUG: NO ELEMENT!!!!\n");
+        send_401_not_authorised(client_data->sockd);
+        close(client_data->sockd);
+        return NULL;
+    }
+
+    // Now assuming, that user is successfully logged in and has valid element
+
     sHTTPHeader req;
     parse_http_request(request, &req);
 
     if (req.type == eHTTP_GET) {
-        send_message(client_data->sockd, "Hello! GET received...");
-    } else if (req.type == eHTTP_POST) {
-        send_message(client_data->sockd, "Hello! POST received...");
+        if (strstr(req.path, "/logout/") == req.path || strstr(req.path, "/logout") == req.path) {
+            memset(element->bound_ip, 0, 17);
+            send_200_message(client_data->sockd, "Successfully logged out");
+            close(client_data->sockd);
+            return NULL;
+        }
+        if (strstr(req.path, "/updatemsg/") == req.path) {
+            char *msg_begin = req.path + strlen("/updatemsg/");
+            char *msg_end = strchr(msg_begin, '/');
+            int msg_len = strlen(msg_begin);
+
+            if (msg_end)
+                msg_len = (int) (msg_end - msg_begin);
+
+            printf("MESSAGE (len = %d): %s", msg_len, msg_begin);
+            update_user_message(element, msg_begin, msg_len);
+        }
+
+        send_200_message(client_data->sockd, element->message);
     } else {
         send_404_not_found(client_data->sockd);
     }
 
     close(client_data->sockd);
-    printf("Worker %d: Finished.\n", pthread_self());
+    printf("Worker %u: Finished.\n", pthread_self());
     return NULL;
 }
 
@@ -356,32 +526,30 @@ void parse_http_request(const char *apstrRequest, sHTTPHeader *apHeader) {
     }
 }
 
-void send_message(int aSock, const char *apstrMessage) {
+void send_200_message(int sockd, m_string message) {
     char buffer[65536] = {0};
-
     strcat(buffer, "HTTP/1.1 200 OK\n\n");
-    strcat(buffer, "<h1>");
-    strcat(buffer, apstrMessage);
-    strcat(buffer, "</h1>");
+    strcat(buffer, "<html><body><h1>");
+    strcat(buffer, message);
+    strcat(buffer, "</h1></body></html>");
+    int len = strlen(buffer);
+    send(sockd, buffer, len, 0);
+}
 
+void send_403_forbidden(int sockd) {
+    const char *buffer = "HTTP/1.1 403 \n\n<h1>Forbidden!<br>Seems like you tried to access data without permission :/</h1>";
     int len = strlen(buffer);
-    send(aSock, buffer, len, 0);
+    send(sockd, buffer, len, 0);
 }
 
 void send_404_not_found(int sockd) {
-    const char *buffer = "HTTP/1.1 404 \n\n";
+    const char *buffer = "HTTP/1.1 404 \n\n<h1>Sorry, nothing was found on your request :(</h1>";
     int len = strlen(buffer);
     send(sockd, buffer, len, 0);
 }
 
-
-// server: got connection from 127.0.0.1
-// request:
-// GET /index.html HTTP/1.1
-// Host: localhost:3490
-// Connection: keep-alive
-// Upgrade-Insecure-Requests: 1
-// User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/68.0.3440.75 Chrome/68.0.3440.75 Safari/537.36
-// Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
-// Accept-Encoding: gzip, deflate, br
-// Accept-Language: en-US,en;q=0.9,ru;q=0.8
+void send_401_not_authorised(int sockd) {
+    const char *buffer = "HTTP/1.1 401\nWWW-Authenticate: Basic realm=0JTQsNGA0L7QstCwLCDQsdC+0LXRhiEg0JfQsNC70L7Qs9C40L3RjNGB0Y8sINGH0YLQvtCx0Ysg0YPQstC40LTQtdGC0Ywg0YHQvtC+0LHRidC10L3QuNC1\n\n";
+    int len = strlen(buffer);
+    send(sockd, buffer, len, 0);
+}

+ 539 - 0
os.h

@@ -0,0 +1,539 @@
+/*
+ * OS specific functions
+ * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef OS_H
+#define OS_H
+
+typedef long os_time_t;
+
+/**
+ * os_sleep - Sleep (sec, usec)
+ * @sec: Number of seconds to sleep
+ * @usec: Number of microseconds to sleep
+ */
+void os_sleep(os_time_t sec, os_time_t usec);
+
+struct os_time {
+	os_time_t sec;
+	os_time_t usec;
+};
+
+/**
+ * os_get_time - Get current time (sec, usec)
+ * @t: Pointer to buffer for the time
+ * Returns: 0 on success, -1 on failure
+ */
+int os_get_time(struct os_time *t);
+
+
+/* Helper macros for handling struct os_time */
+
+#define os_time_before(a, b) \
+	((a)->sec < (b)->sec || \
+	 ((a)->sec == (b)->sec && (a)->usec < (b)->usec))
+
+#define os_time_sub(a, b, res) do { \
+	(res)->sec = (a)->sec - (b)->sec; \
+	(res)->usec = (a)->usec - (b)->usec; \
+	if ((res)->usec < 0) { \
+		(res)->sec--; \
+		(res)->usec += 1000000; \
+	} \
+} while (0)
+
+/**
+ * os_mktime - Convert broken-down time into seconds since 1970-01-01
+ * @year: Four digit year
+ * @month: Month (1 .. 12)
+ * @day: Day of month (1 .. 31)
+ * @hour: Hour (0 .. 23)
+ * @min: Minute (0 .. 59)
+ * @sec: Second (0 .. 60)
+ * @t: Buffer for returning calendar time representation (seconds since
+ * 1970-01-01 00:00:00)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Note: The result is in seconds from Epoch, i.e., in UTC, not in local time
+ * which is used by POSIX mktime().
+ */
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+	      os_time_t *t);
+
+struct os_tm {
+	int sec; /* 0..59 or 60 for leap seconds */
+	int min; /* 0..59 */
+	int hour; /* 0..23 */
+	int day; /* 1..31 */
+	int month; /* 1..12 */
+	int year; /* Four digit year */
+};
+
+int os_gmtime(os_time_t t, struct os_tm *tm);
+
+/**
+ * os_daemonize - Run in the background (detach from the controlling terminal)
+ * @pid_file: File name to write the process ID to or %NULL to skip this
+ * Returns: 0 on success, -1 on failure
+ */
+int os_daemonize(const char *pid_file);
+
+/**
+ * os_daemonize_terminate - Stop running in the background (remove pid file)
+ * @pid_file: File name to write the process ID to or %NULL to skip this
+ */
+void os_daemonize_terminate(const char *pid_file);
+
+/**
+ * os_get_random - Get cryptographically strong pseudo random data
+ * @buf: Buffer for pseudo random data
+ * @len: Length of the buffer
+ * Returns: 0 on success, -1 on failure
+ */
+int os_get_random(unsigned char *buf, size_t len);
+
+/**
+ * os_random - Get pseudo random value (not necessarily very strong)
+ * Returns: Pseudo random value
+ */
+unsigned long os_random(void);
+
+/**
+ * os_rel2abs_path - Get an absolute path for a file
+ * @rel_path: Relative path to a file
+ * Returns: Absolute path for the file or %NULL on failure
+ *
+ * This function tries to convert a relative path of a file to an absolute path
+ * in order for the file to be found even if current working directory has
+ * changed. The returned value is allocated and caller is responsible for
+ * freeing it. It is acceptable to just return the same path in an allocated
+ * buffer, e.g., return strdup(rel_path). This function is only used to find
+ * configuration files when os_daemonize() may have changed the current working
+ * directory and relative path would be pointing to a different location.
+ */
+char * os_rel2abs_path(const char *rel_path);
+
+/**
+ * os_program_init - Program initialization (called at start)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called when a programs starts. If there are any OS specific
+ * processing that is needed, it can be placed here. It is also acceptable to
+ * just return 0 if not special processing is needed.
+ */
+int os_program_init(void);
+
+/**
+ * os_program_deinit - Program deinitialization (called just before exit)
+ *
+ * This function is called just before a program exists. If there are any OS
+ * specific processing, e.g., freeing resourced allocated in os_program_init(),
+ * it should be done here. It is also acceptable for this function to do
+ * nothing.
+ */
+void os_program_deinit(void);
+
+/**
+ * os_setenv - Set environment variable
+ * @name: Name of the variable
+ * @value: Value to set to the variable
+ * @overwrite: Whether existing variable should be overwritten
+ * Returns: 0 on success, -1 on error
+ *
+ * This function is only used for wpa_cli action scripts. OS wrapper does not
+ * need to implement this if such functionality is not needed.
+ */
+int os_setenv(const char *name, const char *value, int overwrite);
+
+/**
+ * os_unsetenv - Delete environent variable
+ * @name: Name of the variable
+ * Returns: 0 on success, -1 on error
+ *
+ * This function is only used for wpa_cli action scripts. OS wrapper does not
+ * need to implement this if such functionality is not needed.
+ */
+int os_unsetenv(const char *name);
+
+/**
+ * os_readfile - Read a file to an allocated memory buffer
+ * @name: Name of the file to read
+ * @len: For returning the length of the allocated buffer
+ * Returns: Pointer to the allocated buffer or %NULL on failure
+ *
+ * This function allocates memory and reads the given file to this buffer. Both
+ * binary and text files can be read with this function. The caller is
+ * responsible for freeing the returned buffer with os_free().
+ */
+char * os_readfile(const char *name, size_t *len);
+
+/**
+ * os_zalloc - Allocate and zero memory
+ * @size: Number of bytes to allocate
+ * Returns: Pointer to allocated and zeroed memory or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+void * os_zalloc(size_t size);
+
+/**
+ * os_calloc - Allocate and zero memory for an array
+ * @nmemb: Number of members in the array
+ * @size: Number of bytes in each member
+ * Returns: Pointer to allocated and zeroed memory or %NULL on failure
+ *
+ * This function can be used as a wrapper for os_zalloc(nmemb * size) when an
+ * allocation is used for an array. The main benefit over os_zalloc() is in
+ * having an extra check to catch integer overflows in multiplication.
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+static inline void * os_calloc(size_t nmemb, size_t size)
+{
+	if (size && nmemb > (~(size_t) 0) / size)
+		return NULL;
+	return os_zalloc(nmemb * size);
+}
+
+
+/*
+ * The following functions are wrapper for standard ANSI C or POSIX functions.
+ * By default, they are just defined to use the standard function name and no
+ * os_*.c implementation is needed for them. This avoids extra function calls
+ * by allowing the C pre-processor take care of the function name mapping.
+ *
+ * If the target system uses a C library that does not provide these functions,
+ * build_config.h can be used to define the wrappers to use a different
+ * function name. This can be done on function-by-function basis since the
+ * defines here are only used if build_config.h does not define the os_* name.
+ * If needed, os_*.c file can be used to implement the functions that are not
+ * included in the C library on the target system. Alternatively,
+ * OS_NO_C_LIB_DEFINES can be defined to skip all defines here in which case
+ * these functions need to be implemented in os_*.c file for the target system.
+ */
+
+#ifdef OS_NO_C_LIB_DEFINES
+
+/**
+ * os_malloc - Allocate dynamic memory
+ * @size: Size of the buffer to allocate
+ * Returns: Allocated buffer or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+void * os_malloc(size_t size);
+
+/**
+ * os_realloc - Re-allocate dynamic memory
+ * @ptr: Old buffer from os_malloc() or os_realloc()
+ * @size: Size of the new buffer
+ * Returns: Allocated buffer or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ * If re-allocation fails, %NULL is returned and the original buffer (ptr) is
+ * not freed and caller is still responsible for freeing it.
+ */
+void * os_realloc(void *ptr, size_t size);
+
+/**
+ * os_free - Free dynamic memory
+ * @ptr: Old buffer from os_malloc() or os_realloc(); can be %NULL
+ */
+void os_free(void *ptr);
+
+/**
+ * os_memcpy - Copy memory area
+ * @dest: Destination
+ * @src: Source
+ * @n: Number of bytes to copy
+ * Returns: dest
+ *
+ * The memory areas src and dst must not overlap. os_memmove() can be used with
+ * overlapping memory.
+ */
+void * os_memcpy(void *dest, const void *src, size_t n);
+
+/**
+ * os_memmove - Copy memory area
+ * @dest: Destination
+ * @src: Source
+ * @n: Number of bytes to copy
+ * Returns: dest
+ *
+ * The memory areas src and dst may overlap.
+ */
+void * os_memmove(void *dest, const void *src, size_t n);
+
+/**
+ * os_memset - Fill memory with a constant byte
+ * @s: Memory area to be filled
+ * @c: Constant byte
+ * @n: Number of bytes started from s to fill with c
+ * Returns: s
+ */
+void * os_memset(void *s, int c, size_t n);
+
+/**
+ * os_memcmp - Compare memory areas
+ * @s1: First buffer
+ * @s2: Second buffer
+ * @n: Maximum numbers of octets to compare
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greater than s2. Only first n
+ * characters will be compared.
+ */
+int os_memcmp(const void *s1, const void *s2, size_t n);
+
+/**
+ * os_strdup - Duplicate a string
+ * @s: Source string
+ * Returns: Allocated buffer with the string copied into it or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+char * os_strdup(const char *s);
+
+/**
+ * os_strlen - Calculate the length of a string
+ * @s: '\0' terminated string
+ * Returns: Number of characters in s (not counting the '\0' terminator)
+ */
+size_t os_strlen(const char *s);
+
+/**
+ * os_strcasecmp - Compare two strings ignoring case
+ * @s1: First string
+ * @s2: Second string
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greatred than s2
+ */
+int os_strcasecmp(const char *s1, const char *s2);
+
+/**
+ * os_strncasecmp - Compare two strings ignoring case
+ * @s1: First string
+ * @s2: Second string
+ * @n: Maximum numbers of characters to compare
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greater than s2. Only first n
+ * characters will be compared.
+ */
+int os_strncasecmp(const char *s1, const char *s2, size_t n);
+
+/**
+ * os_strchr - Locate the first occurrence of a character in string
+ * @s: String
+ * @c: Character to search for
+ * Returns: Pointer to the matched character or %NULL if not found
+ */
+char * os_strchr(const char *s, int c);
+
+/**
+ * os_strrchr - Locate the last occurrence of a character in string
+ * @s: String
+ * @c: Character to search for
+ * Returns: Pointer to the matched character or %NULL if not found
+ */
+char * os_strrchr(const char *s, int c);
+
+/**
+ * os_strcmp - Compare two strings
+ * @s1: First string
+ * @s2: Second string
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greatred than s2
+ */
+int os_strcmp(const char *s1, const char *s2);
+
+/**
+ * os_strncmp - Compare two strings
+ * @s1: First string
+ * @s2: Second string
+ * @n: Maximum numbers of characters to compare
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greater than s2. Only first n
+ * characters will be compared.
+ */
+int os_strncmp(const char *s1, const char *s2, size_t n);
+
+/**
+ * os_strncpy - Copy a string
+ * @dest: Destination
+ * @src: Source
+ * @n: Maximum number of characters to copy
+ * Returns: dest
+ */
+char * os_strncpy(char *dest, const char *src, size_t n);
+
+/**
+ * os_strstr - Locate a substring
+ * @haystack: String (haystack) to search from
+ * @needle: Needle to search from haystack
+ * Returns: Pointer to the beginning of the substring or %NULL if not found
+ */
+char * os_strstr(const char *haystack, const char *needle);
+
+/**
+ * os_snprintf - Print to a memory buffer
+ * @str: Memory buffer to print into
+ * @size: Maximum length of the str buffer
+ * @format: printf format
+ * Returns: Number of characters printed (not including trailing '\0').
+ *
+ * If the output buffer is truncated, number of characters which would have
+ * been written is returned. Since some C libraries return -1 in such a case,
+ * the caller must be prepared on that value, too, to indicate truncation.
+ *
+ * Note: Some C library implementations of snprintf() may not guarantee null
+ * termination in case the output is truncated. The OS wrapper function of
+ * os_snprintf() should provide this guarantee, i.e., to null terminate the
+ * output buffer if a C library version of the function is used and if that
+ * function does not guarantee null termination.
+ *
+ * If the target system does not include snprintf(), see, e.g.,
+ * http://www.ijs.si/software/snprintf/ for an example of a portable
+ * implementation of snprintf.
+ */
+int os_snprintf(char *str, size_t size, const char *format, ...);
+
+#else /* OS_NO_C_LIB_DEFINES */
+
+#ifdef WPA_TRACE
+void * os_malloc(size_t size);
+void * os_realloc(void *ptr, size_t size);
+void os_free(void *ptr);
+char * os_strdup(const char *s);
+#else /* WPA_TRACE */
+#ifndef os_malloc
+#define os_malloc(s) malloc((s))
+#endif
+#ifndef os_realloc
+#define os_realloc(p, s) realloc((p), (s))
+#endif
+#ifndef os_free
+#define os_free(p) free((p))
+#endif
+#ifndef os_strdup
+#ifdef _MSC_VER
+#define os_strdup(s) _strdup(s)
+#else
+#define os_strdup(s) strdup(s)
+#endif
+#endif
+#endif /* WPA_TRACE */
+
+#ifndef os_memcpy
+#define os_memcpy(d, s, n) memcpy((d), (s), (n))
+#endif
+#ifndef os_memmove
+#define os_memmove(d, s, n) memmove((d), (s), (n))
+#endif
+#ifndef os_memset
+#define os_memset(s, c, n) memset(s, c, n)
+#endif
+#ifndef os_memcmp
+#define os_memcmp(s1, s2, n) memcmp((s1), (s2), (n))
+#endif
+
+#ifndef os_strlen
+#define os_strlen(s) strlen(s)
+#endif
+#ifndef os_strcasecmp
+#ifdef _MSC_VER
+#define os_strcasecmp(s1, s2) _stricmp((s1), (s2))
+#else
+#define os_strcasecmp(s1, s2) strcasecmp((s1), (s2))
+#endif
+#endif
+#ifndef os_strncasecmp
+#ifdef _MSC_VER
+#define os_strncasecmp(s1, s2, n) _strnicmp((s1), (s2), (n))
+#else
+#define os_strncasecmp(s1, s2, n) strncasecmp((s1), (s2), (n))
+#endif
+#endif
+#ifndef os_strchr
+#define os_strchr(s, c) strchr((s), (c))
+#endif
+#ifndef os_strcmp
+#define os_strcmp(s1, s2) strcmp((s1), (s2))
+#endif
+#ifndef os_strncmp
+#define os_strncmp(s1, s2, n) strncmp((s1), (s2), (n))
+#endif
+#ifndef os_strncpy
+#define os_strncpy(d, s, n) strncpy((d), (s), (n))
+#endif
+#ifndef os_strrchr
+#define os_strrchr(s, c) strrchr((s), (c))
+#endif
+#ifndef os_strstr
+#define os_strstr(h, n) strstr((h), (n))
+#endif
+
+#ifndef os_snprintf
+#ifdef _MSC_VER
+#define os_snprintf _snprintf
+#else
+#define os_snprintf snprintf
+#endif
+#endif
+
+#endif /* OS_NO_C_LIB_DEFINES */
+
+
+static inline void * os_realloc_array(void *ptr, size_t nmemb, size_t size)
+{
+	if (size && nmemb > (~(size_t) 0) / size)
+		return NULL;
+	return os_realloc(ptr, nmemb * size);
+}
+
+
+/**
+ * os_strlcpy - Copy a string with size bound and NUL-termination
+ * @dest: Destination
+ * @src: Source
+ * @siz: Size of the target buffer
+ * Returns: Total length of the target string (length of src) (not including
+ * NUL-termination)
+ *
+ * This function matches in behavior with the strlcpy(3) function in OpenBSD.
+ */
+size_t os_strlcpy(char *dest, const char *src, size_t siz);
+
+
+#ifdef OS_REJECT_C_LIB_FUNCTIONS
+#define malloc OS_DO_NOT_USE_malloc
+#define realloc OS_DO_NOT_USE_realloc
+#define free OS_DO_NOT_USE_free
+#define memcpy OS_DO_NOT_USE_memcpy
+#define memmove OS_DO_NOT_USE_memmove
+#define memset OS_DO_NOT_USE_memset
+#define memcmp OS_DO_NOT_USE_memcmp
+#undef strdup
+#define strdup OS_DO_NOT_USE_strdup
+#define strlen OS_DO_NOT_USE_strlen
+#define strcasecmp OS_DO_NOT_USE_strcasecmp
+#define strncasecmp OS_DO_NOT_USE_strncasecmp
+#undef strchr
+#define strchr OS_DO_NOT_USE_strchr
+#undef strcmp
+#define strcmp OS_DO_NOT_USE_strcmp
+#undef strncmp
+#define strncmp OS_DO_NOT_USE_strncmp
+#undef strncpy
+#define strncpy OS_DO_NOT_USE_strncpy
+#define strrchr OS_DO_NOT_USE_strrchr
+#define strstr OS_DO_NOT_USE_strstr
+#undef snprintf
+#define snprintf OS_DO_NOT_USE_snprintf
+
+#define strcpy OS_DO_NOT_USE_strcpy
+#endif /* OS_REJECT_C_LIB_FUNCTIONS */
+
+#endif /* OS_H */