/* * libtestsuite.c - This program contains test cases for libcutlass * functionality. * * Copyright (c) 2005 Todd MacDermid */ #include #include #include #include #include #include #include #include #include #include "constants.h" struct action_stack { struct cut_action_obj *action_object; struct action_stack *next; }; pthread_mutex_t stack_mutex; struct action_stack *test_stack = NULL; uint8_t *remote_fingerprint; int check_message = 0; int check_file = 0; int passphrase_null(const char* description, char pass[], uint32_t max_size) { return(0); } int handle_action(cutlass_t *cut_handle, struct cut_action_obj *action_object) { struct cut_action_obj *action_copy; struct action_stack *new_node; struct action_stack *walk_node; action_copy = calloc(1, sizeof(struct cut_action_obj)); if(NULL == action_copy) { return(-1); } new_node = calloc(1, sizeof(struct action_stack)); if(NULL == new_node) { free(action_copy); return(-1); } new_node->action_object = action_copy; memcpy(action_copy, action_object, sizeof(struct cut_action_obj)); new_node->next = NULL; pthread_mutex_lock(&stack_mutex); walk_node = test_stack; if(walk_node == NULL) { test_stack = new_node; } else { while(walk_node->next != NULL) { walk_node = walk_node->next; } walk_node->next = new_node; } pthread_mutex_unlock(&stack_mutex); return(0); } int child_sysmsg_handler(cutlass_t *cut_handle, struct cut_action_obj *action_object) { char *msg; msg = cutlass_action_msg(action_object); if(NULL == msg) { fprintf(stderr, "Error getting mesage\n"); return(1); } printf(" %s", msg); free(msg); return(0); } int parent_sysmsg_handler(cutlass_t *cut_handle, struct cut_action_obj *action_object) { char *msg; msg = cutlass_action_msg(action_object); if(NULL == msg) { fprintf(stderr, "Error getting mesage\n"); return(1); } printf(" %s", msg); free(msg); return(0); } struct cut_action_obj * pop_action(void) { struct cut_action_obj *action_object = NULL; struct action_stack *tmp_node; pthread_mutex_lock(&stack_mutex); if(test_stack != NULL) { action_object = test_stack->action_object; tmp_node = test_stack; test_stack = test_stack->next; free(tmp_node); } pthread_mutex_unlock(&stack_mutex); return(action_object); } int load_key(cutlass_t *cut_handle, char *keyfile_name, int keysize) { struct stat statbuf; FILE *new_key; cutlass_private_key private_key; if(stat(keyfile_name, &statbuf) == 0) { private_key = load_private_key(keyfile_name, passphrase_null); if(private_key.key == 0) { fprintf(stderr, "Error loading key from %s\n", keyfile_name); return(-1); } cut_handle->local_key = private_key; } else { fprintf(stderr, "No file %s: generating new key\n", keyfile_name); new_key = fopen(keyfile_name, "w+"); if(new_key == NULL) { fprintf(stderr, "Error creating file %s\n", keyfile_name); return(-1); } private_key = generate_rsa_key(keysize, NULL, NULL); if(private_key.key == 0) { fprintf(stderr, "Error generating key\n"); return(-1); } cut_handle->local_key = private_key; save_private_key(private_key, "", new_key); fclose(new_key); fprintf(stderr, "New key generated, saved in %s\n", keyfile_name); } return(0); } int test_file_send(cutlass_t *cut_handle, int timeout) { int done = 0; int i; struct stat statbuf; struct cut_action_obj *action_object; FILE *new_file; char file_write_buf[] = MESSAGE8; int buf_offset; int file_accepts = 0; int file_completes = 0; int retval; if(stat(TEST_FILE_1_IN, &statbuf) != 0) { fprintf(stderr, "No file %s exists, generating %d bytes\n", TEST_FILE_1_IN, TEST_FILE_1_SIZE); new_file = fopen(TEST_FILE_1_IN, "w"); for(i = 0; i < TEST_FILE_1_SIZE; i++) { buf_offset = i % strlen(file_write_buf); fwrite(file_write_buf + buf_offset, 1, 1, new_file); } fclose(new_file); } if(stat(TEST_FILE_2_IN, &statbuf) != 0) { fprintf(stderr, "No file %s exists, generating %d bytes\n", TEST_FILE_2_IN, TEST_FILE_2_SIZE); new_file = fopen(TEST_FILE_2_IN, "w"); for(i = 0; i < TEST_FILE_2_SIZE; i++) { buf_offset = i % strlen(file_write_buf); fwrite(file_write_buf + buf_offset, 1, 1, new_file); } fclose(new_file); } /* First, test rejection due to lack of capability */ if(cutlass_file_offer(cut_handle, remote_fingerprint, TEST_FILE_1_IN) != -1) { fprintf(stderr, "ERROR! Remote host should have been rejecting files.\n"); return(-1); } cutlass_msg_send(cut_handle, remote_fingerprint, START_FILE_HALF); sleep(3); /* Next, test remote rejection */ retval = cutlass_file_offer(cut_handle, remote_fingerprint, TEST_FILE_1_IN); if(retval < 0) { fprintf(stderr, "ERROR! Remote host should reject, " "but we should succeed - Got %d\n", retval); return(-1); } /* * ERROR - The remote side, in fact, does not trigger a file * rejection handler. It should. Fix and then uncomment the * below portion of the test harness. */ /* while((timeout > 0) && (!done)) { sleep(1); timeout--; action_object = pop_action(); if(action_object != NULL) { if(action_object->action_type != CUT_FILE_REJECT) { fprintf(stderr, "Test file send: " "Got an action type: %d\n", action_object->action_type); return(-1); } else { done = 1; } } } if(timeout == 0) { fprintf(stderr, "Test file send: Timed out\n"); return(-1); } */ cutlass_msg_send(cut_handle, remote_fingerprint, START_FILE_OPEN); sleep(3); /* Finally, test success! */ if(cutlass_file_offer(cut_handle, remote_fingerprint, TEST_FILE_1_IN) < 0) { fprintf(stderr, "ERROR! File offer failed\n"); return(-1); } if(cutlass_file_offer(cut_handle, remote_fingerprint, TEST_FILE_2_IN) < 0) { fprintf(stderr, "ERROR! File offer failed\n"); return(-1); } done = 0; while((timeout > 0) && (!done)) { sleep(1); timeout--; action_object = pop_action(); if(action_object != NULL) { if(action_object->action_type == CUT_FILE_ACCEPT) { file_accepts++; } else if (action_object->action_type == CUT_FILE_SEND_DONE) { file_completes++; } else { fprintf(stderr, "Test file send 2: " "Got an action type: %d\n", action_object->action_type); return(-1); } } if((file_accepts == 2) && (file_completes == 2)) { done = 1; } } if(timeout == 0) { fprintf(stderr, "Test file send: Timed out\n"); return(-1); } fprintf(stderr, "Test file send: Success\n"); return(0); } int test_file_recv(cutlass_t *cut_handle, int timeout) { char *action_msg; char half_open[] = START_FILE_HALF; char full_open[] = START_FILE_OPEN; int done = 0; int file_completes = 0; struct cut_action_obj *action_object; struct stat statbuf; if(stat(TEST_FILE_1_OUT, &statbuf) == 0) { fprintf(stderr, "File %s exists, deleting...", TEST_FILE_1_OUT); unlink(TEST_FILE_1_OUT); } if(stat(TEST_FILE_2_OUT, &statbuf) == 0) { fprintf(stderr, "File %s exists, deleting...", TEST_FILE_2_OUT); unlink(TEST_FILE_2_OUT); } while((timeout > 0) && (!done)) { sleep(1); timeout--; while((action_object = pop_action()) != NULL) { if(action_object->action_type != CUT_MSG_RECV) { fprintf(stderr, "Test file recv: " "Got an action type: %d\n", action_object->action_type); return(-1); } else { action_msg = cutlass_action_msg(action_object); if(NULL == action_msg) { fprintf(stderr, "Test file recv: " "Got a NULL message\n"); return(-1); } if(strcmp(action_msg, half_open) != 0) { fprintf(stderr, "Expecting '%s', got '%s'\n", half_open, action_msg); return(-1); } else { done = 1; fprintf(stderr, "Test file recv: Setting file permissions to" " NOT_ALLOWED\n"); cutlass_set_permission(cut_handle, CAN_RECV_FILES, NOT_ALLOWED); } } } } if(timeout == 0) { fprintf(stderr, "Test file recv: Timed out\n"); return(-1); } done = 0; while((timeout > 0) && (!done)) { sleep(1); timeout--; while((action_object = pop_action()) != NULL) { if(action_object->action_type != CUT_MSG_RECV) { fprintf(stderr, "Test file recv 2: " "Got an action type: %d\n", action_object->action_type); return(-1); } else { action_msg = cutlass_action_msg(action_object); if(NULL == action_msg) { fprintf(stderr, "Test file recv 2: " "Got a NULL message\n"); return(-1); } if(strcmp(action_msg, full_open) != 0) { fprintf(stderr, "Expecting '%s', got '%s'\n", full_open, action_msg); return(-1); } else { done = 1; fprintf(stderr, "Test file recv: Setting file permissions to" " ALL_ALLOWED\n"); cutlass_set_permission(cut_handle, CAN_RECV_FILES, ALL_ALLOWED); } } } } if(timeout == 0) { fprintf(stderr, "Test file recv 2: Timed out\n"); return(-1); } done = 0; while((timeout > 0) && (!done)) { sleep(1); timeout--; while((action_object = pop_action()) != NULL) { if(action_object->action_type == CUT_FILE_RECV_DONE) { file_completes++; } } if(file_completes == 2) { done = 1; } } if(timeout == 0) { fprintf(stderr, "Test file recv 3: Timed out\n"); return(-1); } fprintf(stderr, "Test file recv: Success\n"); return(0); } int test_message_recv(cutlass_t *cut_handle, int timeout) { int done = 0; int i; struct cut_action_obj *action_object; char *action_msg; char msg1[] = MESSAGE1; char msg2[] = MESSAGE2; char msg3[] = MESSAGE3; char msg4[] = MESSAGE4; char msg5[] = MESSAGE5; char msg6[] = MESSAGE6; char msg7[] = MESSAGE7; char msg8[] = MESSAGE8; char msg9[] = MESSAGE9; char msg10[] = MESSAGE10; char success_msg[] = SUCCESS_MSG; char failure_msg[] = FAILURE_MSG; int got_msg[10] = { 0 }; int got_all; while((timeout > 0) && (!done)) { sleep(1); timeout--; while((action_object = pop_action()) != NULL) { if(action_object->action_type != CUT_MSG_RECV) { fprintf(stderr, "Test message recv: " "Got a message action type: %d\n", action_object->action_type); return(-1); } else { action_msg = cutlass_action_msg(action_object); if(NULL == action_msg) { fprintf(stderr, "Test message recv: " "Got a NULL message\n"); return(-1); } if(strcmp(action_msg, msg1) == 0) { printf("Got message 1\n"); got_msg[0] = 1; } else if(strcmp(action_msg, msg2) == 0) { printf("Got message 2\n"); got_msg[1] = 1; } else if(strcmp(action_msg, msg3) == 0) { printf("Got message 3\n"); got_msg[2] = 1; } else if(strcmp(action_msg, msg4) == 0) { printf("Got message 4\n"); got_msg[3] = 1; } else if(strcmp(action_msg, msg5) == 0) { printf("Got message 5\n"); got_msg[4] = 1; } else if(strcmp(action_msg, msg6) == 0) { printf("Got message 6\n"); got_msg[5] = 1; } else if(strcmp(action_msg, msg7) == 0) { printf("Got message 7\n"); got_msg[6] = 1; } else if(strcmp(action_msg, msg8) == 0) { printf("Got message 8\n"); got_msg[7] = 1; } else if(strcmp(action_msg, msg9) == 0) { printf("Got message 9\n"); got_msg[8] = 1; } else if(strcmp(action_msg, msg10) == 0) { printf("Got message 10\n"); got_msg[9] = 1; } else if(strcmp(action_msg, success_msg) == 0) { fprintf(stderr, "Test message recv: " "Got a spurious success message\n"); } else if(strcmp(action_msg, failure_msg) == 0) { fprintf(stderr, "Test message recv: " "Got a spurious failure message\n"); } else { fprintf(stderr, "Test message recv: " "Got an unknown message len <%d> msg <%s>", strlen(action_msg), action_msg); free(action_msg); goto fail; } free(action_msg); } free(action_object); got_all = 1; for(i = 0; i < 10; i++) { if(got_msg[i] != 1) got_all = 0; } if(got_all) done = 1; } } if(timeout == 0) { fprintf(stderr, "Test message recv: Timed out\n"); goto fail; } cutlass_msg_broadcast(cut_handle, SUCCESS_MSG); fprintf(stderr, "Test message recv: Success\n"); return(0); fail: cutlass_msg_broadcast(cut_handle, FAILURE_MSG); return(-1); } int test_message_send(cutlass_t *cut_handle, int timeout) { int done = 0; struct cut_action_obj *action_object; char *action_msg; char success_msg[] = SUCCESS_MSG; char failure_msg[] = FAILURE_MSG; cutlass_msg_send(cut_handle, remote_fingerprint, MESSAGE1); cutlass_msg_send(cut_handle, remote_fingerprint, MESSAGE2); cutlass_msg_send(cut_handle, remote_fingerprint, MESSAGE3); cutlass_msg_send(cut_handle, remote_fingerprint, MESSAGE4); cutlass_msg_send(cut_handle, remote_fingerprint, MESSAGE5); cutlass_msg_send(cut_handle, remote_fingerprint, MESSAGE6); cutlass_msg_send(cut_handle, remote_fingerprint, MESSAGE7); cutlass_msg_send(cut_handle, remote_fingerprint, MESSAGE8); cutlass_msg_send(cut_handle, remote_fingerprint, MESSAGE9); cutlass_msg_send(cut_handle, remote_fingerprint, MESSAGE10); while((timeout > 0) && (!done)) { sleep(1); timeout--; action_object = pop_action(); if(action_object != NULL) { if(action_object->action_type != CUT_MSG_RECV) { fprintf(stderr, "Test message recv: " "Got a message action type: %d\n", action_object->action_type); return(-1); } else { action_msg = cutlass_action_msg(action_object); if(NULL == action_msg) { fprintf(stderr, "Test message recv: " "Got a NULL message\n"); return(-1); } if(strcmp(action_msg, success_msg) == 0) { done = 1; } else if(strcmp(action_msg, failure_msg) == 0) { fprintf(stderr, "Test message send: Remote side unhappy\n"); free(action_msg); return(-1); } else { fprintf(stderr, "Test message send: " "Got an unknown message: %s\n", action_msg); free(action_msg); return(-1); } free(action_msg); } free(action_object); } } if(timeout == 0) { fprintf(stderr, "Test message send: Timed out\n"); return(-1); } else { fprintf(stderr, "Test message send: Success\n"); return(0); } } int test_connect_send(cutlass_t *cut_handle, int timeout, struct sockaddr_in *dest_addr) { struct cut_action_obj *action_object; int done = 0; if(cutlass_connect(cut_handle, dest_addr) < 0) { fprintf(stderr, "Test connect send: cutlass_connect failed\n"); return(-1); } while((timeout > 0) && (!done)) { sleep(1); timeout--; action_object = pop_action(); if(action_object != NULL) { if(action_object->action_type != CUT_USER_CONN) { fprintf(stderr, "Test connect send: " "Got a non-connect action type: %d\n", action_object->action_type); return(-1); } else { remote_fingerprint = cutlass_action_fingerprint(action_object); done = 1; } free(action_object); } } if(timeout == 0) { fprintf(stderr, "Test connect send: Timed out\n"); return(-1); } fprintf(stderr, "Test connect send: Success\n"); return(0); } int test_connect_recv(cutlass_t *cut_handle, int timeout) { struct cut_action_obj *action_object; int done = 0; while((timeout > 0) && (!done)) { sleep(1); timeout--; action_object = pop_action(); if(action_object != NULL) { if(action_object->action_type != CUT_USER_CONN) { fprintf(stderr, "Test connect recv: " "Got a non-connect action type: %d\n", action_object->action_type); return(-1); } else { remote_fingerprint = cutlass_action_fingerprint(action_object); done = 1; } free(action_object); } } if(timeout == 0) { fprintf(stderr, "Test connect recv: Timed out\n"); return(-1); } fprintf(stderr, "Test connect recv: Success\n"); return(0); } int test_child(struct sockaddr_in *child_addr) { cutlass_t *cut_handle; pthread_mutex_init(&stack_mutex, NULL); cut_handle = cutlass_init(); if(cut_handle == NULL) { fprintf(stderr, "Child: initialization failed\n"); return(-1); } if(load_key(cut_handle, CHILD_KEY_FILE, CHILD_KEY_SIZE) < 0) { fprintf(stderr, "Child: Load_key failed\n"); return(-1); } if(cutlass_set_nick(cut_handle, "child") < 0) { fprintf(stderr, "Child: Set_nick failed\n"); return(-1); } if(cutlass_set_port(cut_handle, CHILD_PORT) < 0) { fprintf(stderr, "Child: Set_port failed\n"); return(-1); } if(cutlass_set_verbose(cut_handle, CUT_INFO) < 0) { fprintf(stderr, "Child: Set_verbose failed\n"); return(-1); } if(cutlass_set_permission(cut_handle, CAN_RECV_MSGS, ALL_ALLOWED) < 0) { fprintf(stderr, "Child: Set_permission failed\n"); return(-1); } if(cutlass_register_action(cut_handle, CUT_SYS_MSG, child_sysmsg_handler) < 0) { fprintf(stderr, "Child: Register_action failed\n"); return(-1); } if(cutlass_register_action(cut_handle, CUT_USER_CONN, handle_action) < 0) { fprintf(stderr, "Child: Register_action failed\n"); return(-1); } if(cutlass_register_action(cut_handle, CUT_MSG_RECV, handle_action) < 0) { fprintf(stderr, "Parent: Register_action failed\n"); return(-1); } fprintf(stderr, "Child: Starting Cutlass\n"); if(cutlass_start(cut_handle) < 0) { fprintf(stderr, "Child: Start failed\n"); return(-1); } fprintf(stderr, "Child: Waiting for connection\n"); if(test_connect_recv(cut_handle, CONN_TIMEOUT) < 0) { fprintf(stderr, "Child: Test connect recv failed\n"); return(-1); } if(check_message) { fprintf(stderr, "Child: Testing message reception\n"); if(test_message_recv(cut_handle, MSG_TIMEOUT) < 0) { fprintf(stderr, "Child: Test message recv failed\n"); return(-1); } sleep(3); fprintf(stderr, "Child: Testing message sending\n"); if(test_message_send(cut_handle, MSG_TIMEOUT) < 0) { fprintf(stderr, "Child: Test message send failed\n"); return(-1); } } if(check_file) { fprintf(stderr, "Child: Testing file reception\n"); if(test_file_recv(cut_handle, FILE_TIMEOUT) < 0) { fprintf(stderr, "Child: Test file recv failed\n"); return(-1); } sleep(3); fprintf(stderr, "Child: Testing file sending\n"); if(test_file_send(cut_handle, FILE_TIMEOUT) < 0) { fprintf(stderr, "Child: Test file send failed\n"); return(-1); } } return(0); } int test_parent(struct sockaddr_in *child_addr) { cutlass_t *cut_handle; pthread_mutex_init(&stack_mutex, NULL); cut_handle = cutlass_init(); if(cut_handle == NULL) { fprintf(stderr, "Parent: initialization failed\n"); return(-1); } if(load_key(cut_handle, PARENT_KEY_FILE, PARENT_KEY_SIZE) < 0) { fprintf(stderr, "Parent: Load_key failed\n"); return(-1); } if(cutlass_set_nick(cut_handle, "parent") < 0) { fprintf(stderr, "Parent: Set_nick failed\n"); return(-1); } if(cutlass_set_verbose(cut_handle, CUT_INFO) < 0) { fprintf(stderr, "Parent: Set_verbose failed\n"); return(-1); } if(cutlass_set_permission(cut_handle, CAN_RECV_MSGS, ALL_ALLOWED) < 0) { fprintf(stderr, "Parent: Set_permission failed\n"); return(-1); } if(cutlass_register_action(cut_handle, CUT_USER_CONN, parent_sysmsg_handler) < 0) { fprintf(stderr, "Parent: Register_action failed\n"); return(-1); } if(cutlass_register_action(cut_handle, CUT_USER_CONN, handle_action) < 0) { fprintf(stderr, "Parent: Register_action failed\n"); return(-1); } if(cutlass_register_action(cut_handle, CUT_MSG_RECV, handle_action) < 0) { fprintf(stderr, "Parent: Register_action failed\n"); return(-1); } fprintf(stderr, "Parent: Starting Cutlass\n"); if(cutlass_start(cut_handle) < 0) { fprintf(stderr, "Parent: Start failed\n"); return(-1); } sleep(3); fprintf(stderr, "Parent: Connecting to Child\n"); if(test_connect_send(cut_handle, CONN_TIMEOUT, child_addr) < 0) { fprintf(stderr, "Parent: Test connect send failed\n"); return(-1); } if(check_message) { sleep(3); fprintf(stderr, "Parent: Testing message sending\n"); if(test_message_send(cut_handle, MSG_TIMEOUT) < 0) { fprintf(stderr, "Parent: Test message send failed\n"); return(-1); } fprintf(stderr, "Parent: Testing message reception\n"); if(test_message_recv(cut_handle, MSG_TIMEOUT) < 0) { fprintf(stderr, "Parent: Test message recv failed\n"); return(-1); } } if(check_file) { sleep(3); fprintf(stderr, "Parent: Testing file sending\n"); if(test_file_send(cut_handle, FILE_TIMEOUT) < 0) { fprintf(stderr, "Parent: Test file send failed\n"); return(-1); } fprintf(stderr, "Parent: Testing file reception\n"); if(test_file_recv(cut_handle, FILE_TIMEOUT) < 0) { fprintf(stderr, "Parent: Test file recv failed\n"); return(-1); } } return(0); } int main(int argc, char **argv) { pid_t retval; int option; int test_result; struct sockaddr_in remote_addr; struct hostent *hostent_ptr; memset(&remote_addr, 0, sizeof(struct sockaddr_in)); remote_addr.sin_family = AF_INET; hostent_ptr = gethostbyname("localhost"); if(AF_INET != hostent_ptr->h_addrtype) { fprintf(stderr, "%s: " "gethostbyname returned an unsupported address type\n", argv[0]); return(-1); } memcpy(&(remote_addr.sin_addr), hostent_ptr->h_addr_list[0], 4); while ((option=getopt(argc, argv, "mf")) != -1) { switch(option) { case 'm': check_message = 1;; break; case 'f': check_file = 1; break; } } retval = fork(); if(retval > 0) { remote_addr.sin_port = htons(CHILD_PORT); test_result = test_parent(&remote_addr); } else if(retval == 0) { remote_addr.sin_port = htons(CUT_DEFAULT_PORT); test_result = test_child(&remote_addr); } else { fprintf(stderr, "%s: Could not fork!\n", argv[0]); return(-1); } if(test_result != 0) { if(retval > 0) { fprintf(stderr, "Parent: Test(s) FAILED!\n"); } else { fprintf(stderr, "Child: Test(s) FAILED!\n"); } fprintf(stderr, "%s: Test(s) FAILED!\n", argv[0]); } else { if(retval > 0) { fprintf(stderr, "Parent: All tests succeeded\n"); sleep(3); } else { fprintf(stderr, "Child: All tests succeeded\n"); sleep(3); } } return(0); }