/* U2FDevice - A program to allow Raspberry Pi Zeros to act as U2F tokens Copyright (C) 2018 Michael Kuc This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "Streams.hpp" #include "Architecture.hpp" #include "IO.hpp" #include #include #include #include #include #include #include #include #include using std::cerr; using std::clog; using std::endl; using std::runtime_error; using std::shared_ptr; using std::string; shared_ptr initialiseHostDescriptor(); #ifdef DEBUG_STREAMS FILE* initHTML(FILE* fPtr, const string& title); void closeHTML(FILE* fPtr); #endif shared_ptr getHostDescriptor() { static shared_ptr descriptor{ initialiseHostDescriptor() }; return descriptor; } #ifdef DEBUG_STREAMS shared_ptr getComHostStream() { static shared_ptr stream{ fopen((cacheDirectory + "comhost.txt").c_str(), "wb"), [](FILE* f) { clog << "Closing comhost stream" << endl; fclose(f); } }; if (!stream) clog << "Stream is unavailable" << endl; return stream; } shared_ptr getHostPacketStream() { static shared_ptr stream{ initHTML(fopen((cacheDirectory + "hostpackets.html").c_str(), "wb"), "Host Packets"), [](FILE* f) { clog << "Closing hostPackets stream" << endl; closeHTML(f); } }; if (!stream) clog << "Stream is unavailable" << endl; return stream; } shared_ptr getHostAPDUStream() { static shared_ptr stream{ initHTML(fopen((cacheDirectory + "hostAPDU.html").c_str(), "wb"), "Host APDU"), [](FILE* f) { clog << "Closing host APDU stream" << endl; closeHTML(f); } }; if (!stream) clog << "Stream is unavailable" << endl; return stream; } shared_ptr getComDevStream() { static shared_ptr stream{ fopen((cacheDirectory + "comdev.txt").c_str(), "wb"), [](FILE* f) { clog << "Closing comdev stream" << endl; fclose(f); } }; if (!stream) clog << "Stream is unavailable" << endl; return stream; } shared_ptr getDevPacketStream() { static shared_ptr stream{ initHTML(fopen((cacheDirectory + "devpackets.html").c_str(), "wb"), "Dev Packets"), [](FILE* f) { clog << "Closing devPackets stream" << endl; closeHTML(f); } }; if (!stream) clog << "Stream is unavailable" << endl; return stream; } shared_ptr getDevAPDUStream() { static shared_ptr stream{ initHTML(fopen((cacheDirectory + "devAPDU.html").c_str(), "wb"), "Dev APDU"), [](FILE* f) { clog << "Closing dev APDU stream" << endl; closeHTML(f); } }; if (!stream) clog << "Stream is unavailable" << endl; return stream; } FILE* initHTML(FILE* fPtr, const string& title) { fprintf(fPtr, "\n" "\t\n" "\t\t%s\n" "\t\t\n" "\t\n" "\n" "\t", title.c_str()); return fPtr; } void closeHTML(FILE* fPtr) { fprintf(fPtr, "\t\n" ""); fclose(fPtr); } #endif shared_ptr initialiseHostDescriptor() { int descriptor; #ifdef HID_SOCKET if (access(clientSocket.c_str(), F_OK)) { remove(clientSocket.c_str()); } descriptor = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); if (descriptor == -1) throw runtime_error{ "Unable to open client socket" }; sockaddr_un serverSockAddr{}, clientSockAddr{}; clientSockAddr.sun_family = AF_UNIX; strncpy(clientSockAddr.sun_path, clientSocket.c_str(), sizeof(clientSockAddr.sun_path) - 1); // Attempt to remove existing unlink(clientSocket.c_str()); int result = ::bind(descriptor, (sockaddr*)&clientSockAddr, sizeof(clientSockAddr)); if (result == -1) throw runtime_error{ "Unable to bind to client socket: " + clientSocket }; serverSockAddr.sun_family = AF_UNIX; strncpy(serverSockAddr.sun_path, HID_DEV, sizeof(serverSockAddr.sun_path) - 1); for (size_t connectCount = 0; connectCount < 100; connectCount++) { result = connect(descriptor, (sockaddr*)&serverSockAddr, sizeof(serverSockAddr)); if (result != -1) break; usleep(100'000); } if (result == -1) throw runtime_error{ "Unable to connect to server socket: " + string{ HID_DEV } }; __android_log_print(ANDROID_LOG_DEBUG, "U2FDevice", "Connected to server"); return shared_ptr{ new int{ descriptor }, [](const int* fd) { close(*fd); remove(clientSocket.c_str()); delete fd; } }; #else descriptor = open(HID_DEV, O_RDWR | O_NONBLOCK | O_APPEND); if (descriptor == -1) throw runtime_error{ "Descriptor is unavailable" }; return shared_ptr{ new int{ descriptor }, [](const int* fd) { close(*fd); delete fd; } }; #endif }