Author: biurrun Date: Thu Nov 26 18:16:32 2009 New Revision: 1836 Log: Move handle_packet_password / handle_packet_pwd_request (and dependencies) to the only place they are used and mark them as static. Deleted: trunk/pairing/packet_handler_accept.c trunk/pairing/packet_handler_accept.h Modified: trunk/Makefile.am trunk/pairing/packet_handler.c Modified: trunk/Makefile.am ============================================================================== --- trunk/Makefile.am Thu Nov 26 18:03:17 2009 (r1835) +++ trunk/Makefile.am Thu Nov 26 18:16:32 2009 (r1836) @@ -80,8 +80,7 @@ pairing/packet_handler.c pairing_accept_SOURCES = $(pairing_ACCEPT_SEND_SRCS) \ - pairing/accept.c \ - pairing/packet_handler_accept.c + pairing/accept.c pairing_send_SOURCES = $(pairing_ACCEPT_SEND_SRCS) \ pairing/send.c Modified: trunk/pairing/packet_handler.c ============================================================================== --- trunk/pairing/packet_handler.c Thu Nov 26 18:03:17 2009 (r1835) +++ trunk/pairing/packet_handler.c Thu Nov 26 18:16:32 2009 (r1836) @@ -11,13 +11,466 @@ */ #include <libconfig.h> +#include <openssl/sha.h> #include <stdio.h> #include <string.h> #include <netinet/in.h> +#include "libpisa/hitlist.h" #include "common.h" +#include "common_headers.h" +#include "libconfig_wrapper.h" #include "packet_handler.h" +/** Default password file is set statically. **/ +#define FILE_PWD "sha.txt" + +#define ERROR_INVALID_PWD 0 +#define ERROR_NOT_CONNECTED 1 + + +/** Creates an error structure and fills it with the information given. + * + * @param error_type Error type (use macros ERROR_*) + * @param error_string Pointer to string containing an error message. + * + * @return A pointer to the header_general structure. Returns NULL on error. + */ +static header_general* create_error_struct(int error_type, + const char *error_string) +{ + if (error_string == NULL) + { + DEBUG("No error string given. Error structure was not created."); + return NULL; + } + + header_general *gen_hdr = malloc(sizeof(header_general)); + gen_hdr->msg_type = MSG_ERROR; + gen_hdr->msg.header_error.error_type = error_type; + strncpy((char*)&((gen_hdr->msg.header_error).error_string), error_string, LENGTH_ERROR_STRING); + + DEBUG_HIGH(LINE_BREAK); + DEBUG_HIGH("General header created."); + DEBUG_HIGH("\tMessage type: %d", gen_hdr->msg_type); + DEBUG_HIGH("Error structure created:"); + DEBUG_HIGH("\tError type: %d", gen_hdr->msg.header_error.error_type); + DEBUG_HIGH("\tError string: %s", (gen_hdr->msg.header_error).error_string); + DEBUG_HIGH(LINE_BREAK); + + return gen_hdr; +} + + +/** Creates a header_general structure which holds a header_ack_1 structure and fills both. + * + * @return A pointer to the header_general structure. Returns NULL on error. + */ +static header_general* create_ack_1_struct(void) +{ + config_t cfg; + const char *nickname, *ipv4_addr, *ipv6_addr; + int success; + + header_general *gen_hdr = malloc(sizeof(header_general)); + gen_hdr->msg_type = MSG_ACK_1; + + // Read config file + config_init(&cfg); + if (!config_read_file(&cfg, FILE_SERVER_CONFIG)) + { + DEBUG("Error reading %s on line %d: %s\n", FILE_SERVER_CONFIG, cfg.error_line, cfg.error_text); + return NULL; + } + + DEBUG_HIGH(LINE_BREAK); + DEBUG_HIGH("General header created."); + DEBUG_HIGH("\tMessage type: %d", gen_hdr->msg_type); + DEBUG_HIGH("ack_1 structure created:"); + + + // Look up nickname + success = config_lookup_string(&cfg, "server_settings.nickname", &nickname); + if (success != CONFIG_TRUE || !nickname) + { // If the setting doesn't exist, set the string to be empty + *((gen_hdr->msg.header_ack_1).nickname) = 0; + DEBUG_HIGH("\nNickname not found."); + } + else // ... write the contents into the structure + strncpy((char*)&((gen_hdr->msg.header_ack_1).nickname), nickname, LENGTH_NICKNAME); + DEBUG_HIGH("\tNickname: \'%s\'", ((gen_hdr->msg.header_ack_1).nickname)); + + + // Look up the IPv4 address + success = config_lookup_string(&cfg, "server_settings.ipv4_addr", &ipv4_addr); + if (success != CONFIG_TRUE || !ipv4_addr) + { // If the setting doesn't exist, set the string to be empty + *((gen_hdr->msg.header_ack_1).ipv4_addr) = 0; + DEBUG_HIGH("\tIPv4 address not found!"); + } + else // ... write the contents into the structure + strncpy((char*)&((gen_hdr->msg.header_ack_1).ipv4_addr), ipv4_addr, INET_ADDRSTRLEN+1); + DEBUG_HIGH("\tIPv4 address: \'%s\'", (gen_hdr->msg.header_ack_1).ipv4_addr); + + + // Look up the IPv6 address + success = config_lookup_string(&cfg, "server_settings.ipv6_addr", &ipv6_addr); + if (success != CONFIG_TRUE || !ipv6_addr) + { // If the setting doesn't exist, set the string to be empty + *((gen_hdr->msg.header_ack_1).ipv6_addr) = 0; + DEBUG_HIGH("\tIPv6 address not found!"); + } + else // ... write the contents into the structure + strncpy((char*)&((gen_hdr->msg.header_ack_1).ipv6_addr), ipv6_addr, INET6_ADDRSTRLEN+1); + DEBUG_HIGH("\tIPv6 address: \'%s\'", (gen_hdr->msg.header_ack_1).ipv6_addr); + + config_destroy(&cfg); + + DEBUG_HIGH(LINE_BREAK); + + return gen_hdr; +} + + +/** Creates a header_general structure which holds a header_ack_2 structure and fills both. + * + * @return A pointer to the header_general structure. Returns NULL on error. + */ +static header_general* create_ack_2_struct(char *password) +{ + assert(password != NULL); + + header_general *gen_hdr = malloc(sizeof(header_general)); + gen_hdr->msg_type = MSG_ACK_2; + + strncpy((char*)&((gen_hdr->msg.header_ack_2).password), password, LENGTH_PASSWORD); + + DEBUG_HIGH(LINE_BREAK); + DEBUG_HIGH("General header created."); + DEBUG_HIGH("\tMessage type: %d", gen_hdr->msg_type); + DEBUG_HIGH("Password structure created:"); + DEBUG_HIGH("\tPassword: \'%s\'", (gen_hdr->msg.header_ack_2).password); + DEBUG_HIGH(LINE_BREAK); + + return gen_hdr; +} + + +/** This function authenticates the password. + * + * @todo Read from config file instead of sha.txt? + * + * @param password A pointer to string containing the received password. + * @return 1 if the password matches, 0 if the password does not match + */ +static int check_password(char *password) +{ + FILE *file; + char file_contents[2*SHA_DIGEST_LENGTH+1]; + int result; + char pwd_hash_hex[2*SHA_DIGEST_LENGTH+1]; + + assert(password != NULL); + DEBUG_MED("Checking password: %s", password); + + // Open file + if ((file = fopen(FILE_PWD, "r")) == NULL) + { + DEBUG("Cannot open password file.\n"); + return 0; + } + + // Read line + if (!fgets(file_contents, 2*SHA_DIGEST_LENGTH+1, file)) + return 0; + file_contents[2*SHA_DIGEST_LENGTH] = 0; // Null-terminate the line + DEBUG_MED("File contents:\t\'%s\'", file_contents); + + get_sha(password, pwd_hash_hex); // Get the SHA1 hash of /password/ + DEBUG_MED("Hash is:\t\t\'%s\'", pwd_hash_hex); + result = strcmp(pwd_hash_hex, file_contents); // Compare the password with the file contents + + // Close file + if (fclose(file)) + DEBUG("File close error.\n"); + + return (result == 0) ? 1 : 0 ; + +} + + +/** This function handles a password packet sent from the user to the relay. + * + * @param socket_addr Pointer to sockaddr_in6 structure connected to peer. + * @param hdr_pwd Pointer to the header_password structure to be handled. + * + * @return The result of the password authentication. + */ +static int handle_packet_password(struct sockaddr_in6 *socket_addr, + header_password *hdr_pwd) +{ + int pwd_valid; + header_general *gen_hdr; + DEBUG_HIGH("Handling a password packet..."); + + assert(socket_addr != NULL); + assert(hdr_pwd != NULL); + + pwd_valid = check_password((char*)&(hdr_pwd->password)); + + if (pwd_valid) + { + DEBUG_HIGH("Valid password."); + // Create ack_1 packet + gen_hdr = create_ack_1_struct(); + } + else // Transmit an error message + { + DEBUG_HIGH("Invalid password."); + gen_hdr = create_error_struct(ERROR_INVALID_PWD, "Invalid password. Please try again."); + } + + CHECK_FOR_NULL_HDR(gen_hdr); + + // Transmit message + SENDTO(global_accept.socket_desc, socket_addr, gen_hdr); + + free(gen_hdr); + + if (pwd_valid) + DEBUG_MED("ACK 1 message sent successfully."); + else + DEBUG_MED("Error message sent successfully."); + + if (pwd_valid) + { // Write the user down in our database + char hit[INET6_ADDRSTRLEN]; + char buf_expiration[LENGTH_TIMEOUT]; + if(!get_default_expiration(buf_expiration)) + { + return 0; + } + + inet_ntop(AF_INET6, &socket_addr->sin6_addr, hit, sizeof(hit)); + write_config(hit, buf_expiration, CONFIG_TYPE_HIT); + } + + return 1; +} + + +/* Stolen from http://en.wikipedia.org/wiki/Itoa */ +/** Convert an integer to a string + * + * @param n Original integer + * @param s String to hold result +*/ +static void itoa(int n, char s[]) +{ + int i, sign; + + if ((sign = n) < 0) /* record sign */ + n = -n; /* make n positive */ + i = 0; + do + { /* generate digits in reverse order */ + s[i++] = n % 10 + '0'; /* get next digit */ + } while ((n /= 10) > 0); /* delete it */ + + if (sign < 0) + s[i++] = '-'; + + s[i] = '\0'; + +// reverse(s); // Orignal; inserted code below + + { + int c, j; + for (i = 0, j = strlen(s)-1; i<j; i++, j--) + { + c = s[i]; + s[i] = s[j]; + s[j] = c; + } + } + +} + + +/** Creates a new password with the associated information and writes it all + * in FILE_AUTHORIZED_HOSTS. + * + * @param nickname Pointer to the nickname for this relay. Leave blank (not null) to autogenerate one. + * @param expr1 Long int representing the length of time for which the password is valid in seconds. + * @param expr2 Long int representing the length of time for which access will be allowed in seconds. + * @param password Pointer to a string to contain the new (generated) password. + * + * @return 1 if everything goes well; 0 otherwise + */ +static int store_pwd(char *nickname, long int expr1, long int expr2, char *password) +{ + + assert(nickname != NULL); + assert(password != NULL); + + // Write down password + config_setting_t *allowed_passwords; + config_setting_t *new_pwd_grp, *new_nick, *new_pwd, *new_expire1, *new_expire2; + char expiration1[LENGTH_TIMEOUT], expiration2[LENGTH_TIMEOUT]; + + struct tm *ts; + time_t time_exp1, time_exp2; + + /** @todo Generate password rather than write statically. **/ + strcpy(password, "aachen2"); + + allowed_passwords = check_list("allowed_passwords"); + + time(&time_exp1); + time(&time_exp2); + + time_exp1 += expr1; + time_exp2 += expr2; + + ts = localtime(&time_exp1); + strftime(expiration1, sizeof(expiration1), EXPIRATION_DATE_FORMAT, ts); + ts = localtime(&time_exp2); + strftime(expiration2, sizeof(expiration2), EXPIRATION_DATE_FORMAT, ts); + + // Add a new group + new_pwd_grp = config_setting_add(allowed_passwords, NULL, CONFIG_TYPE_GROUP); + + // Add the nickname + new_nick = config_setting_add(new_pwd_grp, "nickname", CONFIG_TYPE_STRING); + if (strlen(nickname) == 0) + { + DEBUG_HIGH("Reading nickname from config file."); + + // Read config file + int unknown_user_count_int; + char unknown_user_count_string[5]; + + config_t cfg; + config_setting_t *root; + config_setting_t *unknown_user_count_setting; + config_init(&cfg); + + if (!config_read_file(&cfg, FILE_SERVER_CONFIG)) + { + DEBUG("Could not read file \'%s\'.", FILE_SERVER_CONFIG); + return 0; + } + + root = config_root_setting(&cfg); + unknown_user_count_setting = config_lookup(&cfg, "pwd_request_settings.unknown_user_count"); + if (!unknown_user_count_setting) + { + DEBUG("Error reading unknown user count setting from file %s.", FILE_SERVER_CONFIG); + return 0; + } + + // Build the default nickname + unknown_user_count_int = config_setting_get_int(unknown_user_count_setting); + strcpy(nickname, "unknown"); + itoa(unknown_user_count_int, unknown_user_count_string); + strcat(nickname, unknown_user_count_string); + + // Update the unknown user count + unknown_user_count_int++; + if (config_setting_set_int(unknown_user_count_setting, unknown_user_count_int) != CONFIG_TRUE) + { + DEBUG("Error setting unknown user count."); + return 0; + } + + config_setting_set_string(new_nick, nickname); + + if (config_write_file(&cfg, FILE_SERVER_CONFIG) == CONFIG_FALSE) + { + DEBUG("Error writing to file %s.", FILE_SERVER_CONFIG); + return 0; + } + config_destroy(&cfg); + } + else + config_setting_set_string(new_nick, nickname); + + // Add the password + new_pwd = config_setting_add(new_pwd_grp, "password", CONFIG_TYPE_STRING); + config_setting_set_string(new_pwd, password); + // Add the password expiration date + new_expire1 = config_setting_add(new_pwd_grp, "pwd_expires", CONFIG_TYPE_STRING); + config_setting_set_string(new_expire1, expiration1); + // Add the access expiration date + new_expire2 = config_setting_add(new_pwd_grp, "access_expires", CONFIG_TYPE_STRING); + config_setting_set_string(new_expire2, expiration2); + + DEBUG_HIGH("Password information written."); + DEBUG_HIGH("\tNickname: %s", nickname); + DEBUG_HIGH("\tPassword: %s", password); + DEBUG_HIGH("\tExpiration 1: %s", expiration1); + DEBUG_HIGH("\tExpiration 2: %s", expiration2); + + pisa_cfg_write_authorized_hosts_file(); + + + return 1; +} + + +/** Handles a password request packet. + * + * @param socket_addr Pointer to sockaddr_in6 structure connected to peer. + * @param hdr_pwd_request Pointer to the header_pwd_request structure. + * + * @return 1 if password generated; 0 otherwise + */ +static int handle_packet_pwd_request(struct sockaddr_in6 *socket_addr, + header_pwd_request *hdr_pwd_request) +{ + pisa_hitlist *allowed_hosts; + pisa_hitlist_entry *con; + + assert(socket_addr != NULL); + assert(hdr_pwd_request != NULL); + + header_general *gen_hdr; + char password[LENGTH_PASSWORD]; + + // Check if HIT is in allowed_hosts list + allowed_hosts = pisa_hitlist_build("allowed_hosts"); + con = pisa_hitlist_find(allowed_hosts,&socket_addr->sin6_addr); + + if(!con) + { + gen_hdr = create_error_struct(ERROR_NOT_CONNECTED, "Sorry, but that HIT is not authenticated on this relay."); + CHECK_FOR_NULL_HDR(gen_hdr); + + // Transmit message + SENDTO(global_accept.socket_desc, socket_addr, gen_hdr); + + free(gen_hdr); + + return 0; + } + + if (!store_pwd((char*)hdr_pwd_request->nickname, hdr_pwd_request->expiration1, hdr_pwd_request->expiration2, password)) + return 0; + + // Create password ack structure + gen_hdr = create_ack_2_struct(password); + CHECK_FOR_NULL_HDR(gen_hdr); + + // Send password ack structure + SENDTO(global_accept.socket_desc, socket_addr, gen_hdr); + + pisa_hitlist_destroy(allowed_hosts); + free(gen_hdr); + + + return 1; +} + /** Stores the contact information of a relay in FILE_KNOWN_RELAYS. * * @param nickname Pointer to the string containing the suggested nickname of the relay.