Files
ncpfs/ncplib.c
ncpfs archive import 7591e85f7b Import ncpfs 0.1
2026-04-28 20:39:57 +02:00

599 lines
13 KiB
C

#include "ncplib.h"
#include "nwcrypt.h"
typedef __u8 byte;
typedef __u16 word;
typedef __u32 dword;
#ifdef __KERNEL__
#define ncp_printf DPRINTK
#else
#include <sys/ioctl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#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 (a<b)
return a;
else
return b;
}
#endif
static void
assert_server_locked(struct ncp_server *server)
{
if (server->lock == 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;
}
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;
}
#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;
}
#else
/* We have to read into 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;
}
#endif