// BeServed.cpp : Defines the entry point for the application. // #include "stdafx.h" #include "beCompat.h" #include "betalk.h" #include "authentication.h" #include "readerWriter.h" #include "printing.h" #include "ubi_SplayTree.h" // Windows service-specific header files. #include "winsvc.h" #include "NTServApp.h" #include "myservice.h" #define BT_MAX_THREADS 100 #define BT_MAX_RETRIES 3 #define BT_MAX_FILE_SHARES 128 #define BT_MAX_PRINTER_SHARES 16 #define BT_THREAD_NAME "BeServed Handler" #define BT_HOST_THREAD_NAME "BeServed Host Publisher" #define PATH_ROOT "/boot" #define PATH_DELIMITER '/' #ifndef iswhite #define iswhite(c) ((c == ' ' || c == '\t')) #endif typedef struct { unsigned int type; unsigned int length; char *data; } bt_arg_t; typedef struct btblock { vnode_id vnid; beos_off_t pos; int32 len; int32 count; char *buffer; struct btblock *next; struct btblock *prev; } bt_block; typedef struct session { int socket; unsigned int client_s_addr; HANDLE handlerID; bool killed; // The user that is connected. char user[MAX_NAME_LENGTH + 1]; // What share did the client connect to? And when? int share; int rights; time_t logon; // Buffered write support. bt_block *rootBlock; sem_id blockSem; char ioBuffer[BT_MAX_IO_BUFFER + 1]; char attrBuffer[BT_MAX_ATTR_BUFFER + 1]; char pathBuffer[B_PATH_NAME_LENGTH]; struct session *next; } bt_session_t; typedef void (*bt_net_func)(bt_session_t *, unsigned int, int, bt_arg_t *); typedef struct dirCommand { unsigned char command; bt_net_func handler; bool supported; uint8 args; uint32 argTypes[MAX_COMMAND_ARGS]; } bt_command_t; typedef struct { vnode_id vnid; int shareId; char unused[20]; } bt_fdesc; typedef struct btnode { ubi_trNode node; vnode_id vnid; char *name; bool invalid; struct btnode *parent; } bt_node; typedef struct fileShare { char path[B_PATH_NAME_LENGTH]; char name[B_FILE_NAME_LENGTH]; bool used; bool readOnly; // What rights does each user have? bt_user_rights *rights; int security; struct fileShare *next; } bt_fileShare_t; typedef struct mime_mapping { char extension[7]; char *mimeType; struct mime_mapping *next; } bt_mime_mapping; void BeServedStartup(CMyService *service); bool dateCheck(); DWORD WINAPI btSendHost(LPVOID data); void getHostInfo(bt_hostinfo *info); int getSharedResources(char *buffer, int bufSize, bool shares, bool printers); int getHostUsers(char *buffer); void startService(); void endService(int sig); void initMimeMap(); void closeMimeMap(); void closePrinters(); void freeFileShares(); void waitForThread(HANDLE threadId); void initShares(); void initPrinters(); void loadShares(); void getFileShare(const char *buffer); void loadFolder(const char *path); void getShareProperty(const char *buffer); void getAuthenticate(const char *buffer); bool getAuthServerAddress(const char *name); void addUserRights(char *share, char *user, int rights, bool isGroup); void getGrant(const char *buffer); void getPrinter(const char *buffer); int getToken(); int receiveRequest(bt_session_t *session); void handleRequest(bt_session_t *session, unsigned int xid, unsigned char command, int argc, bt_arg_t argv[]); void launchThread(int client, struct sockaddr_in *addr); int tooManyConnections(unsigned int _s_addr); void sendErrorToClient(int client, unsigned int xid, int error); void getArguments(bt_session_t *session, bt_inPacket *packet, unsigned char command); DWORD WINAPI requestThread(LPVOID data); DWORD WINAPI printerThread(LPVOID data); void KillNode(ubi_trNodePtr node); int CompareVnidNodes(ubi_trItemPtr item, ubi_trNodePtr node); int CompareNameNodes(ubi_trItemPtr item, ubi_trNodePtr node); bt_node *btGetNodeFromVnid(vnode_id vnid); void btAddHandle(vnode_id dir_vnid, vnode_id file_vnid, char *name); void btRemoveHandle(vnode_id vnid); void btPurgeNodes(vnode_id vnid); bool btIsAncestorNode(vnode_id vnid, bt_node *node); char *btGetLocalFileName(char *path, vnode_id vnid); void btMakeHandleFromNode(bt_node *node, vnode_id vnid); bt_node *btFindNode(bt_node *parent, char *fileName); char *btGetSharePath(char *shareName); int btGetShareId(char *shareName); int btGetShareIdByPath(char *path); bt_printer *btFindPrinter(char *printerName); uint32 btGetWinInode(const char *path); int btGetBeosStat(char *fileName, beos_stat *st); void btMakePath(char *path, char *dir, char *file); int btPreMount(bt_session_t *session, char *shareName); int btMount(bt_session_t *session, char *shareName, char *user, char *password, vnode_id *vnid); int btGetFSInfo(fs_info *fsInfo, char *path); int btLookup(char *pathBuf, vnode_id dir_vnid, char *fileName, vnode_id *file_vnid); int btStat(char *pathBuf, vnode_id vnid, beos_stat *st); int btReadDir(char *pathBuf, vnode_id dir_vnid, long **dir, vnode_id *file_vnid, char *filename, beos_stat *st); int32 btRead(char *pathBuf, vnode_id vnid, beos_off_t pos, int32 len, char *buffer); int32 btWrite(bt_session_t *session, vnode_id vnid, beos_off_t pos, int32 len, int32 totalLen, char *buffer); int btCreate(char *pathBuf, vnode_id dir_vnid, char *name, int omode, int perms, vnode_id *file_vnid); int btTruncate(char *pathBuf, vnode_id vnid, int64 len); int btCreateDir(char *pathBuf, vnode_id dir_vnid, char *name, int perms, vnode_id *file_vnid, beos_stat *st); int btDeleteDir(char *pathBuf, vnode_id dir_vnid, char *name); int btRename(char *pathBuf, vnode_id old_vnid, char *oldName, vnode_id new_vnid, char *newName); int btUnlink(char *pathBuf, vnode_id vnid, char *name); int btReadLink(char *pathBuf, vnode_id vnid, char *buffer, int length); int btSymLink(char *pathBuf, vnode_id vnid, char *name, char *dest); int btWStat(char *pathBuf, vnode_id vnid, long mask, int32 mode, int32 uid, int32 gid, int64 size, int32 atime, int32 mtime); int btCommit(bt_session_t *session, vnode_id vnid); int btReadAttrib(char *pathBuf, vnode_id vnid, char *name, char *buffer); int btAuthenticate(char *resource, char *user, char *password); bt_block *btGetWriteBlock(bt_session_t *session, vnode_id vnid); void btInsertWriteBlock(bt_session_t *session, bt_block *block); void btRemoveWriteBlock(bt_session_t *session, bt_block *block); void netbtPreMount(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtMount(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtFSInfo(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtLookup(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtStat(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtReadDir(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtRead(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtWrite(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtCreate(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtTruncate(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtCreateDir(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtDeleteDir(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtRename(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtUnlink(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtReadLink(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtSymLink(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtWStat(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtReadAttrib(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtWriteAttrib(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtReadAttribDir(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtRemoveAttrib(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtStatAttrib(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtReadIndexDir(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtCreateIndex(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtRemoveIndex(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtStatIndex(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtReadQuery(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtCommit(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtPrintJobNew(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtPrintJobData(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtPrintJobCommit(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtAuthenticate(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); void netbtQuit(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]); CMyService *winService; bt_node *rootNode = NULL; ubi_btRoot vnidTree; ubi_btRoot nameTree; bt_mime_mapping *mimeMap = NULL; bt_session_t *rootSession = NULL; bt_fileShare_t fileShares[BT_MAX_FILE_SHARES]; bt_printer sharedPrinters[BT_MAX_PRINTER_SHARES]; char tokBuffer[MAX_NAME_LENGTH + 1], *tokPtr; bool running = true; bool preload = false; int server; char authServerName[B_FILE_NAME_LENGTH]; unsigned int authServerIP; bt_managed_data handleData; bt_managed_data sessionData; HANDLE hostThread; char *keywords[] = { "share", "as", "set", "read", "write", "read-write", "promiscuous", "on", "to", "authenticate", "with", "group", "printer", "print", "is", "spooled", "device", "type", "preload", NULL }; bt_command_t dirCommands[] = { { BT_CMD_PREMOUNT, netbtPreMount, true, 1, { B_STRING_TYPE } }, { BT_CMD_MOUNT, netbtMount, true, 3, { B_STRING_TYPE, B_STRING_TYPE, B_STRING_TYPE } }, { BT_CMD_FSINFO, netbtFSInfo, true, 1, { B_INT64_TYPE } }, { BT_CMD_LOOKUP, netbtLookup, true, 2, { B_INT64_TYPE, B_STRING_TYPE } }, { BT_CMD_STAT, netbtStat, true, 1, { B_INT64_TYPE } }, { BT_CMD_READDIR, netbtReadDir, true, 2, { B_INT64_TYPE, B_STRING_TYPE } }, { BT_CMD_READ, netbtRead, true, 3, { B_INT64_TYPE, B_INT32_TYPE, B_INT32_TYPE } }, { BT_CMD_WRITE, netbtWrite, true, 5, { B_INT64_TYPE, B_INT64_TYPE, B_INT32_TYPE, B_INT32_TYPE, B_STRING_TYPE } }, { BT_CMD_CREATE, netbtCreate, true, 4, { B_INT64_TYPE, B_STRING_TYPE, B_INT32_TYPE, B_INT32_TYPE } }, { BT_CMD_TRUNCATE, netbtTruncate, true, 2, { B_INT64_TYPE, B_INT64_TYPE } }, { BT_CMD_MKDIR, netbtCreateDir, true, 3, { B_INT64_TYPE, B_STRING_TYPE, B_INT32_TYPE } }, { BT_CMD_RMDIR, netbtDeleteDir, true, 2, { B_INT64_TYPE, B_STRING_TYPE } }, { BT_CMD_RENAME, netbtRename, true, 4, { B_INT64_TYPE, B_STRING_TYPE, B_INT64_TYPE, B_STRING_TYPE } }, { BT_CMD_UNLINK, netbtUnlink, true, 2, { B_INT64_TYPE, B_STRING_TYPE } }, { BT_CMD_READLINK, netbtReadLink, false, 1, { B_INT64_TYPE } }, { BT_CMD_SYMLINK, netbtSymLink, false, 3, { B_INT64_TYPE, B_STRING_TYPE, B_STRING_TYPE } }, { BT_CMD_WSTAT, netbtWStat, true, 8, { B_INT64_TYPE, B_INT32_TYPE, B_INT32_TYPE, B_INT32_TYPE, B_INT32_TYPE, B_INT32_TYPE, B_INT32_TYPE, B_INT32_TYPE } }, { BT_CMD_READATTRIB, netbtReadAttrib, true, 5, { B_STRING_TYPE, B_STRING_TYPE, B_INT32_TYPE, B_INT32_TYPE, B_INT32_TYPE } }, { BT_CMD_WRITEATTRIB, netbtWriteAttrib, false, 6, { B_STRING_TYPE, B_STRING_TYPE, B_INT32_TYPE, B_STRING_TYPE, B_INT32_TYPE, B_INT32_TYPE } }, { BT_CMD_READATTRIBDIR, netbtReadAttribDir, false, 2, { B_STRING_TYPE, B_STRING_TYPE } }, { BT_CMD_REMOVEATTRIB, netbtRemoveAttrib, false, 2, { B_STRING_TYPE, B_STRING_TYPE } }, { BT_CMD_STATATTRIB, netbtStatAttrib, true, 2, { B_STRING_TYPE, B_STRING_TYPE } }, { BT_CMD_READINDEXDIR, netbtReadIndexDir, false, 1, { B_STRING_TYPE } }, { BT_CMD_CREATEINDEX, netbtCreateIndex, false, 3, { B_STRING_TYPE, B_INT32_TYPE, B_INT32_TYPE } }, { BT_CMD_REMOVEINDEX, netbtRemoveIndex, false, 1, { B_STRING_TYPE } }, { BT_CMD_STATINDEX, netbtStatIndex, false, 1, { B_STRING_TYPE } }, { BT_CMD_READQUERY, netbtReadQuery, false, 2, { B_STRING_TYPE, B_STRING_TYPE } }, { BT_CMD_COMMIT, netbtCommit, true, 1, { B_INT64_TYPE } }, { BT_CMD_PRINTJOB_NEW, netbtPrintJobNew, true, 4, { B_STRING_TYPE, B_STRING_TYPE, B_STRING_TYPE, B_STRING_TYPE } }, { BT_CMD_PRINTJOB_DATA, netbtPrintJobData, true, 4, { B_STRING_TYPE, B_STRING_TYPE, B_STRING_TYPE, B_INT32_TYPE } }, { BT_CMD_PRINTJOB_COMMIT, netbtPrintJobCommit, true, 2, { B_STRING_TYPE, B_STRING_TYPE } }, { BT_CMD_AUTHENTICATE, netbtAuthenticate, true, 3, { B_STRING_TYPE, B_STRING_TYPE, B_STRING_TYPE } }, { BT_CMD_QUIT, netbtQuit, true, 0, { 0 } }, { 0, NULL, false, 0, { 0 } } }; //int APIENTRY WinMain(HINSTANCE hInstance, // HINSTANCE hPrevInstance, // LPSTR lpCmdLine, // int nCmdShow) void BeServedStartup(CMyService *service) { WSADATA wsaData; DWORD threadId; ASSERT(service); winService = service; initPrinters(); initMimeMap(); initShares(); signal(SIGINT, endService); signal(SIGTERM, endService); // Initialize the trees sorted by vnode_id and by name. ubi_trInitTree(&vnidTree, CompareVnidNodes, 0); ubi_trInitTree(&nameTree, CompareNameNodes, 0); if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) return; if (initManagedData(&handleData)) if (initManagedData(&sessionData)) hostThread = CreateThread(NULL, 0, btSendHost, NULL, 0, &threadId); } bool dateCheck() { struct _stat st; time_t curTime; time(&curTime); if (curTime > 1012537700) return false; if (_stat("/boot/home/config/servers/beserved_server", &st) == 0) if (curTime < st.st_ctime || curTime > st.st_ctime + 7776000) return false; return true; } void restartService() { bt_fileShare_t *oldShares; int i; // Printers are easier because the printer name is sent with each print request. // If the printer is no longer available, the next transmission sent regarding // that printer will result in an error, terminating the print job on the client. // All we have to do is clear out the structures, and initShares will read the // configuration file. initPrinters(); // Delay all mounting and other file system operations. beginWriting(&handleData); beginWriting(&sessionData); // Copy existing share data. oldShares = (bt_fileShare_t *) malloc(sizeof(bt_fileShare_t) * BT_MAX_FILE_SHARES); if (oldShares) { for (i = 0; i < BT_MAX_FILE_SHARES; i++) memcpy(&oldShares[i], &fileShares[i], sizeof(bt_fileShare_t)); // Reload the share data. initShares(); // Now loop through the old file shares. For each one, check if the same // path exists in the new shares. for (i = 0; i < BT_MAX_FILE_SHARES; i++) if (oldShares[i].used) { bt_session_t *s; int share = btGetShareIdByPath(oldShares[i].path); if (share == -1) { for (s = rootSession; s; s = s->next) if (s->share == i) s->killed = true; } else if (share != i) { for (s = rootSession; s; s = s->next) if (s->share == i) s->share = share; } } free(oldShares); } // Resume normal operation. endWriting(&sessionData); endWriting(&handleData); } DWORD WINAPI btSendHost(LPVOID data) { bt_request request; bt_hostinfo info; struct sockaddr_in serverAddr, clientAddr; char buffer[4096]; int server, addrLen, bufLen, replyLen; buffer[0] = 0; bufLen = sizeof(buffer); server = socket(AF_INET, SOCK_DGRAM, 0); if (server == INVALID_SOCKET) return 0; memset(&serverAddr, 0, sizeof(serverAddr)); serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(BT_QUERYHOST_PORT); serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); // Bind that socket to the address constructed above. if (bind(server, (struct sockaddr *) &serverAddr, sizeof(serverAddr))) return 0; while (running) { addrLen = sizeof(struct sockaddr_in); replyLen = 0; if (recvfrom(server, (char *) &request, sizeof(request), 0, (struct sockaddr *) &clientAddr, &addrLen) <= 0) continue; switch (request.command) { case BT_REQ_HOST_PROBE: gethostname(buffer, bufLen); break; case BT_REQ_SHARE_PROBE: replyLen = getSharedResources(buffer, sizeof(buffer), true, true); break; case BT_REQ_PRINTER_PROBE: replyLen = getSharedResources(buffer, sizeof(buffer), false, true); break; case BT_REQ_HOST_INFO: getHostInfo(&info); memcpy(buffer, &info, sizeof(bt_hostinfo)); replyLen = sizeof(bt_hostinfo); break; case BT_REQ_HOST_USERS: replyLen = getHostUsers(buffer); break; } // If no reply length has been specified, calculate it now by taking the // length of the buffer. if (replyLen == 0) replyLen = strlen(buffer); sendto(server, buffer, replyLen, 0, (struct sockaddr *) &clientAddr, addrLen); } // Close the socket. Technically, I believe we should call shutdown() // first, but the BeOS header file socket.h indicates that this // function is not currently working. It is present but may not have // any effect. shutdown(server, 2); closesocket(server); return 0; } // getSharedResources() // int getSharedResources(char *buffer, int bufSize, bool shares, bool printers) { bt_resource resource; int i, bufPos = 0; // If the supplied buffer can't hold at least two resource structures, one // for a shared resource and one to terminate the list, then don't bother // building the list. if (bufSize < 2 * sizeof(bt_resource)) return 0; if (shares) for (i = 0; i < BT_MAX_FILE_SHARES; i++) if (fileShares[i].used) { // If this is the last resource structure that will fit in the // buffer, then don't add any more into the list. if (bufPos + sizeof(bt_resource) >= bufSize) break; // Fill out the resource structure. resource.type = BT_SHARED_FOLDER; resource.subType = 0; strcpy(resource.name, fileShares[i].name); // Copy the resource structure into the buffer at the current offset. memcpy(buffer + bufPos, &resource, sizeof(bt_resource)); bufPos += sizeof(bt_resource); } if (printers) for (i = 0; i < BT_MAX_PRINTER_SHARES; i++) if (sharedPrinters[i].used) { // If this is the last resource structure that will fit in the // buffer, then don't add any more into the list. if (bufPos + sizeof(bt_resource) >= bufSize) break; // Fill out the resource structure. resource.type = BT_SHARED_PRINTER; resource.subType = BT_PRINTER_PCL3; strcpy(resource.name, sharedPrinters[i].printerName); // Copy the resource structure into the buffer at the current offset. memcpy(buffer + bufPos, &resource, sizeof(bt_resource)); bufPos += sizeof(bt_resource); } // Copy the null terminating structure. resource.type = BT_SHARED_NULL; resource.subType = 0; resource.name[0] = 0; memcpy(buffer + bufPos, &resource, sizeof(bt_resource)); bufPos += sizeof(bt_resource); return bufPos; } // getHostInfo() // void getHostInfo(bt_hostinfo *info) { SYSTEM_INFO systemInfo; OSVERSIONINFOEX osInfo; bt_session_t *s; osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if (!GetVersionEx((OSVERSIONINFO *) &osInfo)) { osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx((OSVERSIONINFO *) &osInfo); } GetSystemInfo(&systemInfo); switch (osInfo.dwPlatformId) { case VER_PLATFORM_WIN32_WINDOWS: if (osInfo.dwMinorVersion == 0) { strcpy(info->system, "Windows 95"); if (osInfo.szCSDVersion[1] == 'C' || osInfo.szCSDVersion[1] == 'B') strcat(info->system, " OSR2"); } else if (osInfo.dwMinorVersion == 10) { strcpy(info->system, "Windows 98"); if (osInfo.szCSDVersion[1] == 'A') strcat(info->system, " SE"); } else if (osInfo.dwMinorVersion == 90) strcpy(info->system, "Windows Me"); break; case VER_PLATFORM_WIN32_NT: if (osInfo.dwMajorVersion <= 4) sprintf(info->system, "Windows NT %d.%d %s (Build %d)", osInfo.dwMajorVersion, osInfo.dwMinorVersion, osInfo.szCSDVersion, osInfo.dwBuildNumber); else if (osInfo.dwMajorVersion == 5) if (osInfo.dwMinorVersion == 0) sprintf(info->system, "Windows 2000 %s (Build %d)", osInfo.szCSDVersion, osInfo.dwBuildNumber & 0xffff); else sprintf(info->system, "Windows XP %s (Build %d)", osInfo.szCSDVersion, osInfo.dwBuildNumber & 0xffff); break; } strcpy(info->beServed, "BeServed 1.2.6"); info->cpus = systemInfo.dwNumberOfProcessors; info->maxConnections = BT_MAX_THREADS; switch (systemInfo.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_MIPS: strcpy(info->platform, "MIPS"); break; case PROCESSOR_ARCHITECTURE_ALPHA: strcpy(info->platform, "DEC Alpha"); break; case PROCESSOR_ARCHITECTURE_PPC: strcpy(info->platform, "PowerPC"); break; case PROCESSOR_ARCHITECTURE_INTEL: strcpy(info->platform, "Intel x86"); break; default: strcpy(info->platform, "Unknown"); } // Delay all new session creation. beginReading(&sessionData); info->connections = 0; for (s = rootSession; s; s = s->next) if (s->socket != INVALID_SOCKET) info->connections++; info->connections = B_HOST_TO_LENDIAN_INT32(info->connections); endReading(&sessionData); } // getHostUsers() // int getHostUsers(char *buffer) { bt_session_t *s; char addr[20]; int len, bufSize; // Initialize the buffer to be empty. buffer[0] = 0; bufSize = 0; // Delay all new session creation. beginReading(&sessionData); for (s = rootSession; s; s = s->next) if (s->socket != INVALID_SOCKET) { uint8 *client_s_addr = (uint8 *) s->client_s_addr; sprintf(addr, "%d.%d.%d.%d", client_s_addr[0], client_s_addr[1], client_s_addr[2], client_s_addr[3]); len = strlen(buffer); strcpy(&buffer[len > 0 ? len + 1 : 0], addr); bufSize += len + 1; } endReading(&sessionData); buffer[bufSize++] = 0; return bufSize; } // initMimeMap() // void initMimeMap() { FILE *fp; bt_mime_mapping *map; char mimeLine[256]; int i, mimeLen; fp = fopen("BeServed-MimeMap", "r"); if (fp) { while (fgets(mimeLine, sizeof(mimeLine) - 1, fp)) { // Strip off the carriage return. mimeLine[strlen(mimeLine) - 1] = 0; // Create a new MIME map entry. map = (bt_mime_mapping *) malloc(sizeof(bt_mime_mapping)); if (!map) continue; map->next = mimeMap; mimeMap = map; // Grab the extension. for (i = 0; mimeLine[i] != ' '; i++) map->extension[i] = mimeLine[i]; map->extension[i] = 0; // Skip to the start of the MIME type. while (mimeLine[i] == ' ') i++; // Grab the MIME type. mimeLen = strlen(&mimeLine[i]); map->mimeType = (char *) malloc(mimeLen + 1); if (map->mimeType) strncpy(map->mimeType, &mimeLine[i], mimeLen + 1); } fclose(fp); } } void closeMimeMap() { bt_mime_mapping *map = mimeMap; while (map) { map = mimeMap->next; free(mimeMap->mimeType); free(mimeMap); mimeMap = map; } } void initShares() { FILE *fp; char buffer[512]; int i, length; for (i = 0; i < BT_MAX_FILE_SHARES; i++) { fileShares[i].name[0] = 0; fileShares[i].path[0] = 0; fileShares[i].used = false; fileShares[i].readOnly = true; fileShares[i].security = BT_AUTH_NONE; fileShares[i].rights = NULL; fileShares[i].next = NULL; } fp = fopen("BeServed-Settings", "r"); if (fp) { while (fgets(buffer, sizeof(buffer) - 1, fp)) { length = strlen(buffer); if (length <= 1 || buffer[0] == '#') continue; if (buffer[length - 1] == '\n') buffer[--length] = 0; if (strncmp(buffer, "share ", 6) == 0) getFileShare(buffer); else if (strncmp(buffer, "set ", 4) == 0) getShareProperty(buffer); else if (strncmp(buffer, "grant ", 6) == 0) getGrant(buffer); else if (strncmp(buffer, "authenticate ", 13) == 0) getAuthenticate(buffer); else if (strncmp(buffer, "printer ", 8) == 0) getPrinter(buffer); else if (strcmp(buffer, "preload") == 0) preload = true; } fclose(fp); } } void initPrinters() { int i; for (i = 0; i < BT_MAX_PRINTER_SHARES; i++) { sharedPrinters[i].printerName[0] = 0; sharedPrinters[i].deviceName[0] = 0; sharedPrinters[i].spoolDir[0] = 0; sharedPrinters[i].rights = NULL; sharedPrinters[i].security = BT_AUTH_NONE; sharedPrinters[i].used = false; sharedPrinters[i].killed = false; } } void loadShares() { int i; if (preload) for (i = 0; i < BT_MAX_FILE_SHARES; i++) if (fileShares[i].used) loadFolder(fileShares[i].path); } void getFileShare(const char *buffer) { struct _stat st; char path[B_PATH_NAME_LENGTH], share[MAX_NAME_LENGTH + 1], *folder; int i, tok; // Skip over SHARE command. tokPtr = (char *) buffer + (6 * sizeof(char)); tok = getToken(); if (tok != BT_TOKEN_STRING) return; strcpy(path, tokBuffer); tok = getToken(); if (tok != BT_TOKEN_AS) return; tok = getToken(); if (tok != BT_TOKEN_STRING) return; strcpy(share, tokBuffer); // Now verify that the share name specified has not already been // used to share another path. folder = btGetSharePath(share); if (folder) { winService->LogEvent(EVENTLOG_WARNING_TYPE, EVMSG_DUPLICATE_SHARE, share); return; } // Check the path to ensure its validity. if (_stat(path, &st) != 0) { winService->LogEvent(EVENTLOG_WARNING_TYPE, EVMSG_INVALID_SHARE_PATH, path); return; } for (i = 0; i < BT_MAX_FILE_SHARES; i++) if (!fileShares[i].used) { strcpy(fileShares[i].name, share); strcpy(fileShares[i].path, path); fileShares[i].used = true; return; } winService->LogEvent(EVENTLOG_WARNING_TYPE, EVMSG_TOO_MANY_SHARES, share); } void getShareProperty(const char *buffer) { char share[B_FILE_NAME_LENGTH + 1]; int tok, shareId; // Skip over SET command. tokPtr = (char *) buffer + (4 * sizeof(char)); tok = getToken(); if (tok != BT_TOKEN_STRING) return; strcpy(share, tokBuffer); // Get the index of the share referred to. If the named share cannot be // found, then abort. shareId = btGetShareId(share); if (shareId < 0) return; tok = getToken(); if (tok == BT_TOKEN_READWRITE) fileShares[shareId].readOnly = false; } void getGrant(const char *buffer) { char share[MAX_NAME_LENGTH + 1]; int tok, rights; bool isGroup = false; // Skip over GRANT command. tokPtr = (char *) buffer + (6 * sizeof(char)); rights = 0; do { tok = getToken(); if (tok == BT_TOKEN_READ) { rights |= BT_RIGHTS_READ; tok = getToken(); } else if (tok == BT_TOKEN_WRITE) { rights |= BT_RIGHTS_WRITE; tok = getToken(); } else if (tok == BT_TOKEN_PRINT) { rights |= BT_RIGHTS_PRINT; tok = getToken(); } } while (tok == BT_TOKEN_COMMA); if (tok != BT_TOKEN_ON) return; tok = getToken(); if (tok != BT_TOKEN_STRING) return; strcpy(share, tokBuffer); tok = getToken(); if (tok != BT_TOKEN_TO) return; tok = getToken(); if (tok == BT_TOKEN_GROUP) { isGroup = true; tok = getToken(); } if (tok != BT_TOKEN_STRING) return; addUserRights(share, tokBuffer, rights, isGroup); } void getAuthenticate(const char *buffer) { int i, tok; // Skip over AUTHENTICATE command. tokPtr = (char *) buffer + (13 * sizeof(char)); tok = getToken(); if (tok != BT_TOKEN_WITH) return; tok = getToken(); if (tok != BT_TOKEN_STRING) return; // Loop up address for given host. getAuthServerAddress(tokBuffer); for (i = 0; i < BT_MAX_FILE_SHARES; i++) fileShares[i].security = BT_AUTH_BESURE; for (i = 0; i < BT_MAX_PRINTER_SHARES; i++) sharedPrinters[i].security = BT_AUTH_BESURE; } bool getAuthServerAddress(const char *name) { // Look up address for given host. struct hostent *ent = gethostbyname(name); if (ent == NULL) { unsigned long addr = inet_addr(tokBuffer); authServerIP = ntohl(addr); } else authServerIP = ntohl(*((unsigned int *) ent->h_addr)); strcpy(authServerName, name); return true; } void addUserRights(char *share, char *user, int rights, bool isGroup) { bt_printer *printer; bt_user_rights *ur; bool isPrinter = false; int shareId; // Now make sure that the rights make sense. If we're granting the // right to print, we should not have granted the right to read or write. // We should also be working exclusively with a printer. if (rights & BT_RIGHTS_PRINT) { if (rights & BT_RIGHTS_READ || rights & BT_RIGHTS_WRITE) return; printer = btFindPrinter(share); if (!printer) return; isPrinter = true; } else { shareId = btGetShareId(share); if (shareId < 0) return; } // Allocate a new user rights structure, populate it, and attach it to // either a file share or printer. ur = (bt_user_rights *) malloc(sizeof(bt_user_rights)); if (ur) { ur->user = (char *) malloc(strlen(user) + 1); if (ur->user) { strcpy(ur->user, user); ur->rights = rights; ur->isGroup = isGroup; if (isPrinter) { ur->next = printer->rights; printer->rights = ur; } else { ur->next = fileShares[shareId].rights; fileShares[shareId].rights = ur; } } else free(ur); } } void getPrinter(const char *buffer) { bt_printer printer; DWORD threadId; int i, tok; // Skip over PRINTER command. tokPtr = (char *) buffer + (8 * sizeof(char)); // Now get the name this printer will be shared as. tok = getToken(); if (tok != BT_TOKEN_STRING) return; strcpy(printer.printerName, tokBuffer); // Bypass the IS and TYPE keywords. tok = getToken(); if (tok != BT_TOKEN_IS) return; tok = getToken(); if (tok != BT_TOKEN_TYPE) return; // Get the device type of the printer. tok = getToken(); if (tok != BT_TOKEN_STRING) return; strcpy(printer.deviceType, tokBuffer); // Bypass the DEVICE keyword. tok = getToken(); if (tok != BT_TOKEN_DEVICE) return; // Get the system device name of the printer. tok = getToken(); if (tok != BT_TOKEN_STRING) return; strcpy(printer.deviceName, tokBuffer); // Bypass the SPOOLED TO keywords. tok = getToken(); if (tok != BT_TOKEN_SPOOLED) return; tok = getToken(); if (tok != BT_TOKEN_TO) return; // Get the spooling folder, where temporary files will be stored. tok = getToken(); if (tok != BT_TOKEN_STRING) return; strcpy(printer.spoolDir, tokBuffer); for (i = 0; i < BT_MAX_PRINTER_SHARES; i++) if (!sharedPrinters[i].used) { sharedPrinters[i].used = true; strcpy(sharedPrinters[i].printerName, printer.printerName); strcpy(sharedPrinters[i].deviceType, printer.deviceType); strcpy(sharedPrinters[i].deviceName, printer.deviceName); strcpy(sharedPrinters[i].spoolDir, printer.spoolDir); sharedPrinters[i].handlerID = CreateThread(NULL, 0, printerThread, (void *) &sharedPrinters[i], 0, &threadId); break; } } int getToken() { bool quoted = false; tokBuffer[0] = 0; while (*tokPtr && iswhite(*tokPtr)) tokPtr++; if (*tokPtr == ',') { *tokPtr++; return BT_TOKEN_COMMA; } else if (*tokPtr == '\"') { quoted = true; tokPtr++; } if (isalnum(*tokPtr) || *tokPtr == '\\') { int i = 0; while (isalnum(*tokPtr) || isValid(*tokPtr) || (quoted && *tokPtr == ' ')) if (i < MAX_NAME_LENGTH) tokBuffer[i++] = *tokPtr++; else tokPtr++; tokBuffer[i] = 0; if (!quoted) for (i = 0; keywords[i]; i++) if (stricmp(tokBuffer, keywords[i]) == 0) return ++i; if (quoted) if (*tokPtr != '\"') return BT_TOKEN_ERROR; else tokPtr++; return BT_TOKEN_STRING; } return BT_TOKEN_ERROR; } void startService() { struct sockaddr_in serverAddr, clientAddr; int client, addrLen; char flags; // Store the length of the socket addressing structure for accept(). addrLen = sizeof(struct sockaddr_in); // Initialize the server address structure. memset(&serverAddr, 0, sizeof(serverAddr)); serverAddr.sin_port = htons(BT_TCPIP_PORT); serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); // Create a new socket to receive incoming requests. server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (server == INVALID_SOCKET) return; // Set the socket option to reuse the current address in case it was // in use by a prior version of the service that has not yet relinquished // the socket. flags = 1; setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags)); // Bind that socket to the address constructed above. if (bind(server, (struct sockaddr *) &serverAddr, sizeof(serverAddr))) return; // Listen for incoming connections. if (listen(server, 5)) return; // Continually accept incoming connections. When one is found, // fire off a handler thread to accept commands. while (running) { client = accept(server, (struct sockaddr *) &clientAddr, &addrLen); if (client != INVALID_SOCKET) launchThread(client, &clientAddr); } // Close the socket. Technically, I believe we should call shutdown() // first, but the BeOS header file socket.h indicates that this // function is not currently working. It is present but may not have // any effect. shutdown(server, 2); closesocket(server); server = INVALID_SOCKET; } void endService(int sig) { WSACleanup(); TerminateThread(hostThread, 0); closeManagedData(&sessionData); closeManagedData(&handleData); closePrinters(); closeMimeMap(); freeFileShares(); ubi_trKillTree(&vnidTree, KillNode); ubi_trKillTree(&nameTree, KillNode); signal(SIGINT, SIG_DFL); signal(SIGTERM, SIG_DFL); } void closePrinters() { int i; // Close down shared printer spooling threads. for (i = 0; i < BT_MAX_PRINTER_SHARES; i++) if (sharedPrinters[i].used) { sharedPrinters[i].killed = true; waitForThread(sharedPrinters[i].handlerID); } } // waitForThread() // void waitForThread(HANDLE threadId) { DWORD exitCode; while (true) { // Get the exit code of the thread. If the function fails, the // thread is invalid and thus already gone. if (!GetExitCodeThread(threadId, &exitCode)) break; // If we have an exit code, the thread isn't running. if (exitCode != STILL_ACTIVE) break; // Otherwise, wait and retry. Sleep(100); } } // freeFileShares() // void freeFileShares() { bt_user_rights *ur, *nextUr; int i; for (i = 0; i < BT_MAX_FILE_SHARES; i++) for (ur = fileShares[i].rights; ur; ) { nextUr = ur->next; if (ur->user) free(ur->user); free(ur); ur = nextUr; } } // launchThread() // void launchThread(int client, struct sockaddr_in *addr) { bt_session_t *s, *cur, *last = NULL; DWORD threadId; int count = 0; // First verify that the server's not too busy by scanning the list of active // sessions. This is also useful because we need to eliminate unused sessions // from the list, i.e., sessions that have closed. beginWriting(&sessionData); s = rootSession; while (s) { if (s->socket == INVALID_SOCKET) { if (last) last->next = s->next; else rootSession = s->next; cur = s->next; free(s); s = cur; continue; } last = s; s = s->next; count++; } // If the total number of valid sessions was less than our allowed maximum, then // we can create a new session. if (count < BT_MAX_THREADS) { // We need to create an available session for this connection. bt_session_t *session = (bt_session_t *) malloc(sizeof(bt_session_t)); if (session) { session->socket = client; session->client_s_addr = addr->sin_addr.s_addr; session->rootBlock = NULL; session->killed = false; session->rights = 0; session->handlerID = CreateThread(NULL, 0, requestThread, (void *) session, 0, &threadId); // Add this to the session list. session->next = rootSession; rootSession = session; endWriting(&sessionData); return; } } endWriting(&sessionData); // We must have too many threads active, so let the client know we're busy. sendErrorToClient(client, 0, EBUSY); shutdown(client, 2); closesocket(client); } DWORD WINAPI requestThread(LPVOID data) { bt_session_t *session = (bt_session_t *) data; if (!session) return 0; session->blockSem = CreateSemaphore(NULL, 1, 1, NULL); if (session->blockSem) { session->rootBlock = NULL; while (!session->killed && receiveRequest(session)); CloseHandle(session->blockSem); } shutdown(session->socket, 2); closesocket(session->socket); session->socket = INVALID_SOCKET; return 0; } int receiveRequest(bt_session_t *session) { bt_inPacket packet; char signature[20], *buffer; unsigned char command; int client, sigLen; int32 length; client = session->socket; // Read the BeTalk RPC header. sigLen = strlen(BT_RPC_SIGNATURE); if (btRecvMsg(client, signature, sigLen, 0) == -1) return 0; // recv(client, &verHi, sizeof(verHi), 0); // recv(client, &verLo, sizeof(verLo), 0); signature[sigLen] = 0; if (strcmp(signature, BT_RPC_SIGNATURE)) return 0; // Read in the rest of the packet. if (btRecvMsg(client, (char *) &length, sizeof(int32), 0) == -1) return 0; length = B_LENDIAN_TO_HOST_INT32(length); if (length == 0 || length > BT_RPC_MAX_PACKET_SIZE) return 0; buffer = (char *) malloc(length + 1); if (!buffer) return 0; if (btRecvMsg(client, buffer, length, 0) == -1) { free(buffer); return 0; } buffer[length] = 0; packet.buffer = buffer; packet.length = length; packet.offset = 0; // Read the transmission ID and command. command = btRPCGetChar(&packet); getArguments(session, &packet, command); free(buffer); return (command != BT_CMD_QUIT && command != BT_CMD_PREMOUNT); } void getArguments(bt_session_t *session, bt_inPacket *packet, unsigned char command) { bt_arg_t args[MAX_COMMAND_ARGS]; int i, client; bool error; unsigned char argc, terminator; int32 xid; error = false; client = session->socket; argc = btRPCGetChar(packet); if (argc > MAX_COMMAND_ARGS) return; for (i = 0; i < argc && !error; i++) { args[i].type = btRPCGetInt32(packet); args[i].data = btRPCGetNewString(packet); if (args[i].data == NULL) error = true; } if (!error) { xid = btRPCGetInt32(packet); terminator = btRPCGetChar(packet); if (terminator == BT_CMD_TERMINATOR) handleRequest(session, xid, command, argc, args); } while (--i >= 0) free(args[i].data); } void handleRequest(bt_session_t *session, unsigned int xid, unsigned char command, int argc, bt_arg_t argv[]) { bool validated = true; int i, j; for (i = 0; dirCommands[i].handler; i++) if (command == dirCommands[i].command) { // We may have received a valid command, but one that is not supported by this // server. In this case, we'll want to return an operation not supported error, // as opposed to an invalid command error. if (!dirCommands[i].supported) { sendErrorToClient(session->socket, xid, ENOTSUP); return; } // Now verify that the argument count is correct, and if so, the type of all // arguments is correct. If not, an invalid command error is returned. // Otherise, the command is executed, and the handler returns any necessary // acknowledgement. if (argc == dirCommands[i].args) { for (j = 0; j < argc; j++) if (dirCommands[i].argTypes[j] != argv[j].type) { validated = false; break; } if (validated) { (*dirCommands[i].handler)(session, xid, argc, argv); return; } } } sendErrorToClient(session->socket, xid, EINVAL); } void sendErrorToClient(int client, unsigned int xid, int error) { bt_outPacket packet; btRPCCreateAck(&packet, xid, error); btRPCSendAck(client, &packet); } // btRecvMsg() // int btRecvMsg(int sock, void *data, int dataLen, int flags) { int bytesRead = 0; do { int bytes = btRecv(sock, (char *) data + bytesRead, dataLen - bytesRead, flags); if (bytes == -1) return -1; bytesRead += bytes; } while (bytesRead < dataLen); return bytesRead; } // btRecv() // int btRecv(int sock, void *data, int dataLen, int flags) { int bytes; for (;;) { bytes = recv(sock, (char *) data, dataLen, flags); if (bytes == 0) return -1; else if (bytes == -1) if (errno == EINTR) continue; else return -1; else break; } return bytes; } // btSendMsg() // int btSendMsg(int sock, void *data, int dataLen, int flags) { int bytesSent = 0; do { int bytes = btSend(sock, (char *) data + bytesSent, dataLen - bytesSent, flags); if (bytes == -1) return -1; bytesSent += bytes; } while (bytesSent < dataLen); return bytesSent; } // btSend() // int btSend(int sock, void *data, int dataLen, int flags) { int bytes; for (;;) { bytes = send(sock, (char *) data, dataLen, flags); if (bytes == -1) if (errno == EINTR) continue; else return -1; else break; } return bytes; } uint32 btSwapInt32(uint32 num) { uint8 byte; union { uint32 value; uint8 bytes[4]; } convert; convert.value = num; byte = convert.bytes[0]; convert.bytes[0] = convert.bytes[3]; convert.bytes[3] = byte; byte = convert.bytes[1]; convert.bytes[1] = convert.bytes[2]; convert.bytes[2] = byte; return convert.value; } uint64 btSwapInt64(uint64 num) { uint8 byte; union { uint64 value; uint8 bytes[8]; } convert; convert.value = num; byte = convert.bytes[0]; convert.bytes[0] = convert.bytes[7]; convert.bytes[7] = byte; byte = convert.bytes[1]; convert.bytes[1] = convert.bytes[6]; convert.bytes[6] = byte; byte = convert.bytes[2]; convert.bytes[2] = convert.bytes[5]; convert.bytes[5] = byte; byte = convert.bytes[3]; convert.bytes[3] = convert.bytes[4]; convert.bytes[4] = byte; return convert.value; } void btRPCCreateAck(bt_outPacket *packet, unsigned int xid, int error) { packet->size = BT_RPC_MIN_PACKET_SIZE; packet->buffer = (char *) malloc(packet->size); packet->length = 0; if (!packet->buffer) return; strcpy(packet->buffer, BT_RPC_SIGNATURE); packet->length += strlen(BT_RPC_SIGNATURE); btRPCPutInt32(packet, xid); btRPCPutInt32(packet, 0); btRPCPutInt32(packet, error); } void btRPCSendAck(int client, bt_outPacket *packet) { if (packet) if (packet->buffer) { *(int32 *)(&packet->buffer[9]) = B_HOST_TO_LENDIAN_INT32(packet->length - 13); btSendMsg(client, packet->buffer, packet->length, 0); free(packet->buffer); } } unsigned char btRPCGetChar(bt_inPacket *packet) { unsigned char value; if (packet->offset < packet->length) value = (unsigned char) packet->buffer[packet->offset]; else value = 0; packet->offset += sizeof(value); return value; } unsigned int btRPCGetInt32(bt_inPacket *packet) { int32 value; if (packet->offset < packet->length) value = B_LENDIAN_TO_HOST_INT32(*((int32 *) &packet->buffer[packet->offset])); else value = 0; packet->offset += sizeof(value); return value; } int64 btRPCGetInt64(bt_inPacket *packet) { int64 value; if (packet->offset < packet->length) value = B_LENDIAN_TO_HOST_INT64(*((int64 *) &packet->buffer[packet->offset])); else value = 0; packet->offset += sizeof(value); return value; } char *btRPCGetNewString(bt_inPacket *packet) { char *str; unsigned int bytes; if (packet->offset >= packet->length) return NULL; bytes = B_LENDIAN_TO_HOST_INT32(*((int32 *) &packet->buffer[packet->offset])); packet->offset += sizeof(bytes); if (bytes < 0 || bytes > BT_MAX_IO_BUFFER) return NULL; str = (char *) malloc(bytes + 1); if (!str) return NULL; if (bytes > 0) memcpy(str, &packet->buffer[packet->offset], bytes); str[bytes] = 0; packet->offset += bytes; return str; } int btRPCGetString(bt_inPacket *packet, char *buffer, int length) { unsigned int bytes; if (packet->offset >= packet->length) return ERANGE; bytes = B_LENDIAN_TO_HOST_INT32(*((int32 *) &packet->buffer[packet->offset])); packet->offset += sizeof(bytes); if (bytes < 0 || bytes > BT_MAX_IO_BUFFER) return ERANGE; if (length < bytes) return ERANGE; if (bytes > 0) memcpy(buffer, &packet->buffer[packet->offset], bytes); packet->offset += bytes; return bytes; } void btRPCGrowPacket(bt_outPacket *packet, int bytes) { if (packet->length + bytes > packet->size) { int growth = ((bytes / BT_RPC_MIN_PACKET_SIZE) + 1) * BT_RPC_MIN_PACKET_SIZE; packet->buffer = (char *) realloc(packet->buffer, packet->size + growth); packet->size += growth; } } void btRPCPutChar(bt_outPacket *packet, char value) { btRPCGrowPacket(packet, sizeof(value)); packet->buffer[packet->length] = value; packet->length += sizeof(value); } void btRPCPutInt32(bt_outPacket *packet, int32 value) { btRPCGrowPacket(packet, sizeof(value)); *(int32 *)(&packet->buffer[packet->length]) = B_HOST_TO_LENDIAN_INT32(value); packet->length += sizeof(value); } void btRPCPutInt64(bt_outPacket *packet, int64 value) { btRPCGrowPacket(packet, sizeof(value)); *(int64 *)(&packet->buffer[packet->length]) = B_HOST_TO_LENDIAN_INT64(value); packet->length += sizeof(value); } void btRPCPutString(bt_outPacket *packet, char *buffer, int length) { if (packet && buffer) { btRPCGrowPacket(packet, sizeof(length) + length); btRPCPutInt32(packet, length); memcpy(&packet->buffer[packet->length], buffer, length); packet->length += length; } } void btRPCPutBinary(bt_outPacket *packet, void *buffer, int length) { if (packet && buffer) { btRPCGrowPacket(packet, length); memcpy(&packet->buffer[packet->length], buffer, length); packet->length += length; } } void btRPCGetStat(bt_inPacket *packet, beos_stat *st) { st->st_dev = 0; st->st_nlink = btRPCGetInt32(packet); st->st_uid = btRPCGetInt32(packet); st->st_gid = btRPCGetInt32(packet); st->st_size = (int32) btRPCGetInt64(packet); st->st_blksize = btRPCGetInt32(packet); st->st_rdev = btRPCGetInt32(packet); st->st_ino = (int32) btRPCGetInt64(packet); st->st_mode = btRPCGetInt32(packet); st->st_atime = btRPCGetInt32(packet); st->st_mtime = btRPCGetInt32(packet); st->st_ctime = btRPCGetInt32(packet); } void btRPCPutStat(bt_outPacket *packet, beos_stat *st) { if (packet && st) { int64 size = (int64) st->st_size; int64 inode = (int64) st->st_ino; btRPCPutInt32(packet, (int) st->st_nlink); btRPCPutInt32(packet, (int) st->st_uid); btRPCPutInt32(packet, (int) st->st_gid); btRPCPutInt64(packet, size); btRPCPutInt32(packet, (int) 1024); btRPCPutInt32(packet, (int) st->st_rdev); btRPCPutInt64(packet, inode); btRPCPutInt32(packet, (int) st->st_mode); btRPCPutInt32(packet, (int) st->st_atime); btRPCPutInt32(packet, (int) st->st_mtime); btRPCPutInt32(packet, (int) st->st_ctime); } } //////////////////////////////////////////////////////////////////// bt_node *btGetNodeFromVnid(vnode_id vnid) { return (bt_node *) ubi_trFind(&vnidTree, &vnid); } // btAddHandle() // void btAddHandle(vnode_id dir_vnid, vnode_id file_vnid, char *name) { bt_node *vnidNode, *nameNode, *dirNode; // We don't store the references to the current and the parent directory. if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) return; beginWriting(&handleData); // Obtain the parent node. If no parent vnid is provided, then this must be // the root node. The parent of the root node is NULL, but it should be the // only node for which this is true. if (dir_vnid) dirNode = btGetNodeFromVnid(dir_vnid); else dirNode = NULL; // If a node already exists with the given vnid, then it is either a symbolic // link or an attempt to add the same node again, such as when mounting or // walking a directory tree. If we find a matching vnid whose parent directory // and name also match, this is a duplicate and can be ignored. if (btGetNodeFromVnid(file_vnid)) { endWriting(&handleData); return; } // Allocate a new node for the vnid and name-based trees. A separate node must exist for // each tree or the tree structure will go haywire. vnidNode = (bt_node *) malloc(sizeof(bt_node)); if (vnidNode == NULL) { endWriting(&handleData); return; } nameNode = (bt_node *) malloc(sizeof(bt_node)); if (nameNode == NULL) { free(vnidNode); endWriting(&handleData); return; } // Allocate memory for the file name itself. This prevents huge memory consumption used by // a static buffer that assumes the worst case file name length. vnidNode->name = (char *) malloc(strlen(name) + 1); if (vnidNode->name == NULL) { free(nameNode); free(vnidNode); endWriting(&handleData); return; } // Copy the name into the allocated buffer. strcpy(vnidNode->name, name); nameNode->name = strdup(vnidNode->name); if (nameNode->name == NULL) { free(vnidNode->name); free(nameNode); free(vnidNode); endWriting(&handleData); return; } // Copy over the vnid, and parent node. vnidNode->invalid = nameNode->invalid = false; vnidNode->vnid = nameNode->vnid = file_vnid; vnidNode->parent = nameNode->parent = dirNode; // Now insert the new nodes into the tree. ubi_trInsert(&vnidTree, vnidNode, &vnidNode->vnid, NULL); ubi_trInsert(&nameTree, nameNode, nameNode, NULL); endWriting(&handleData); } // btRemoveHandle() // void btRemoveHandle(vnode_id vnid) { bt_node *deadVnidNode, *deadNameNode; beginWriting(&handleData); deadVnidNode = (bt_node *) ubi_trFind(&vnidTree, &vnid); if (deadVnidNode) { ubi_trRemove(&vnidTree, deadVnidNode); deadNameNode = (bt_node *) ubi_trFind(&nameTree, deadVnidNode); if (deadNameNode) ubi_trRemove(&nameTree, deadNameNode); } endWriting(&handleData); } // btPurgeNodes() // void btPurgeNodes(vnode_id vnid) { bt_node *curNode; ubi_trNodePtr cur, next; ubi_trRootPtr tree; ubi_trRootPtr trees[] = { &vnidTree, &nameTree, NULL }; int i; beginWriting(&handleData); // First loop through, marking this node and all its children as invalid. for (i = 0, tree = trees[i]; trees[i]; i++) { cur = ubi_trFirst(tree->root); while (cur) { next = ubi_trNext(cur); curNode = (bt_node *) cur; if (curNode->vnid == vnid || btIsAncestorNode(vnid, curNode)) curNode->invalid = true; cur = next; } // Now loop through again, removing all invalid nodes. This prevents removing // a parent node and all its children being orphaned (with invalid pointers // back to the destroyed parent). cur = ubi_trFirst(tree->root); while (cur) { next = ubi_trNext(cur); curNode = (bt_node *) cur; if (curNode->invalid) { ubi_trRemove(&vnidTree, curNode); free(curNode); } cur = next; } } endWriting(&handleData); } // btIsAncestorNode() // bool btIsAncestorNode(vnode_id vnid, bt_node *node) { bt_node *curNode = node->parent; while (curNode) { if (curNode->vnid == vnid) return true; curNode = curNode->parent; } return false; } // btGetLocalFileName() // char *btGetLocalFileName(char *path, vnode_id vnid) { bt_node *node, *nodeStack[100]; int stackSize; path[0] = 0; stackSize = 1; beginReading(&handleData); node = btGetNodeFromVnid(vnid); if (node == NULL) { endReading(&handleData); return NULL; } nodeStack[0] = node; while ((node = node->parent) != NULL) nodeStack[stackSize++] = node; while (--stackSize >= 0) { strcat(path, nodeStack[stackSize]->name); if (stackSize) { int length = strlen(path); if (length > 0 && path[length - 1] != '\\') strcat(path, "\\"); } } endReading(&handleData); return path; } bt_node *btFindNode(bt_node *parent, char *fileName) { bt_node search, *node; // Initialize the node for tree searching purposes. search.parent = parent; search.name = strdup(fileName); if (search.name == NULL) return NULL; beginReading(&handleData); node = (bt_node *) ubi_trFind(&nameTree, &search); endReading(&handleData); free(search.name); return node; } char *btGetSharePath(char *shareName) { int i; for (i = 0; i < BT_MAX_FILE_SHARES; i++) if (fileShares[i].used) if (stricmp(fileShares[i].name, shareName) == 0) return fileShares[i].path; return NULL; } int btGetShareId(char *shareName) { int i; for (i = 0; i < BT_MAX_FILE_SHARES; i++) if (fileShares[i].used) if (stricmp(fileShares[i].name, shareName) == 0) return i; return -1; } int btGetShareIdByPath(char *path) { int i; for (i = 0; i < BT_MAX_FILE_SHARES; i++) if (fileShares[i].used) if (stricmp(fileShares[i].path, path) == 0) return i; return -1; } // btFindPrinter() // bt_printer *btFindPrinter(char *printerName) { int i; for (i = 0; i < BT_MAX_PRINTER_SHARES; i++) if (sharedPrinters[i].used) if (stricmp(printerName, sharedPrinters[i].printerName) == 0) return &sharedPrinters[i]; return NULL; } void btGetRootPath(vnode_id vnid, char *path) { bt_node *curNode; beginReading(&handleData); curNode = btGetNodeFromVnid(vnid); while (curNode && curNode->parent) curNode = curNode->parent; if (curNode) strcpy(path, curNode->name); else path[0] = 0; endReading(&handleData); } uint32 btGetWinInode(const char *path) { const int MAX_FOLDER_NESTING = 100; char *folders[MAX_FOLDER_NESTING + 1]; char newPath[B_PATH_NAME_LENGTH + 1]; int i, level, len, charSum; // Subdivide the path into its components. char *p, *s = strdup(path); level = 0; folders[level++] = s; for (p = s; *p; p++) if (*p == '\\') { folders[level++] = p + 1; *p = 0; } folders[level] = 0; // Now look through the folders, to see if any are . and .. references. for (i = 0; i < level; i++) if (*folders[i]) if (strcmp(folders[i], ".") == 0) folders[i] = NULL; else if (strcmp(folders[i], "..") == 0) { int j = i; folders[i] = 0; while (j > 0 && folders[j] == NULL) j--; if (j >= 0) folders[j] = 0; } // Now reconstruct the path without the folders eliminated above. newPath[0] = 0; for (i = 0; i < level; i++) if (folders[i]) { strcat(newPath, folders[i]); if (i < level - 1) strcat(newPath, "\\"); } // If we eliminated folders at the end of the path, the level will have // resulted in a trailing backslash. len = strlen(newPath); if (newPath[len - 1] == '\\') newPath[--len] = 0; // Now compute the checksum, i.e., inode number, using the revised path. free(s); p = newPath; for (charSum = len = 0; *p; p++, len++) charSum += (*p * len); return ((len << 24) + charSum); } int btGetBeosStat(char *fileName, beos_stat *st) { struct _stat _st; if (_stat(fileName, &_st) != 0) return BEOS_ENOENT; st->st_atime = _st.st_atime; st->st_blksize = 1024; st->st_ctime = _st.st_ctime; st->st_dev = 0; st->st_gid = 0; st->st_uid = 0; st->st_ino = btGetWinInode(fileName); st->st_mode = _st.st_mode; st->st_mtime = _st.st_mtime; st->st_nlink = 0; st->st_rdev = 0; st->st_size = _st.st_size; return B_OK; } void btMakePath(char *path, char *dir, char *file) { int length; strcpy(path, dir); length = strlen(path); if (length > 0) if (path[length - 1] != '\\') strcat(path, "\\"); strcat(path, file); } //////////////////////////////////////////////////////////////////// int btPreMount(bt_session_t *session, char *shareName) { // Look for the specified share name. If it can't be found, check to see if it's // a printer. If not, then there is no such resource available on this host. int shareId = btGetShareId(shareName); if (shareId < 0) { bt_printer *printer = btFindPrinter(shareName); if (!printer) return BEOS_ENOENT; return printer->security; } return fileShares[shareId].security; } int btMount(bt_session_t *session, char *shareName, char *user, char *password, vnode_id *vnid) { bt_user_rights *ur; struct stat st; char *path, *groups[MAX_GROUPS_PER_USER]; int i, shareId; bool authenticated = false; // Initialize the groups array. We may need to release the memory later. for (i = 0; i < MAX_GROUPS_PER_USER; i++) groups[i] = NULL; // Look for the specified share name. If it can't be found, it must no longer be // shared on this host. shareId = btGetShareId(shareName); if (shareId < 0) return BEOS_ENOENT; if (fileShares[shareId].security != BT_AUTH_NONE) { // Authenticate the user with name/password. authenticated = authenticateUser(user, password); if (!authenticated) return BEOS_EACCES; // Does the authenticated user have any rights on this file share? session->rights = 0; for (ur = fileShares[shareId].rights; ur; ur = ur->next) if (!ur->isGroup && stricmp(ur->user, user) == 0) session->rights |= ur->rights; getUserGroups(user, groups); for (ur = fileShares[shareId].rights; ur; ur = ur->next) if (ur->isGroup) for (i = 0; i < MAX_GROUPS_PER_USER; i++) if (groups[i] && stricmp(ur->user, groups[i]) == 0) { session->rights |= ur->rights; break; } // Free the memory occupied by the group list. for (i = 0; i < MAX_GROUPS_PER_USER; i++) if (groups[i]) free(groups[i]); // If no rights have been granted, deny access. if (session->rights == 0) return BEOS_EACCES; // If write access has been globally disabled, this user's rights must be // correspondingly synchronized. if (fileShares[shareId].readOnly) session->rights = BT_RIGHTS_READ; } else session->rights = fileShares[shareId].readOnly ? BT_RIGHTS_READ : BT_RIGHTS_READ | BT_RIGHTS_WRITE; // Make sure the folder we want to share still exists. path = fileShares[shareId].path; if (stat(path, &st) != 0) return BEOS_ENOENT; if (!S_ISDIR(st.st_mode)) return BEOS_EACCES; // Mark this session as owned by this user. strcpy(session->user, user); return B_OK; } int btGetFSInfo(fs_info *fsInfo, char *path) { DWORD secsPerClstr, bytesPerSec, freeClstrs, totalClstrs; char rootDir[5]; // We only want the root directory specification, not the entire path. strncpy(rootDir, path, 3); rootDir[3] = 0; if (GetDiskFreeSpace(rootDir, &secsPerClstr, &bytesPerSec, &freeClstrs, &totalClstrs)) { fsInfo->block_size = bytesPerSec; fsInfo->total_blocks = secsPerClstr * totalClstrs; fsInfo->free_blocks = secsPerClstr * freeClstrs; return B_OK; } return ENOTSUP; } int btLookup(char *pathBuf, vnode_id dir_vnid, char *fileName, vnode_id *file_vnid) { struct _stat st; if (_stat(fileName, &st) != 0) return BEOS_ENOENT; return B_OK; } int btStat(char *pathBuf, vnode_id vnid, beos_stat *st) { char *fileName; int error; fileName = btGetLocalFileName(pathBuf, vnid); if (fileName) { error = btGetBeosStat(fileName, st); return error; } return BEOS_ENOENT; } int btReadDir(char *pathBuf, vnode_id dir_vnid, long **dir, vnode_id *file_vnid, char *filename, beos_stat *st) { struct _finddata_t fileInfo; char *folder, path[B_PATH_NAME_LENGTH]; long result = -1; if (dir_vnid == 0 || !file_vnid || !filename) return EINVAL; if (!*dir) { folder = btGetLocalFileName(pathBuf, dir_vnid); if (folder) { char search[B_PATH_NAME_LENGTH]; btMakePath(search, folder, "*.*"); result = _findfirst(search, &fileInfo); *dir = (long *) malloc(sizeof(long *)); memcpy(*dir, &result, sizeof(result)); } } else result = _findnext((long) **dir, &fileInfo); if (result != -1) { folder = btGetLocalFileName(pathBuf, dir_vnid); if (folder) { btMakePath(path, folder, fileInfo.name); if (btGetBeosStat(path, st) != 0) return BEOS_ENOENT; strcpy(filename, fileInfo.name); *file_vnid = (vnode_id) st->st_ino; btAddHandle(dir_vnid, *file_vnid, filename); return B_OK; } } else if (*dir) { _findclose((long) **dir); return BEOS_ENOENT; } return EINVAL; } int32 btRead(char *pathBuf, vnode_id vnid, beos_off_t pos, int32 len, char *buffer) { char *path; int bytes; path = btGetLocalFileName(pathBuf, vnid); if (path) { FILE *fp = fopen(path, "rb"); if (!fp) return EACCES; fseek(fp, (int) pos, SEEK_SET); bytes = fread(buffer, 1, len, fp); fclose(fp); buffer[bytes] = 0; return bytes; } return 0; } int32 btWrite(bt_session_t *session, vnode_id vnid, beos_off_t pos, int32 len, int32 totalLen, char *buffer) { bt_block *block; // If we've been given a total length, then we have a new buffered write // session coming. A block will need to be allocated. if (totalLen > 0) { // Make sure we don't have a wildly inaccurate total length to allocate. if (totalLen > 10 * 1024 * 1024) return 0; // Allocate a new buffered I/O block. block = (bt_block *) malloc(sizeof(bt_block)); if (block) { block->vnid = vnid; block->pos = pos; block->len = totalLen; block->count = 0; block->buffer = (char *) malloc(totalLen + 1); if (!block->buffer) { free(block); return 0; } btInsertWriteBlock(session, block); } else return 0; } else { block = btGetWriteBlock(session, vnid); if (!block) return 0; } memcpy(block->buffer + block->count, buffer, len); block->count += len; return len; } // btGetWriteBlock() // bt_block *btGetWriteBlock(bt_session_t *session, vnode_id vnid) { bt_block *block; WaitForSingleObject(session->blockSem, INFINITE); block = session->rootBlock; while (block && block->vnid != vnid) block = block->next; ReleaseSemaphore(session->blockSem, 1, NULL); return block; } // btInsertWriteBlock() // void btInsertWriteBlock(bt_session_t *session, bt_block *block) { WaitForSingleObject(session->blockSem, INFINITE); block->next = session->rootBlock; block->prev = NULL; if (session->rootBlock) session->rootBlock->prev = block; session->rootBlock = block; ReleaseSemaphore(session->blockSem, 1, NULL); } int btCommit(bt_session_t *session, vnode_id vnid) { bt_block *block; char *path; int file; // Get the full path for the specified file. path = btGetLocalFileName(session->pathBuffer, vnid); if (!path) return BEOS_ENOENT; // Obtain the buffered I/O block. If one can't be found, no buffered I/O // session was started for this vnode. block = btGetWriteBlock(session, vnid); if (!block) return BEOS_ENOENT; // Open the file for writing. file = _open(path, _O_WRONLY | _O_CREAT | _O_BINARY); if (file < 0) return errno; WaitForSingleObject(session->blockSem, INFINITE); // Write the data. _lseek(file, (int32) block->pos, SEEK_SET); _write(file, block->buffer, block->len); btRemoveWriteBlock(session, block); ReleaseSemaphore(session->blockSem, 1, NULL); _close(file); return B_OK; } void btRemoveWriteBlock(bt_session_t *session, bt_block *block) { // If we're removing the root, then adjust the root block pointer. if (session->rootBlock == block) session->rootBlock = block->next; // If there's a previous block, it should now point beyond this block. if (block->prev) block->prev->next = block->next; // If there's a next block, it hsould now point to the current predecessor. if (block->next) block->next->prev = block->prev; // Release the memory used by this block. free(block->buffer); free(block); } int btCreate(char *pathBuf, vnode_id dir_vnid, char *name, int omode, int perms, vnode_id *file_vnid) { beos_stat st; char path[B_PATH_NAME_LENGTH], *folder; int fh; folder = btGetLocalFileName(pathBuf, dir_vnid); if (folder) { btMakePath(path, folder, name); fh = open(path, O_WRONLY | O_CREAT | O_TRUNC, _S_IREAD | _S_IWRITE); if (fh == -1) return errno; else { close(fh); if (btGetBeosStat(path, &st) == 0) { *file_vnid = (vnode_id) st.st_ino; btAddHandle(dir_vnid, *file_vnid, name); } else return BEOS_EACCES; } } return B_OK; } int btTruncate(char *pathBuf, vnode_id vnid, int64 len) { char *path; path = btGetLocalFileName(pathBuf, vnid); if (path) { FILE *fp = fopen(path, "w"); fclose(fp); return B_OK; } return BEOS_EACCES; } // btCreateDir() // int btCreateDir(char *pathBuf, vnode_id dir_vnid, char *name, int perms, vnode_id *file_vnid, beos_stat *st) { char path[B_PATH_NAME_LENGTH], *folder; folder = btGetLocalFileName(pathBuf, dir_vnid); if (folder) { btMakePath(path, folder, name); if (_mkdir(path) == -1) return errno; if (btGetBeosStat(path, st) != 0) return BEOS_ENOENT; *file_vnid = (vnode_id) st->st_ino; btAddHandle(dir_vnid, *file_vnid, name); return B_OK; } return BEOS_ENOENT; } // btDeleteDir() // int btDeleteDir(char *pathBuf, vnode_id vnid, char *name) { struct _stat st; char path[B_PATH_NAME_LENGTH], *folder; folder = btGetLocalFileName(pathBuf, vnid); if (folder) { btMakePath(path, folder, name); if (_stat(path, &st) != 0) return errno; if (_rmdir(path) == -1) return errno; btPurgeNodes(btGetWinInode(path)); return B_OK; } return BEOS_ENOENT; } // btRename() // int btRename(char *pathBuf, vnode_id old_vnid, char *oldName, vnode_id new_vnid, char *newName) { struct _stat st; char oldPath[B_PATH_NAME_LENGTH], newPath[B_PATH_NAME_LENGTH], *oldFolder, *newFolder; oldFolder = btGetLocalFileName(pathBuf, old_vnid); if (oldFolder) { btMakePath(oldPath, oldFolder, oldName); newFolder = btGetLocalFileName(pathBuf, new_vnid); if (newFolder) { btMakePath(newPath, newFolder, newName); if (_stat(oldPath, &st) != 0) return errno; btPurgeNodes(btGetWinInode(oldPath)); if (rename(oldPath, newPath) == -1) return errno; return B_OK; } } return BEOS_ENOENT; } // btUnlink() // int btUnlink(char *pathBuf, vnode_id vnid, char *name) { struct _stat st; char path[B_PATH_NAME_LENGTH], *folder; int error; folder = btGetLocalFileName(pathBuf, vnid); if (folder) { btMakePath(path, folder, name); // Obtain the inode (vnid) of the specified file through stat(). if (_stat(path, &st) != 0) return errno; // Construct a dummy file descriptor and cause it to be removed from // the list. btRemoveHandle(btGetWinInode(path)); error = unlink(path); return (error == -1 ? errno : B_OK); } return BEOS_EACCES; } int btReadLink(char *pathBuf, vnode_id vnid, char *buffer, int length) { return BEOS_ENOENT; } int btSymLink(char *pathBuf, vnode_id vnid, char *name, char *dest) { return BEOS_ENOENT; } int btWStat(char *pathBuf, vnode_id vnid, long mask, int32 mode, int32 uid, int32 gid, int64 size, int32 atime, int32 mtime) { struct _utimbuf ftimes; struct _stat st; char *path; path = btGetLocalFileName(pathBuf, vnid); if (path) { // if (mask & WSTAT_MODE) // chmod(path, mode); // if (mask & WSTAT_UID) // chown(path, uid, -1); // if (mask & WSTAT_GID) // chown(path, -1, gid); // if (mask & WSTAT_SIZE) // truncate(path, size); if (_stat(path, &st) == 0) if (mask & WSTAT_ATIME || mask & WSTAT_MTIME) { ftimes.actime = mask & WSTAT_ATIME ? atime : st.st_atime; ftimes.modtime = mask & WSTAT_MTIME ? mtime : st.st_mtime; _utime(path, &ftimes); } return B_OK; } return BEOS_ENOENT; } int btReadAttrib(char *pathBuf, vnode_id vnid, char *name, char *buffer) { bt_mime_mapping *map; char *path; path = btGetLocalFileName(pathBuf, vnid); if (path) { char *ext = strrchr(path, '.'); if (ext) { ext++; for (map = mimeMap; map; map = map->next) if (stricmp(ext, map->extension) == 0) { strcpy(buffer, map->mimeType); return (strlen(buffer)); } } } return 0; } int btAuthenticate(char *resource, char *user, char *password) { bt_user_rights *ur, *rootUr; bt_printer *printer; char *groups[MAX_GROUPS_PER_USER]; int i, rights, share; bool authenticated = false; // Determine if the resource is a file share or a printer. share = btGetShareId(resource); if (share >= 0) { if (fileShares[share].security == BT_AUTH_NONE) return B_OK; rootUr = fileShares[share].rights; } else { printer = btFindPrinter(resource); if (printer) if (printer->security == BT_AUTH_NONE) return B_OK; rootUr = printer->rights; } // Authenticate the user with name/password. authenticated = authenticateUser(user, password); if (!authenticated) return BEOS_EACCES; // Does the authenticated user have any rights on this file share? rights = 0; for (ur = rootUr; ur; ur = ur->next) if (!ur->isGroup && stricmp(ur->user, user) == 0) rights |= ur->rights; // Does the authenticated user belong to any groups that have any rights on this // file share? for (i = 0; i < MAX_GROUPS_PER_USER; i++) groups[i] = NULL; getUserGroups(user, groups); for (ur = rootUr; ur; ur = ur->next) if (ur->isGroup) for (i = 0; i < MAX_GROUPS_PER_USER; i++) if (groups[i] && stricmp(ur->user, groups[i]) == 0) { rights |= ur->rights; break; } // Free the memory occupied by the group list. for (i = 0; i < MAX_GROUPS_PER_USER; i++) if (groups[i]) free(groups[i]); // If no rights have been granted, deny access. if (!rights) return BEOS_EACCES; return B_OK; } //////////////////////////////////////////////////////////////////// void netbtPreMount(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client, security; client = session->socket; security = btPreMount(session, argv[0].data); btRPCCreateAck(&packet, xid, security); btRPCSendAck(session->socket, &packet); } void netbtMount(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; vnode_id vnid; int client, error; char *shareName = argv[0].data; char *user = argv[1].data; char *password = argv[2].data; client = session->socket; error = btMount(session, shareName, user, password, &vnid); if (error == B_OK) { // Record this session having logged in to a specific share. session->share = btGetShareId(shareName); session->logon = time(NULL); // Now send the client a response with the root vnid; btRPCCreateAck(&packet, xid, error); btRPCPutInt64(&packet, vnid); } else btRPCCreateAck(&packet, xid, error); btRPCSendAck(client, &packet); } void netbtFSInfo(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client, error; fs_info info; client = session->socket; error = btGetFSInfo(&info, fileShares[session->share].path); if (error == B_OK) { btRPCCreateAck(&packet, xid, error); btRPCPutInt32(&packet, info.block_size); btRPCPutInt32(&packet, info.total_blocks); btRPCPutInt32(&packet, info.free_blocks); } else btRPCCreateAck(&packet, xid, error); btRPCSendAck(client, &packet); } void netbtLookup(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; beos_stat st; int client, error; vnode_id dir_vnid = *((vnode_id *) argv[0].data); vnode_id file_vnid; client = session->socket; error = btLookup(session->pathBuffer, dir_vnid, argv[1].data, &file_vnid); if (error == B_OK) error = btStat(session->pathBuffer, file_vnid, &st); if (error == B_OK) { btRPCCreateAck(&packet, xid, B_OK); btRPCPutInt64(&packet, file_vnid); btRPCPutStat(&packet, &st); } else btRPCCreateAck(&packet, xid, error); btRPCSendAck(client, &packet); } void netbtReadDir(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { const int MAX_FOLDER_ENTRIES = 128; bt_outPacket packet; beos_stat st; int client, error; vnode_id dir_vnid = *((vnode_id *) argv[0].data); vnode_id file_vnid; long *dir; char filename[B_PATH_NAME_LENGTH]; int entries = 0; client = session->socket; dir = (long *)(*((int32 *) argv[1].data)); error = btReadDir(session->pathBuffer, dir_vnid, &dir, &file_vnid, filename, &st); if (error != B_OK) { btRPCCreateAck(&packet, xid, error); btRPCSendAck(client, &packet); return; } btRPCCreateAck(&packet, xid, B_OK); while (error == B_OK) { btRPCPutInt64(&packet, file_vnid); btRPCPutString(&packet, filename, strlen(filename)); btRPCPutInt32(&packet, (int32) dir); btRPCPutStat(&packet, &st); if (++entries >= MAX_FOLDER_ENTRIES) break; error = btReadDir(session->pathBuffer, dir_vnid, &dir, &file_vnid, filename, &st); btRPCPutInt32(&packet, error); } // If we exhausted the list of directory entries without filling // the buffer, add an error message that will prevent the client // from requesting further entries. if (entries < MAX_FOLDER_ENTRIES) btRPCPutInt32(&packet, BEOS_ENOENT); btRPCSendAck(client, &packet); } void netbtStat(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client, error; beos_stat info; vnode_id vnid = *((vnode_id *) argv[0].data); client = session->socket; error = btStat(session->pathBuffer, vnid, &info); if (error == B_OK) { btRPCCreateAck(&packet, xid, error); btRPCPutStat(&packet, &info); } else btRPCCreateAck(&packet, xid, error); btRPCSendAck(client, &packet); } void netbtRead(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client; vnode_id vnid = *((vnode_id *) argv[0].data); beos_off_t pos = *((beos_off_t *) argv[1].data); int32 len = *((int32 *) argv[2].data); int32 bytes = 0; client = session->socket; session->ioBuffer[len] = 0; bytes = btRead(session->pathBuffer, vnid, pos, len, session->ioBuffer); btRPCCreateAck(&packet, xid, B_OK); btRPCPutString(&packet, session->ioBuffer, bytes); btRPCSendAck(client, &packet); } void netbtWrite(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { int client; vnode_id vnid = *((vnode_id *) argv[0].data); beos_off_t pos = *((beos_off_t *) argv[1].data); int32 len = *((int32 *) argv[2].data); int32 totalLen = *((int32 *) argv[3].data); client = session->socket; // If the file share this user is connected to is read-only, the command // cannot be honored. if (session->rights & BT_RIGHTS_WRITE) btWrite(session, vnid, pos, len, totalLen, argv[4].data); } void netbtCreate(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; beos_stat st; int client, error; vnode_id dir_vnid = *((vnode_id *) argv[0].data); vnode_id file_vnid; int omode = *((int *) argv[2].data); int perms = *((int *) argv[3].data); client = session->socket; // If the file share this user is connected to is read-only, the command // cannot be honored. if (!(session->rights & BT_RIGHTS_WRITE)) { btRPCCreateAck(&packet, xid, BEOS_EACCES); btRPCSendAck(client, &packet); return; } error = btCreate(session->pathBuffer, dir_vnid, argv[1].data, omode, perms, &file_vnid); if (error == B_OK) error = btStat(session->pathBuffer, file_vnid, &st); if (error == B_OK) { btRPCCreateAck(&packet, xid, B_OK); btRPCPutInt64(&packet, file_vnid); btRPCPutStat(&packet, &st); } else btRPCCreateAck(&packet, xid, error); btRPCSendAck(client, &packet); } void netbtTruncate(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client, error; vnode_id vnid = *((vnode_id *) argv[0].data); client = session->socket; // If the file share this user is connected to is read-only, the command // cannot be honored. if (!(session->rights & BT_RIGHTS_WRITE)) { btRPCCreateAck(&packet, xid, BEOS_EACCES); btRPCSendAck(client, &packet); return; } error = btTruncate(session->pathBuffer, vnid, *((int64 *) argv[1].data)); btRPCCreateAck(&packet, xid, error); btRPCSendAck(client, &packet); } void netbtUnlink(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client, error; vnode_id vnid = *((vnode_id *) argv[0].data); client = session->socket; // If the file share this user is connected to is read-only, the command // cannot be honored. if (!(session->rights & BT_RIGHTS_WRITE)) { btRPCCreateAck(&packet, xid, BEOS_EACCES); btRPCSendAck(client, &packet); return; } error = btUnlink(session->pathBuffer, vnid, argv[1].data); btRPCCreateAck(&packet, xid, error); btRPCSendAck(client, &packet); } void netbtRename(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client, error; vnode_id old_vnid = *((vnode_id *) argv[0].data); vnode_id new_vnid = *((vnode_id *) argv[2].data); client = session->socket; // If the file share this user is connected to is read-only, the command // cannot be honored. if (!(session->rights & BT_RIGHTS_WRITE)) { btRPCCreateAck(&packet, xid, BEOS_EACCES); btRPCSendAck(client, &packet); return; } error = btRename(session->pathBuffer, old_vnid, argv[1].data, new_vnid, argv[3].data); btRPCCreateAck(&packet, xid, error); btRPCSendAck(client, &packet); } void netbtCreateDir(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client, error; vnode_id dir_vnid = *((vnode_id *) argv[0].data); vnode_id file_vnid; beos_stat st; client = session->socket; // If the file share this user is connected to is read-only, the command // cannot be honored. if (!(session->rights & BT_RIGHTS_WRITE)) { btRPCCreateAck(&packet, xid, BEOS_EACCES); btRPCSendAck(client, &packet); return; } error = btCreateDir(session->pathBuffer, dir_vnid, argv[1].data, *((int *) argv[2].data), &file_vnid, &st); if (error == B_OK) { btRPCCreateAck(&packet, xid, B_OK); btRPCPutInt64(&packet, file_vnid); btRPCPutStat(&packet, &st); } else btRPCCreateAck(&packet, xid, error); btRPCSendAck(client, &packet); } void netbtDeleteDir(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client, error; vnode_id vnid = *((vnode_id *) argv[0].data); client = session->socket; // If the file share this user is connected to is read-only, the command // cannot be honored. if (!(session->rights & BT_RIGHTS_WRITE)) { btRPCCreateAck(&packet, xid, BEOS_EACCES); btRPCSendAck(client, &packet); return; } error = btDeleteDir(session->pathBuffer, vnid, argv[1].data); btRPCCreateAck(&packet, xid, error); btRPCSendAck(client, &packet); } void netbtReadLink(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client; client = session->socket; btRPCCreateAck(&packet, xid, ENOTSUP); btRPCSendAck(client, &packet); } void netbtSymLink(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client; client = session->socket; btRPCCreateAck(&packet, xid, ENOTSUP); btRPCSendAck(client, &packet); } void netbtWStat(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client, error; vnode_id vnid = *((vnode_id *) argv[0].data); int32 mask = *((int32 *) argv[1].data); int32 mode = *((int32 *) argv[2].data); int32 uid = *((int32 *) argv[3].data); int32 gid = *((int32 *) argv[4].data); int64 size = (int64) *((int32 *) argv[5].data); int32 atime = *((int32 *) argv[6].data); int32 mtime = *((int32 *) argv[7].data); client = session->socket; // If the file share this user is connected to is read-only, the command // cannot be honored. if (!(session->rights & BT_RIGHTS_WRITE)) { btRPCCreateAck(&packet, xid, BEOS_EACCES); btRPCSendAck(client, &packet); return; } error = btWStat(session->pathBuffer, vnid, mask, mode, uid, gid, size, atime, mtime); btRPCCreateAck(&packet, xid, error); btRPCSendAck(client, &packet); } void netbtReadAttrib(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client, bytesRead; client = session->socket; if (stricmp(argv[1].data, "BEOS:TYPE") == 0) { vnode_id vnid = *((vnode_id *) argv[0].data); bytesRead = btReadAttrib(session->pathBuffer, vnid, argv[1].data, session->attrBuffer); if (bytesRead > 0) { btRPCCreateAck(&packet, xid, B_OK); btRPCPutInt32(&packet, (int32) bytesRead + 1); btRPCPutString(&packet, session->attrBuffer, bytesRead + 1); btRPCSendAck(client, &packet); return; } } btRPCCreateAck(&packet, xid, ENOTSUP); btRPCSendAck(client, &packet); } void netbtWriteAttrib(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client; client = session->socket; btRPCCreateAck(&packet, xid, ENOTSUP); btRPCSendAck(client, &packet); } void netbtReadAttribDir(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client; client = session->socket; btRPCCreateAck(&packet, xid, ENOTSUP); btRPCSendAck(client, &packet); } void netbtRemoveAttrib(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client; client = session->socket; btRPCCreateAck(&packet, xid, ENOTSUP); btRPCSendAck(client, &packet); } void netbtStatAttrib(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client, bytesRead; client = session->socket; if (strcmp(argv[1].data, "BEOS:TYPE") == 0) { vnode_id vnid = *((vnode_id *) argv[0].data); bytesRead = btReadAttrib(session->pathBuffer, vnid, argv[1].data, session->attrBuffer); btRPCCreateAck(&packet, xid, B_OK); btRPCPutInt32(&packet, B_STRING_TYPE); btRPCPutInt64(&packet, bytesRead + 1); btRPCSendAck(client, &packet); return; } btRPCCreateAck(&packet, xid, ENOTSUP); btRPCSendAck(client, &packet); } void netbtReadIndexDir(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client; client = session->socket; btRPCCreateAck(&packet, xid, ENOTSUP); btRPCSendAck(client, &packet); } void netbtCreateIndex(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client; client = session->socket; btRPCCreateAck(&packet, xid, ENOTSUP); btRPCSendAck(client, &packet); } void netbtRemoveIndex(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client; client = session->socket; btRPCCreateAck(&packet, xid, ENOTSUP); btRPCSendAck(client, &packet); } void netbtStatIndex(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client; client = session->socket; btRPCCreateAck(&packet, xid, ENOTSUP); btRPCSendAck(client, &packet); } void netbtReadQuery(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client; client = session->socket; btRPCCreateAck(&packet, xid, ENOTSUP); btRPCSendAck(client, &packet); } void netbtCommit(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client, error; vnode_id vnid = *((vnode_id *) argv[0].data); client = session->socket; // If the file share this user is connected to is read-only, the command // cannot be honored. if (!(session->rights & BT_RIGHTS_WRITE)) { btRPCCreateAck(&packet, xid, BEOS_EACCES); btRPCSendAck(client, &packet); return; } error = btCommit(session, vnid); btRPCCreateAck(&packet, xid, error); btRPCSendAck(client, &packet); } void netbtPrintJobNew(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client, error; char jobId[MAX_NAME_LENGTH]; char *printerName = argv[0].data; char *user = argv[1].data; char *password = argv[2].data; char *jobName = argv[3].data; client = session->socket; error = btPrintJobNew(printerName, user, password, session->client_s_addr, jobName, jobId); btRPCCreateAck(&packet, xid, error); if (error == B_OK) btRPCPutString(&packet, jobId, strlen(jobId)); btRPCSendAck(client, &packet); } void netbtPrintJobData(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client, error; char *printerName = argv[0].data; char *jobId = argv[1].data; char *jobData = argv[2].data; int32 dataLen = *((int32 *) argv[3].data); client = session->socket; error = btPrintJobData(printerName, jobId, jobData, dataLen); btRPCCreateAck(&packet, xid, error); btRPCSendAck(client, &packet); } void netbtPrintJobCommit(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client, error; char *printerName = argv[0].data; char *jobId = argv[1].data; client = session->socket; error = btPrintJobCommit(printerName, jobId); btRPCCreateAck(&packet, xid, error); btRPCSendAck(client, &packet); } void netbtAuthenticate(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client, error; char *resource = argv[0].data; char *user = argv[1].data; char *password = argv[2].data; client = session->socket; error = btAuthenticate(resource, user, password); btRPCCreateAck(&packet, xid, error); btRPCSendAck(client, &packet); } void netbtQuit(bt_session_t *session, unsigned int xid, int argc, bt_arg_t argv[]) { bt_outPacket packet; int client; client = session->socket; btRPCCreateAck(&packet, xid, B_OK); btRPCSendAck(client, &packet); } /* bool IsValidUser(char *user, char *domain, char *password) { HANDLE hUser, hTok; OSVERSIONINFO osInfo; bool authenticated; authenticated = false; osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (GetVersionEx(&osInfo)) if (osInfo.dwPlatformId != VER_PLATFORM_WIN32_NT) return true; hTok = 0; if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hTok)) { TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (LookupPrivilegeValue(0, SE_TCB_NAME, &tp.Privileges[0].Luid)) if (AdjustTokenPrivileges(hTok, FALSE, &tp, 0, NULL, NULL)) if (LogonUser(user, domain, password, LOGON32_LOGON_BATCH, LOGON32_PROVIDER_DEFAULT, &hUser)) { CloseHandle(hUser); authenticated = true; } CloseHandle(hTok); } return authenticated; } */ void loadFolder(const char *path) { struct _finddata_t fileInfo; struct _stat st; char *search; long dir, result; uint32 dir_vnid; search = (char *) malloc(MAX_PATH); if (search == NULL) return; dir_vnid = btGetWinInode(path); sprintf(search, "%s\\*.*", path); dir = result = _findfirst(search, &fileInfo); while (result != -1) { btMakePath(search, (char *) path, fileInfo.name); btAddHandle(dir_vnid, btGetWinInode(search), fileInfo.name); _stat(search, &st); if (st.st_mode & _S_IFDIR) if (strcmp(fileInfo.name, ".") && strcmp(fileInfo.name, "..")) loadFolder(search); result = _findnext(dir, &fileInfo); } _findclose(dir); free(search); } //////// void KillNode(ubi_trNodePtr node) { bt_node *bn = (bt_node *) node; free(bn->name); free(node); } int CompareVnidNodes(ubi_trItemPtr item, ubi_trNodePtr node) { vnode_id vnid1 = *((vnode_id *) item); vnode_id vnid2 = ((bt_node *) node)->vnid; if (vnid1 < vnid2) return -1; else if (vnid1 > vnid2) return 1; else return 0; } int CompareNameNodes(ubi_trItemPtr item, ubi_trNodePtr node) { bt_node *node1 = (bt_node *) item; bt_node *node2 = (bt_node *) node; if (node1->parent < node2->parent) return -1; else if (node1->parent > node2->parent) return 1; else return strcmp(node1->name, node2->name); }