#include "ncplib.h" #include "nwcrypt.h" typedef __u8 byte; typedef __u16 word; typedef __u32 dword; #ifdef __KERNEL__ #define ncp_printf DPRINTK #else #include #include #include #include #define ncp_printf printf static void assert_server_locked(struct ncp_server *server); static void assert_server_not_locked(struct ncp_server *server) { if (server->lock != 0) { ncp_printf("ncpfs: server already locked!\n"); } } static void ncp_lock_server(struct ncp_server *server) { assert_server_not_locked(server); server->lock = 1; } static void ncp_unlock_server(struct ncp_server *server) { assert_server_locked(server); server->lock = 0; } static int ncp_request(struct ncp_server *server, int function) { struct ncp_reply_header *reply = (struct ncp_reply_header *)(server->packet); struct ncp_ioctl_request request; int result; assert_server_locked(server); if (server->has_subfunction != 0) { *(word *)(server->packet) = server->current_size - 2; } request.function = function; request.size = server->current_size; request.data = server->packet; if ((result = ioctl(server->mount_fid, NCP_IOC_NCPREQUEST, &request)) < 0) { return result; } server->ncp_reply_size = result - sizeof(struct ncp_reply_header); return reply->completion_code; } static inline int min(int a, int b) { if (alock == 0) { ncp_printf("ncpfs: server not locked!\n"); } } static void ncp_add_byte(struct ncp_server *server, byte x) { assert_server_locked(server); *(byte *)(&(server->packet[server->current_size])) = x; server->current_size += 1; return; } static void ncp_add_word(struct ncp_server *server, word x) { assert_server_locked(server); *(word *)(&(server->packet[server->current_size])) = x; server->current_size += 2; return; } static void ncp_add_dword(struct ncp_server *server, dword x) { assert_server_locked(server); *(dword *)(&(server->packet[server->current_size])) = x; server->current_size += 4; return; } static void ncp_add_mem(struct ncp_server *server, const char *source, int size) { assert_server_locked(server); memcpy(&(server->packet[server->current_size]), source, size); server->current_size += size; return; } #ifdef __KERNEL__ static void ncp_add_mem_fromfs(struct ncp_server *server, const char *source, int size) { assert_server_locked(server); memcpy_fromfs(&(server->packet[server->current_size]), source, size); server->current_size += size; return; } #endif static void ncp_add_pstring(struct ncp_server *server, const char *s) { int len = strlen(s); assert_server_locked(server); if (len > 255) { ncp_printf("ncpfs: string too long: %s\n", s); len = 255; } ncp_add_byte(server, len); ncp_add_mem(server, s, len); return; } static void ncp_init_request(struct ncp_server *server) { ncp_lock_server(server); #ifdef __KERNEL__ server->current_size = sizeof(struct ncp_request_header); #else server->current_size = 0; server->packet = server->ncp_data; #endif server->has_subfunction = 0; } static void ncp_init_request_s(struct ncp_server *server, int subfunction) { ncp_init_request(server); ncp_add_word(server, 0); /* preliminary size */ ncp_add_byte(server, subfunction); server->has_subfunction = 1; } static char * ncp_reply_data(struct ncp_server *server, int offset) { return &(server->packet[sizeof(struct ncp_reply_header) + offset]); } static byte ncp_reply_byte(struct ncp_server *server, int offset) { return *(byte *)(ncp_reply_data(server, offset)); } static word ncp_reply_word(struct ncp_server *server, int offset) { return *(word *)(ncp_reply_data(server, offset)); } static dword ncp_reply_dword(struct ncp_server *server, int offset) { return *(dword *)(ncp_reply_data(server, offset)); } int ncp_negotiate_buffersize(struct ncp_server *server, int size, int *target) { int result; ncp_init_request(server); ncp_add_word(server, htons(size)); if ((result = ncp_request(server, 33)) < 0) { ncp_printf("ncp_request_error: %d\n", result); ncp_unlock_server(server); return result; } *target =min(ntohs(ncp_reply_word(server, 0)), size); ncp_unlock_server(server); return 0; } /* * result is a 8-byte buffer */ int ncp_get_encryption_key(struct ncp_server *server, char *target) { int result; ncp_init_request_s(server, 23); if ((result = ncp_request(server, 23)) != 0) { ncp_printf("ncp_request_error: %d\n", result); ncp_unlock_server(server); return result; } if (server->ncp_reply_size < 8) { ncp_printf("ncp_reply_size %d < 8\n", server->ncp_reply_size); ncp_unlock_server(server); return result; } memcpy(target, ncp_reply_data(server, 0), 8); ncp_unlock_server(server); return 0; } int ncp_get_bindery_object_id(struct ncp_server *server, int object_type, char *object_name, struct ncp_bindery_object *target) { int result; ncp_init_request_s(server, 53); ncp_add_word(server, ntohs(object_type)); ncp_add_pstring(server, object_name); if ((result = ncp_request(server, 23)) != 0) { ncp_printf("ncp_request_error: %d\n", result); ncp_unlock_server(server); return result; } if (server->ncp_reply_size < 54) { ncp_printf("ncp_reply_size %d < 54\n", server->ncp_reply_size); ncp_unlock_server(server); return result; } target->object_id = ntohl(ncp_reply_dword(server, 0)); target->object_type = ntohs(ncp_reply_word (server, 4)); memcpy(target->object_name, ncp_reply_data(server, 6), 48); ncp_unlock_server(server); return 0; } int ncp_login_encrypted(struct ncp_server *server, struct ncp_bindery_object *object, unsigned char *key, unsigned char *passwd) { dword tmpID = htonl(object->object_id); unsigned char buf[128]; unsigned char encrypted[8]; int result; shuffle((byte *)&tmpID, passwd, strlen(passwd), buf); nw_encrypt(key, buf, encrypted); ncp_init_request_s(server, 24); ncp_add_mem(server, encrypted, 8); ncp_add_word(server, htons(object->object_type)); ncp_add_pstring(server, object->object_name); if ((result = ncp_request(server, 23)) != 0) { ncp_printf("ncp_request_error: %d\n", result); ncp_unlock_server(server); return result; } ncp_unlock_server(server); return 0; } int ncp_login_user(struct ncp_server *server, unsigned char *username, unsigned char *password) { int result; unsigned char ncp_key[8]; struct ncp_bindery_object user; if ((result = ncp_get_encryption_key(server, ncp_key)) != 0) { return result; } if ((result = ncp_get_bindery_object_id(server, NCP_BINDERY_USER, username, &user)) != 0) { return result; } if ((result = ncp_login_encrypted(server, &user, ncp_key, password)) != 0) { return result; } return 0; } int ncp_get_volume_info_with_number(struct ncp_server *server, int n, struct ncp_volume_info *target) { int result; int len; ncp_init_request_s(server, 44); ncp_add_byte(server, n); if ((result = ncp_request(server, 22)) != 0) { ncp_printf("ncp_request_error: %d\n", result); ncp_unlock_server(server); return result; } target->total_blocks = ncp_reply_dword(server, 0); target->free_blocks = ncp_reply_dword(server, 4); target->purgeable_blocks = ncp_reply_dword(server, 8); target->not_yet_purgeable_blocks = ncp_reply_dword(server, 12); target->total_dir_entries = ncp_reply_dword(server, 16); target->available_dir_entries = ncp_reply_dword(server, 20); target->sectors_per_block = ncp_reply_byte(server, 28); memset(&(target->volume_name), 0, sizeof(target->volume_name)); len = ncp_reply_byte(server, 29); if (len > NCP_VOLNAME_LEN) { ncp_printf("ncpfs: volume name too long: %d\n", len); ncp_unlock_server(server); return -EIO; } memcpy(&(target->volume_name), ncp_reply_data(server, 30), len); ncp_unlock_server(server); return 0; } int ncp_get_volume_number(struct ncp_server *server, const char *name, int *target) { int result; ncp_init_request_s(server, 5); ncp_add_pstring(server, name); if ((result = ncp_request(server, 22)) != 0) { ncp_printf("ncp_request_error: %d\n", result); ncp_unlock_server(server); return result; } *target = ncp_reply_byte(server, 0); ncp_unlock_server(server); return 0; } int ncp_file_search_init(struct ncp_server *server, int dir_handle, const char *path, struct ncp_filesearch_info *target) { int result; ncp_init_request(server); ncp_add_byte(server, dir_handle); ncp_add_pstring(server, path); if ((result = ncp_request(server, 62)) != 0) { ncp_printf("ncp_request_error: %d\n", result); ncp_unlock_server(server); return result; } target->volume_number = ncp_reply_byte(server, 0); target->directory_id = ntohs(ncp_reply_word(server, 1)); target->sequence_no = ntohs(ncp_reply_word(server, 3)); target->access_rights = ncp_reply_byte(server, 5); ncp_unlock_server(server); return 0; } int ncp_file_search_continue(struct ncp_server *server, struct ncp_filesearch_info *fsinfo, int attributes, const char *name, struct ncp_file_info *target) { int result; ncp_init_request(server); ncp_add_byte(server, fsinfo->volume_number); ncp_add_word(server, htons(fsinfo->directory_id)); ncp_add_word(server, htons(fsinfo->sequence_no)); ncp_add_byte(server, attributes); ncp_add_pstring(server, name); if ((result = ncp_request(server, 63)) != 0) { ncp_printf("ncp_request_error: %d\n", result); ncp_unlock_server(server); return result; } fsinfo->sequence_no = ntohs(ncp_reply_word(server, 0)); memset(&(target->file_name), 0, sizeof(target->file_name)); memcpy(&(target->file_name), ncp_reply_data(server, 4), NCP_MAX_FILENAME); target->file_attributes = ncp_reply_byte(server, 18); target->file_mode = ncp_reply_byte(server, 19); target->file_length = ntohl(ncp_reply_dword(server, 20)); target->creation_date = ntohs(ncp_reply_word(server, 24)); target->access_date = ntohs(ncp_reply_word(server, 26)); target->update_date = ntohs(ncp_reply_word(server, 28)); target->update_time = ntohs(ncp_reply_word(server, 30)); ncp_unlock_server(server); return 0; } int ncp_get_finfo(struct ncp_server *server, int dir_handle, const char *path, const char *name, struct ncp_file_info *target) { int result; struct ncp_filesearch_info fsinfo; if ((result = ncp_file_search_init(server, dir_handle, path, &fsinfo)) != 0) { return result; } if ((result = ncp_file_search_continue(server, &fsinfo, 0, name, target)) == 0) { return result; } if ((result = ncp_file_search_init(server, dir_handle, path, &fsinfo)) != 0) { return result; } return ncp_file_search_continue(server, &fsinfo, aDIR, name, target); } int ncp_open_file(struct ncp_server *server, int dir_handle, const char *path, int attr, int access, struct ncp_file_info *target) { int result; ncp_init_request(server); ncp_add_byte(server, dir_handle); ncp_add_byte(server, attr); ncp_add_byte(server, access); ncp_add_pstring(server, path); if ((result = ncp_request(server, 76)) != 0) { ncp_printf("ncp_request_error: %d\n", result); ncp_unlock_server(server); return result; } memcpy(&(target->file_id), ncp_reply_data(server, 0), NCP_FILE_ID_LEN); memset(&(target->file_name), 0, sizeof(target->file_name)); memcpy(&(target->file_name), ncp_reply_data(server, 8), NCP_MAX_FILENAME); target->file_attributes = ncp_reply_byte(server, 22); target->file_mode = ncp_reply_byte(server, 23); target->file_length = ntohl(ncp_reply_dword(server, 24)); target->creation_date = ntohs(ncp_reply_word(server, 28)); target->access_date = ntohs(ncp_reply_word(server, 30)); target->update_date = ntohs(ncp_reply_word(server, 32)); target->update_time = ntohs(ncp_reply_word(server, 34)); ncp_unlock_server(server); return 0; } int ncp_close_file(struct ncp_server *server, const char *file_id) { int result; ncp_init_request(server); ncp_add_byte(server, 0); ncp_add_mem(server, file_id, 6); if ((result = ncp_request(server, 66)) != 0) { ncp_printf("ncp_request_error: %d\n", result); ncp_unlock_server(server); return result; } ncp_unlock_server(server); return 0; } static int ncp_do_create(struct ncp_server *server, int dir_handle, const char *path, int attr, struct ncp_file_info *target, int function) { int result; ncp_init_request(server); ncp_add_byte(server, dir_handle); ncp_add_byte(server, attr); ncp_add_pstring(server, path); if ((result = ncp_request(server, function)) != 0) { ncp_printf("ncp_request_error: %d\n", result); ncp_unlock_server(server); return result; } memcpy(&(target->file_id), ncp_reply_data(server, 0), NCP_FILE_ID_LEN); memset(&(target->file_name), 0, sizeof(target->file_name)); memcpy(&(target->file_name), ncp_reply_data(server, 8), NCP_MAX_FILENAME); target->file_attributes = ncp_reply_byte(server, 22); target->file_mode = ncp_reply_byte(server, 23); target->file_length = ntohl(ncp_reply_dword(server, 24)); target->creation_date = ntohs(ncp_reply_word(server, 28)); target->access_date = ntohs(ncp_reply_word(server, 30)); target->update_date = ntohs(ncp_reply_word(server, 32)); target->update_time = ntohs(ncp_reply_word(server, 34)); ncp_unlock_server(server); return 0; } int ncp_create_newfile(struct ncp_server *server, int dir_handle, const char *path, int attr, struct ncp_file_info *target) { return ncp_do_create(server, dir_handle, path, attr, target, 77); } int ncp_create_file(struct ncp_server *server, int dir_handle, const char *path, int attr, struct ncp_file_info *target) { return ncp_do_create(server, dir_handle, path, attr, target, 67); } int ncp_erase_file(struct ncp_server *server, int dir_handle, const char *path, int attr) { int result; ncp_init_request(server); ncp_add_byte(server, dir_handle); ncp_add_byte(server, attr); ncp_add_pstring(server, path); if ((result = ncp_request(server, 68)) != 0) { ncp_printf("ncp_request_error: %d\n", result); ncp_unlock_server(server); return result; } ncp_unlock_server(server); return 0; } int ncp_rename_file(struct ncp_server *server, int old_handle, const char *old_path, int attr, int new_handle, const char *new_path) { int result; ncp_init_request(server); ncp_add_byte(server, old_handle); ncp_add_byte(server, attr); ncp_add_pstring(server, old_path); ncp_add_byte(server, new_handle); ncp_add_pstring(server, new_path); if ((result = ncp_request(server, 69)) != 0) { ncp_printf("ncp_request_error: %d\n", result); ncp_unlock_server(server); return result; } ncp_unlock_server(server); return 0; } int ncp_create_directory(struct ncp_server *server, int dir_handle, const char *path, int inherit_mask) { int result; ncp_init_request_s(server, 10); ncp_add_byte(server, dir_handle); ncp_add_byte(server, inherit_mask); ncp_add_pstring(server, path); if ((result = ncp_request(server, 22)) != 0) { ncp_printf("ncp_request_error: %d\n", result); ncp_unlock_server(server); return result; } ncp_unlock_server(server); return 0; } int ncp_delete_directory(struct ncp_server *server, int dir_handle, const char *path) { int result; ncp_init_request_s(server, 11); ncp_add_byte(server, dir_handle); ncp_add_byte(server, 0); /* reserved */ ncp_add_pstring(server, path); if ((result = ncp_request(server, 22)) != 0) { ncp_printf("ncp_request_error: %d\n", result); ncp_unlock_server(server); return result; } ncp_unlock_server(server); return 0; } int ncp_rename_directory(struct ncp_server *server, int dir_handle, const char *old_path, const char *new_path) { int result; ncp_init_request_s(server, 15); ncp_add_byte(server, dir_handle); ncp_add_pstring(server, old_path); ncp_add_pstring(server, new_path); if ((result = ncp_request(server, 22)) != 0) { ncp_printf("ncp_request_error: %d\n", result); ncp_unlock_server(server); return result; } ncp_unlock_server(server); return 0; } #ifndef __KERNEL__ int ncp_read(struct ncp_server *server, const char *file_id, __u32 offset, __u16 to_read, char *target, int *bytes_read) { int result; ncp_init_request(server); ncp_add_byte(server, 0); ncp_add_mem(server, file_id, 6); ncp_add_dword(server, htonl(offset)); ncp_add_word(server, htons(to_read)); if ((result = ncp_request(server, 72)) != 0) { ncp_printf("ncp_request_error: %d\n", result); ncp_unlock_server(server); return result; } *bytes_read = ntohs(ncp_reply_word(server, 0)); memcpy(target, ncp_reply_data(server, 2), *bytes_read); ncp_unlock_server(server); return 0; } int ncp_write(struct ncp_server *server, const char *file_id, __u32 offset, __u16 to_write, const char *source, int *bytes_written) { int result; ncp_init_request(server); ncp_add_byte(server, 0); ncp_add_mem(server, file_id, 6); ncp_add_dword(server, htonl(offset)); ncp_add_word(server, htons(to_write)); ncp_add_mem(server, source, to_write); if ((result = ncp_request(server, 73)) != 0) { ncp_printf("ncp_request_error: %d\n", result); ncp_unlock_server(server); return result; } *bytes_written = to_write; ncp_unlock_server(server); return 0; } #else /* We have to transfer to/from user space */ int ncp_read(struct ncp_server *server, const char *file_id, __u32 offset, __u16 to_read, char *target, int *bytes_read) { int result; ncp_init_request(server); ncp_add_byte(server, 0); ncp_add_mem(server, file_id, 6); ncp_add_dword(server, htonl(offset)); ncp_add_word(server, htons(to_read)); if ((result = ncp_request(server, 72)) != 0) { ncp_printf("ncp_request_error: %d\n", result); ncp_unlock_server(server); return result; } *bytes_read = ntohs(ncp_reply_word(server, 0)); memcpy_tofs(target, ncp_reply_data(server, 2), *bytes_read); ncp_unlock_server(server); return 0; } int ncp_write(struct ncp_server *server, const char *file_id, __u32 offset, __u16 to_write, const char *source, int *bytes_written) { int result; ncp_init_request(server); ncp_add_byte(server, 0); ncp_add_mem(server, file_id, 6); ncp_add_dword(server, htonl(offset)); ncp_add_word(server, htons(to_write)); ncp_add_mem_fromfs(server, source, to_write); if ((result = ncp_request(server, 73)) != 0) { ncp_printf("ncp_request_error: %d\n", result); ncp_unlock_server(server); return result; } *bytes_written = to_write; ncp_unlock_server(server); return 0; } #endif